From 5e506bfab0b6d507b323519b3830bb0485d43560 Mon Sep 17 00:00:00 2001 From: matzakos Date: Fri, 24 Sep 2021 16:36:02 +0200 Subject: [PATCH 001/267] Trigger F1 UE context setup request from CU after reception of NR UE capabilities -Include UE_Capability_RAT_container_list in UE context setup request so that it gets processed at the DU -Next steps: DU should store and process the UE capabilities and generate updates in master cell group config to be included in UE context setup response. Then upon reception of UE context setup response, the first RRC Reconfiguration can be triggered at the CU with the updates on master cell group config. --- openair2/COMMON/f1ap_messages_types.h | 11 ++- openair2/F1AP/f1ap_cu_ue_context_management.c | 40 +++++++---- openair2/F1AP/f1ap_du_ue_context_management.c | 5 +- openair2/RRC/NR/rrc_gNB.c | 71 +++++++++++++++++-- 4 files changed, 103 insertions(+), 24 deletions(-) diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index 1aba05e82d..7116dd09c1 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -343,6 +343,15 @@ typedef struct f1ap_rb_failed_to_be_setup_s { long rb_id; } f1ap_rb_failed_to_be_setup_t; +typedef struct cu_to_du_rrc_information_s { + uint8_t * cG_ConfigInfo; + uint8_t cG_ConfigInfo_length; + uint8_t * uE_CapabilityRAT_ContainerList; + uint8_t uE_CapabilityRAT_ContainerList_length; + uint8_t * measConfig; + uint8_t measConfig_length; +}cu_to_du_rrc_information_t; + typedef struct f1ap_ue_context_setup_s { uint32_t gNB_CU_ue_id; // BK: need to replace by use from rnti uint32_t gNB_DU_ue_id; @@ -355,7 +364,7 @@ typedef struct f1ap_ue_context_setup_s { uint8_t servCellIndex; uint8_t *cellULConfigured; uint32_t servCellId; - uint8_t *cu_to_du_rrc_information; + cu_to_du_rrc_information_t *cu_to_du_rrc_information; uint8_t cu_to_du_rrc_information_length; uint8_t *du_to_cu_rrc_information; uint8_t du_to_cu_rrc_information_length; diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index 5030e84e35..6910c9d71b 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -132,21 +132,31 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(instance_t instance, ie6->id = F1AP_ProtocolIE_ID_id_CUtoDURRCInformation; ie6->criticality = F1AP_Criticality_reject; ie6->value.present = F1AP_UEContextSetupRequestIEs__value_PR_CUtoDURRCInformation; - /* optional */ - /* 6.1 cG_ConfigInfo */ - if (0) { - const char cG_ConfigInfoStr[]="asdsa1d32sa1d31asd31as"; - asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.cG_ConfigInfo, F1AP_CG_ConfigInfo_t, cG_ConfigInfo); - OCTET_STRING_fromBuf(cG_ConfigInfo, cG_ConfigInfoStr, strlen( cG_ConfigInfoStr )) ; + + if (f1ap_ue_context_setup_req->cu_to_du_rrc_information!=NULL) { + /* optional */ + /* 6.1 cG_ConfigInfo */ + if(f1ap_ue_context_setup_req->cu_to_du_rrc_information->cG_ConfigInfo!=NULL){ + const char cG_ConfigInfoStr[]="asdsa1d32sa1d31asd31as"; + asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.cG_ConfigInfo, F1AP_CG_ConfigInfo_t, cG_ConfigInfo); + OCTET_STRING_fromBuf(cG_ConfigInfo, cG_ConfigInfoStr, strlen(cG_ConfigInfoStr)) ; + } /* optional */ /* 6.2 uE_CapabilityRAT_ContainerList */ - asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList, F1AP_UE_CapabilityRAT_ContainerList_t, uE_CapabilityRAT_ContainerList ); - OCTET_STRING_fromBuf(uE_CapabilityRAT_ContainerList, cG_ConfigInfoStr, strlen( cG_ConfigInfoStr )) ; + if(f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList!=NULL){ + asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList, F1AP_UE_CapabilityRAT_ContainerList_t, uE_CapabilityRAT_ContainerList ); + OCTET_STRING_fromBuf(uE_CapabilityRAT_ContainerList, (const char *)f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, + f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length) ; + } /* optional */ /* 6.3 measConfig */ - asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.measConfig, F1AP_MeasConfig_t, measConfig); - OCTET_STRING_fromBuf(measConfig, cG_ConfigInfoStr, strlen( cG_ConfigInfoStr )) ; + if(f1ap_ue_context_setup_req->cu_to_du_rrc_information->measConfig!=NULL){ + const char measConfigStr[]="asdsa1d32sa1d31asd31as"; + asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.measConfig, F1AP_MeasConfig_t, measConfig); + OCTET_STRING_fromBuf(measConfig, measConfigStr, strlen(measConfigStr)) ; + } } + /* mandatory */ /* c7. Candidate_SpCell_List */ @@ -238,6 +248,7 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(instance_t instance, /* mandatory */ /* c11. SRBs_ToBeSetup_List */ + if(f1ap_ue_context_setup_req->srbs_to_be_setup_length > 0){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie11); ie11->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetup_List; ie11->criticality = F1AP_Criticality_reject; // ? @@ -260,9 +271,11 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(instance_t instance, F1AP_DuplicationIndication_t, F1AP_DuplicationIndication_true); // enum //} } + } /* mandatory */ /* c12. DRBs_ToBeSetup_List */ + if(f1ap_ue_context_setup_req->drbs_to_be_setup_length){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie12); ie12->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_List; ie12->criticality = F1AP_Criticality_reject; @@ -511,16 +524,14 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(instance_t instance, /* 12.1.3 uLUPTNLInformation_ToBeSetup_List */ for (int j = 0; j < f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl_length; j++) { - /* Here the callback function used as input is not the right one. Need to create a new one probably for F1-U, not sure - * if the kind of input parameters to the callback function are convenient though for gtp-u over F1-U.*/ - //Use a dummy teid for the outgoing GTP-U tunnel (DU) which will be updated once we get the UE context setup response from the DU + /*Use a dummy teid for the outgoing GTP-U tunnel (DU) which will be updated once we get the UE context setup response from the DU*/ transport_layer_addr_t addr; int sz=sizeof(f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_dl_tnl[0].tl_address); memcpy(addr.buffer,&f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_dl_tnl[0].tl_address, sz); addr.length = sz*8; f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl[j].teid= - newGtpuCreateTunnel(getCxt(CUtype, instance)->gtpInst, + newGtpuCreateTunnel(getCxt(CUtype, instance)->gtpInst, f1ap_ue_context_setup_req->rnti, f1ap_ue_context_setup_req->drbs_to_be_setup[i].drb_id, f1ap_ue_context_setup_req->drbs_to_be_setup[i].drb_id, @@ -567,6 +578,7 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(instance_t instance, *tmp = F1AP_DuplicationActivation_active; // enum } } + } /* OPTIONAL */ /* InactivityMonitoringRequest */ diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index 70556e78c7..818c18c173 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -134,7 +134,7 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, /* DRB */ F1AP_UEContextSetupRequestIEs_t *ieDrb; F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupRequestIEs_t, ieDrb, container, - F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_List, true); + F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_List, false); if(ieDrb!=NULL) { f1ap_ue_context_setup_req->drbs_to_be_setup_length = ieDrb->value.choice.DRBs_ToBeSetup_List.list.count; @@ -187,7 +187,7 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, /* SRB */ F1AP_UEContextSetupRequestIEs_t *ieSrb; F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupRequestIEs_t, ieSrb, container, - F1AP_ProtocolIE_ID_id_SRBs_ToBeSetup_List, true); + F1AP_ProtocolIE_ID_id_SRBs_ToBeSetup_List, false); if(ieSrb != NULL) { f1ap_ue_context_setup_req->srbs_to_be_setup_length = ieSrb->value.choice.SRBs_ToBeSetup_List.list.count; @@ -580,6 +580,7 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, f1ap_ue_context_setup getCxt(false, instance)->default_sctp_stream_id); return 0; } + int DU_send_UE_CONTEXT_SETUP_FAILURE(instance_t instance) { AssertFatal(1==0,"Not implemented yet\n"); } diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index e240c9d269..bd6ce4c7de 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1347,7 +1347,6 @@ rrc_gNB_process_RRCReconfigurationComplete( NULL, get_softmodem_params()->sa ? ue_context_pP->ue_context.masterCellGroup->rlc_BearerToAddModList : NULL); /* Refresh SRBs/DRBs */ - if (!NODE_IS_CU(RC.nrrrc[ctxt_pP->module_id]->node_type)) { rrc_mac_config_req_gNB(rrc->module_id, rrc->carrier.ssb_SubcarrierOffset, @@ -1367,7 +1366,7 @@ rrc_gNB_process_RRCReconfigurationComplete( NULL, get_softmodem_params()->sa ? ue_context_pP->ue_context.masterCellGroup->rlc_BearerToAddModList : NULL); } - else if(SRB_configList!=NULL || DRB_configList!=NULL){ + /*else if(SRB_configList!=NULL || DRB_configList!=NULL){ MessageDef *message_p; message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, F1AP_UE_CONTEXT_SETUP_REQ); f1ap_ue_context_setup_t *req=&F1AP_UE_CONTEXT_SETUP_REQ (message_p); @@ -1409,7 +1408,7 @@ rrc_gNB_process_RRCReconfigurationComplete( LOG_I(RRC, "Send F1AP_UE_CONTEXT_SETUP_REQ with ITTI\n"); } itti_send_msg_to_task (TASK_CU_F1, ctxt_pP->module_id, message_p); - } + }*/ #endif /* Set the SRB active in UE context */ @@ -2690,11 +2689,69 @@ rrc_gNB_decode_dcch( ul_dcch_msg); } - if (ue_context_p->ue_context.established_pdu_sessions_flag == 1) { - rrc_gNB_generate_dedicatedRRCReconfiguration(ctxt_pP, ue_context_p); - } else { - rrc_gNB_generate_defaultRRCReconfiguration(ctxt_pP, ue_context_p); + if(!NODE_IS_CU(RC.nrrrc[ctxt_pP->module_id]->node_type)){ + if (ue_context_p->ue_context.established_pdu_sessions_flag == 1) { + rrc_gNB_generate_dedicatedRRCReconfiguration(ctxt_pP, ue_context_p); + } else { + rrc_gNB_generate_defaultRRCReconfiguration(ctxt_pP, ue_context_p); + } } + else{ + /*Generate a UE context setup request message towards the DU to provide the UE + *capability info and get the updates on master cell group config from the DU*/ + MessageDef *message_p; + message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, F1AP_UE_CONTEXT_SETUP_REQ); + f1ap_ue_context_setup_t *req=&F1AP_UE_CONTEXT_SETUP_REQ (message_p); + //UE_IDs will be extracted from F1AP layer + req->gNB_CU_ue_id = 0; + req->gNB_DU_ue_id = 0; + req->rnti = ue_context_p->ue_context.rnti; + req->mcc = RC.nrrrc[ctxt_pP->module_id]->configuration.mcc[0]; + req->mnc = RC.nrrrc[ctxt_pP->module_id]->configuration.mnc[0]; + req->mnc_digit_length = RC.nrrrc[ctxt_pP->module_id]->configuration.mnc_digit_length[0]; + req->nr_cellid = RC.nrrrc[ctxt_pP->module_id]->nr_cellid; + + if (ue_context_p->ue_context.established_pdu_sessions_flag == 1) { + /*Instruction towards the DU for SRB2 configuration*/ + req->srbs_to_be_setup = malloc(1*sizeof(f1ap_srb_to_be_setup_t)); + req->srbs_to_be_setup_length = 1; + f1ap_srb_to_be_setup_t *SRBs=req->srbs_to_be_setup; + SRBs[0].srb_id = 2; + SRBs[0].lcid = 2; + + /*Instruction towards the DU for DRB configuration and tunnel creation*/ + gtpv1u_gnb_create_tunnel_req_t create_tunnel_req; + memset(&create_tunnel_req, 0, sizeof(gtpv1u_gnb_create_tunnel_req_t)); + req->drbs_to_be_setup = malloc(1*sizeof(f1ap_drb_to_be_setup_t)); + req->drbs_to_be_setup_length = 1; + f1ap_drb_to_be_setup_t *DRBs=req->drbs_to_be_setup; + LOG_I(RRC, "Length of DRB list:%d \n", req->drbs_to_be_setup_length); + DRBs[0].drb_id = 1; + DRBs[0].rlc_mode = RLC_MODE_AM; + DRBs[0].up_ul_tnl[0].tl_address = inet_addr(RC.nrrrc[ctxt_pP->module_id]->eth_params_s.my_addr); + DRBs[0].up_ul_tnl[0].port=RC.nrrrc[ctxt_pP->module_id]->eth_params_s.my_portd; + DRBs[0].up_ul_tnl_length = 1; + DRBs[0].up_dl_tnl[0].tl_address = inet_addr(RC.nrrrc[ctxt_pP->module_id]->eth_params_s.remote_addr); + DRBs[0].up_dl_tnl[0].port=RC.nrrrc[ctxt_pP->module_id]->eth_params_s.remote_portd; + DRBs[0].up_dl_tnl_length = 1; + } + if( ul_dcch_msg->message.choice.c1->choice.ueCapabilityInformation->criticalExtensions.present == + NR_UECapabilityInformation__criticalExtensions_PR_ueCapabilityInformation ) { + struct NR_UE_CapabilityRAT_ContainerList *ue_CapabilityRAT_ContainerList = + ul_dcch_msg->message.choice.c1->choice.ueCapabilityInformation->criticalExtensions.choice.ueCapabilityInformation->ue_CapabilityRAT_ContainerList; + + req->cu_to_du_rrc_information = calloc(1,sizeof(cu_to_du_rrc_information_t)); + req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList = calloc(1,1024); + asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_UE_CapabilityRAT_ContainerList, + NULL, + (void *)ue_CapabilityRAT_ContainerList, + req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, + 1024); + req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length = (enc_rval.encoded+7)>>3; + } + itti_send_msg_to_task (TASK_CU_F1, ctxt_pP->module_id, message_p); + } + break; From 55476b175f94aa23091798b5edcf6caf063595b4 Mon Sep 17 00:00:00 2001 From: matzakos Date: Mon, 27 Sep 2021 18:02:13 +0200 Subject: [PATCH 002/267] Handle UE capabilities info at the DU received through UE context setup request -Trigger UE context setup response at the DU and RRC Reconfiguration at the CU upon reception of UE context setup response. -Pending: The DU should generate some updates on the master cell groupconfig based also on the received UE capabilities and add them in the UE context setup response message so that they can be included in the RRC Reconfiguration message sent from the CU. For the moment the corresponding function is empty. -Next steps: trigger UE context modification procedures --- openair2/F1AP/f1ap_cu_ue_context_management.c | 4 +- openair2/F1AP/f1ap_du_ue_context_management.c | 16 ++ openair2/RRC/NR/MESSAGES/asn1_msg.c | 169 ++++++++++-------- openair2/RRC/NR/MESSAGES/asn1_msg.h | 4 +- openair2/RRC/NR/nr_rrc_proto.h | 3 +- openair2/RRC/NR/rrc_gNB.c | 133 +++++++++++++- openair2/RRC/NR/rrc_gNB_NGAP.c | 2 +- 7 files changed, 238 insertions(+), 93 deletions(-) diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index 6910c9d71b..740d3a75b4 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -696,7 +696,7 @@ int CU_handle_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, // DRBs_Setup_List F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_DRBs_Setup_List, true); + F1AP_ProtocolIE_ID_id_DRBs_Setup_List, false); if(ie!=NULL){ f1ap_ue_context_setup_resp->drbs_to_be_setup_length = ie->value.choice.DRBs_Setup_List.list.count; f1ap_ue_context_setup_resp->drbs_to_be_setup = calloc(f1ap_ue_context_setup_resp->drbs_to_be_setup_length, @@ -762,7 +762,7 @@ int CU_handle_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, // SRBs_Setup_List F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_SRBs_Setup_List, true); + F1AP_ProtocolIE_ID_id_SRBs_Setup_List, false); if(ie!=NULL){ f1ap_ue_context_setup_resp->srbs_to_be_setup_length = ie->value.choice.SRBs_Setup_List.list.count; f1ap_ue_context_setup_resp->srbs_to_be_setup = calloc(f1ap_ue_context_setup_resp->srbs_to_be_setup_length, diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index 818c18c173..e2f804c35b 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -131,6 +131,18 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, f1ap_ue_context_setup_req->cellULConfigured = NULL; } + F1AP_UEContextSetupRequestIEs_t *ieCuRrcInfo; + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupRequestIEs_t, ieCuRrcInfo, container, + F1AP_ProtocolIE_ID_id_CUtoDURRCInformation, false); + if(ieCuRrcInfo!=NULL){ + f1ap_ue_context_setup_req->cu_to_du_rrc_information = (cu_to_du_rrc_information_t *)calloc(1,sizeof(cu_to_du_rrc_information_t)); + if(ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList!=NULL){ + f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList = (uint8_t *)calloc(1,ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList->size); + memcpy(f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList->buf, ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList->size); + f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length = ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList->size; + } + } + /* DRB */ F1AP_UEContextSetupRequestIEs_t *ieDrb; F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupRequestIEs_t, ieDrb, container, @@ -334,6 +346,7 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, f1ap_ue_context_setup /* mandatory */ /* c7. DRBs_Setup_List */ + if(req->drbs_to_be_setup_length > 0){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie7); ie7->id = F1AP_ProtocolIE_ID_id_DRBs_Setup_List; ie7->criticality = F1AP_Criticality_ignore; @@ -374,6 +387,7 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, f1ap_ue_context_setup INT32_TO_OCTET_STRING(req->drbs_to_be_setup[i].up_dl_tnl[j].teid, &gTPTunnel->gTP_TEID); } // for j } // for i + } /* mandatory */ /* c8. SRBs_FailedToBeSetup_List */ @@ -523,6 +537,7 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, f1ap_ue_context_setup /* mandatory */ /* c11. SRBs_Setup_List */ + if(req->srbs_to_be_setup_length > 0){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie11); ie11->id = F1AP_ProtocolIE_ID_id_SRBs_Setup_List; ie11->criticality = F1AP_Criticality_ignore; @@ -540,6 +555,7 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, f1ap_ue_context_setup /* sRBID */ srbs_setup_item->sRBID = req->srbs_to_be_setup[i].srb_id; } + } /* Optional */ /* c12. InactivityMonitoringResponse */ diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index f1930f65a4..143eac680d 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1096,7 +1096,7 @@ void fill_initial_SpCellConfig(rnti_t rnti, SpCellConfig->spCellConfigDedicated->tag_Id=0; } -void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGroupConfig_t *ue_context_mastercellGroup) { +void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGroupConfig_t *ue_context_mastercellGroup, uint8_t SRB_config_present, uint8_t DRB_config_present) { cellGroupConfig->cellGroupId = 0; cellGroupConfig->rlc_BearerToReleaseList = NULL; @@ -1104,86 +1104,97 @@ void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGr // RLC Bearer Config // TS38.331 9.2.1 Default SRB configurations - NR_RLC_BearerConfig_t *rlc_BearerConfig = NULL; - NR_RLC_Config_t *rlc_Config = NULL; - NR_LogicalChannelConfig_t *logicalChannelConfig = NULL; - long *logicalChannelGroup = NULL; - rlc_BearerConfig = calloc(1, sizeof(NR_RLC_BearerConfig_t)); - rlc_BearerConfig->logicalChannelIdentity = 2; - rlc_BearerConfig->servedRadioBearer = calloc(1, sizeof(*rlc_BearerConfig->servedRadioBearer)); - rlc_BearerConfig->servedRadioBearer->present = NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity; - rlc_BearerConfig->servedRadioBearer->choice.srb_Identity = 2; - rlc_BearerConfig->reestablishRLC = NULL; - rlc_Config = calloc(1, sizeof(NR_RLC_Config_t)); - rlc_Config->present = NR_RLC_Config_PR_am; - rlc_Config->choice.am = calloc(1, sizeof(*rlc_Config->choice.am)); - rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); - *(rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size12; - rlc_Config->choice.am->dl_AM_RLC.t_Reassembly = NR_T_Reassembly_ms35; - rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms0; - rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); - *(rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size12; - rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms45; - rlc_Config->choice.am->ul_AM_RLC.pollPDU = NR_PollPDU_infinity; - rlc_Config->choice.am->ul_AM_RLC.pollByte = NR_PollByte_infinity; - rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t8; - rlc_BearerConfig->rlc_Config = rlc_Config; - logicalChannelConfig = calloc(1, sizeof(NR_LogicalChannelConfig_t)); - logicalChannelConfig->ul_SpecificParameters = calloc(1, sizeof(*logicalChannelConfig->ul_SpecificParameters)); - logicalChannelConfig->ul_SpecificParameters->priority = 3; - logicalChannelConfig->ul_SpecificParameters->prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity; - logicalChannelConfig->ul_SpecificParameters->bucketSizeDuration = NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms5; - logicalChannelGroup = CALLOC(1, sizeof(long)); - *logicalChannelGroup = 0; - logicalChannelConfig->ul_SpecificParameters->logicalChannelGroup = logicalChannelGroup; - logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = CALLOC(1, sizeof(*logicalChannelConfig->ul_SpecificParameters->schedulingRequestID)); - *logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = 0; - logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_Mask = 0; - logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = 0; - rlc_BearerConfig->mac_LogicalChannelConfig = logicalChannelConfig; - ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig); - ASN_SEQUENCE_ADD(&ue_context_mastercellGroup->rlc_BearerToAddModList->list, rlc_BearerConfig); + if(SRB_config_present){ + NR_RLC_BearerConfig_t *rlc_BearerConfig = NULL; + NR_RLC_Config_t *rlc_Config = NULL; + NR_LogicalChannelConfig_t *logicalChannelConfig = NULL; + long *logicalChannelGroup = NULL; + rlc_BearerConfig = calloc(1, sizeof(NR_RLC_BearerConfig_t)); + rlc_BearerConfig->logicalChannelIdentity = 2; + rlc_BearerConfig->servedRadioBearer = calloc(1, sizeof(*rlc_BearerConfig->servedRadioBearer)); + rlc_BearerConfig->servedRadioBearer->present = NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity; + rlc_BearerConfig->servedRadioBearer->choice.srb_Identity = 2; + rlc_BearerConfig->reestablishRLC = NULL; + rlc_Config = calloc(1, sizeof(NR_RLC_Config_t)); + rlc_Config->present = NR_RLC_Config_PR_am; + rlc_Config->choice.am = calloc(1, sizeof(*rlc_Config->choice.am)); + rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); + *(rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size12; + rlc_Config->choice.am->dl_AM_RLC.t_Reassembly = NR_T_Reassembly_ms35; + rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms0; + rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); + *(rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size12; + rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms45; + rlc_Config->choice.am->ul_AM_RLC.pollPDU = NR_PollPDU_infinity; + rlc_Config->choice.am->ul_AM_RLC.pollByte = NR_PollByte_infinity; + rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t8; + rlc_BearerConfig->rlc_Config = rlc_Config; + logicalChannelConfig = calloc(1, sizeof(NR_LogicalChannelConfig_t)); + logicalChannelConfig->ul_SpecificParameters = calloc(1, sizeof(*logicalChannelConfig->ul_SpecificParameters)); + logicalChannelConfig->ul_SpecificParameters->priority = 3; + logicalChannelConfig->ul_SpecificParameters->prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity; + logicalChannelConfig->ul_SpecificParameters->bucketSizeDuration = NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms5; + logicalChannelGroup = CALLOC(1, sizeof(long)); + *logicalChannelGroup = 0; + logicalChannelConfig->ul_SpecificParameters->logicalChannelGroup = logicalChannelGroup; + logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = CALLOC(1, sizeof(*logicalChannelConfig->ul_SpecificParameters->schedulingRequestID)); + *logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = 0; + logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_Mask = 0; + logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = 0; + rlc_BearerConfig->mac_LogicalChannelConfig = logicalChannelConfig; + ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig); + ASN_SEQUENCE_ADD(&ue_context_mastercellGroup->rlc_BearerToAddModList->list, rlc_BearerConfig); + } // DRB Configuration - NR_RLC_BearerConfig_t *rlc_BearerConfig_drb = NULL; - NR_RLC_Config_t *rlc_Config_drb = NULL; - NR_LogicalChannelConfig_t *logicalChannelConfig_drb = NULL; - long *logicalChannelGroup_drb = NULL; - rlc_BearerConfig_drb = calloc(1, sizeof(NR_RLC_BearerConfig_t)); - rlc_BearerConfig_drb->logicalChannelIdentity = 4; - rlc_BearerConfig_drb->servedRadioBearer = calloc(1, sizeof(*rlc_BearerConfig_drb->servedRadioBearer)); - rlc_BearerConfig_drb->servedRadioBearer->present = NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity; - rlc_BearerConfig_drb->servedRadioBearer->choice.drb_Identity = 1; - rlc_BearerConfig_drb->reestablishRLC = NULL; - rlc_Config_drb = calloc(1, sizeof(NR_RLC_Config_t)); - rlc_Config_drb->present = NR_RLC_Config_PR_am; - rlc_Config_drb->choice.am = calloc(1, sizeof(*rlc_Config_drb->choice.am)); - rlc_Config_drb->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); - *(rlc_Config_drb->choice.am->dl_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size18; - rlc_Config_drb->choice.am->dl_AM_RLC.t_Reassembly = NR_T_Reassembly_ms80; - rlc_Config_drb->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms10; - rlc_Config_drb->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); - *(rlc_Config_drb->choice.am->ul_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size18; - rlc_Config_drb->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms80; - rlc_Config_drb->choice.am->ul_AM_RLC.pollPDU = NR_PollPDU_p64; - rlc_Config_drb->choice.am->ul_AM_RLC.pollByte = NR_PollByte_kB125; - rlc_Config_drb->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t4; - rlc_BearerConfig_drb->rlc_Config = rlc_Config_drb; - logicalChannelConfig_drb = calloc(1, sizeof(NR_LogicalChannelConfig_t)); - logicalChannelConfig_drb->ul_SpecificParameters = calloc(1, sizeof(*logicalChannelConfig_drb->ul_SpecificParameters)); - logicalChannelConfig_drb->ul_SpecificParameters->priority = 13; - logicalChannelConfig_drb->ul_SpecificParameters->prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8; - logicalChannelConfig_drb->ul_SpecificParameters->bucketSizeDuration = NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms100; - logicalChannelGroup_drb = CALLOC(1, sizeof(long)); - *logicalChannelGroup_drb = 1; - logicalChannelConfig_drb->ul_SpecificParameters->logicalChannelGroup = logicalChannelGroup_drb; - logicalChannelConfig_drb->ul_SpecificParameters->schedulingRequestID = CALLOC(1, sizeof(*logicalChannelConfig_drb->ul_SpecificParameters->schedulingRequestID)); - *logicalChannelConfig_drb->ul_SpecificParameters->schedulingRequestID = 0; - logicalChannelConfig_drb->ul_SpecificParameters->logicalChannelSR_Mask = 0; - logicalChannelConfig_drb->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = 0; - rlc_BearerConfig_drb->mac_LogicalChannelConfig = logicalChannelConfig_drb; - ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig_drb); - ASN_SEQUENCE_ADD(&ue_context_mastercellGroup->rlc_BearerToAddModList->list, rlc_BearerConfig_drb); + if(DRB_config_present){ + NR_RLC_BearerConfig_t *rlc_BearerConfig_drb = NULL; + NR_RLC_Config_t *rlc_Config_drb = NULL; + NR_LogicalChannelConfig_t *logicalChannelConfig_drb = NULL; + long *logicalChannelGroup_drb = NULL; + rlc_BearerConfig_drb = calloc(1, sizeof(NR_RLC_BearerConfig_t)); + rlc_BearerConfig_drb->logicalChannelIdentity = 4; + rlc_BearerConfig_drb->servedRadioBearer = calloc(1, sizeof(*rlc_BearerConfig_drb->servedRadioBearer)); + rlc_BearerConfig_drb->servedRadioBearer->present = NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity; + rlc_BearerConfig_drb->servedRadioBearer->choice.drb_Identity = 1; + rlc_BearerConfig_drb->reestablishRLC = NULL; + rlc_Config_drb = calloc(1, sizeof(NR_RLC_Config_t)); + rlc_Config_drb->present = NR_RLC_Config_PR_am; + rlc_Config_drb->choice.am = calloc(1, sizeof(*rlc_Config_drb->choice.am)); + rlc_Config_drb->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); + *(rlc_Config_drb->choice.am->dl_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size18; + rlc_Config_drb->choice.am->dl_AM_RLC.t_Reassembly = NR_T_Reassembly_ms80; + rlc_Config_drb->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms10; + rlc_Config_drb->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); + *(rlc_Config_drb->choice.am->ul_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size18; + rlc_Config_drb->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms80; + rlc_Config_drb->choice.am->ul_AM_RLC.pollPDU = NR_PollPDU_p64; + rlc_Config_drb->choice.am->ul_AM_RLC.pollByte = NR_PollByte_kB125; + rlc_Config_drb->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t4; + rlc_BearerConfig_drb->rlc_Config = rlc_Config_drb; + logicalChannelConfig_drb = calloc(1, sizeof(NR_LogicalChannelConfig_t)); + logicalChannelConfig_drb->ul_SpecificParameters = calloc(1, sizeof(*logicalChannelConfig_drb->ul_SpecificParameters)); + logicalChannelConfig_drb->ul_SpecificParameters->priority = 13; + logicalChannelConfig_drb->ul_SpecificParameters->prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8; + logicalChannelConfig_drb->ul_SpecificParameters->bucketSizeDuration = NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms100; + logicalChannelGroup_drb = CALLOC(1, sizeof(long)); + *logicalChannelGroup_drb = 1; + logicalChannelConfig_drb->ul_SpecificParameters->logicalChannelGroup = logicalChannelGroup_drb; + logicalChannelConfig_drb->ul_SpecificParameters->schedulingRequestID = CALLOC(1, sizeof(*logicalChannelConfig_drb->ul_SpecificParameters->schedulingRequestID)); + *logicalChannelConfig_drb->ul_SpecificParameters->schedulingRequestID = 0; + logicalChannelConfig_drb->ul_SpecificParameters->logicalChannelSR_Mask = 0; + logicalChannelConfig_drb->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = 0; + rlc_BearerConfig_drb->mac_LogicalChannelConfig = logicalChannelConfig_drb; + ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig_drb); + ASN_SEQUENCE_ADD(&ue_context_mastercellGroup->rlc_BearerToAddModList->list, rlc_BearerConfig_drb); + } +} + +void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGroupConfig_t *ue_context_mastercellGroup){ + /*Function to be filled with the updates on the cellGroupConfig at the UE context, + * upon reception of the NR UE capabilities at the gNB. This cellGroupConfig information + * should be communicated to the UE through the first (default) RRC Reconfiguration message*/ + LOG_I(NR_RRC, "Implementation pending \n"); } void fill_initial_cellGroupConfig(rnti_t rnti, diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 419352255a..696a5a9839 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -97,7 +97,9 @@ void fill_initial_cellGroupConfig(rnti_t rnti, NR_CellGroupConfig_t *cellGroupConfig, NR_ServingCellConfigCommon_t *scc); -void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGroupConfig_t *ue_context_mastercellGroup); +void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGroupConfig_t *ue_context_mastercellGroup); + +void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGroupConfig_t *ue_context_mastercellGroup, uint8_t SRB_config_present, uint8_t DRB_config_present); uint8_t do_RRCSetup(rrc_gNB_ue_context_t *const ue_context_pP, uint8_t *const buffer, diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 9465b9b4b0..2ac8d14a23 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -204,4 +204,5 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( void rrc_gNB_generate_dedicatedRRCReconfiguration( const protocol_ctxt_t *const ctxt_pP, - rrc_gNB_ue_context_t *ue_context_pP); + rrc_gNB_ue_context_t *ue_context_pP, + NR_CellGroupConfig_t *cell_groupConfig_from_DU); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index bd6ce4c7de..0208cc4a57 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -746,7 +746,8 @@ rrc_gNB_process_RRCSetupComplete( void rrc_gNB_generate_defaultRRCReconfiguration( const protocol_ctxt_t *const ctxt_pP, - rrc_gNB_ue_context_t *ue_context_pP + rrc_gNB_ue_context_t *ue_context_pP, + NR_CellGroupConfig_t *cellGroupConfig ) //----------------------------------------------------------------------------- { @@ -871,7 +872,7 @@ rrc_gNB_generate_defaultRRCReconfiguration( NULL, dedicatedNAS_MessageList, NULL, - NULL); + cellGroupConfig); free(ue_context_pP->ue_context.nas_pdu.buffer); @@ -960,7 +961,8 @@ rrc_gNB_generate_defaultRRCReconfiguration( void rrc_gNB_generate_dedicatedRRCReconfiguration( const protocol_ctxt_t *const ctxt_pP, - rrc_gNB_ue_context_t *ue_context_pP + rrc_gNB_ue_context_t *ue_context_pP, + NR_CellGroupConfig_t *cell_groupConfig_from_DU ) //----------------------------------------------------------------------------- { @@ -980,7 +982,7 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( NR_QFI_t qfi = 0; int pdu_sessions_done = 0; int i; - NR_CellGroupConfig_t *cellGroupConfig; + NR_CellGroupConfig_t *cellGroupConfig = NULL; uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); @@ -1117,8 +1119,13 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( } memset(buffer, 0, RRC_BUF_SIZE); - cellGroupConfig = calloc(1, sizeof(NR_CellGroupConfig_t)); - fill_mastercellGroupConfig(cellGroupConfig, ue_context_pP->ue_context.masterCellGroup); + if(cell_groupConfig_from_DU == NULL){ + cellGroupConfig = calloc(1, sizeof(NR_CellGroupConfig_t)); + fill_mastercellGroupConfig(cellGroupConfig, ue_context_pP->ue_context.masterCellGroup,1,1); + } + else{ + cellGroupConfig = cell_groupConfig_from_DU; + } size = do_RRCReconfiguration(ctxt_pP, buffer, xid, *SRB_configList2, @@ -2691,9 +2698,9 @@ rrc_gNB_decode_dcch( if(!NODE_IS_CU(RC.nrrrc[ctxt_pP->module_id]->node_type)){ if (ue_context_p->ue_context.established_pdu_sessions_flag == 1) { - rrc_gNB_generate_dedicatedRRCReconfiguration(ctxt_pP, ue_context_p); + rrc_gNB_generate_dedicatedRRCReconfiguration(ctxt_pP, ue_context_p, NULL); } else { - rrc_gNB_generate_defaultRRCReconfiguration(ctxt_pP, ue_context_p); + rrc_gNB_generate_defaultRRCReconfiguration(ctxt_pP, ue_context_p, NULL); } } else{ @@ -2747,6 +2754,8 @@ rrc_gNB_decode_dcch( (void *)ue_CapabilityRAT_ContainerList, req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, 1024); + AssertFatal (enc_rval.encoded > 0, "ASN1 ue_CapabilityRAT_ContainerList encoding failed (%s, %jd)!\n", + enc_rval.failed_type->name, enc_rval.encoded); req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length = (enc_rval.encoded+7)>>3; } itti_send_msg_to_task (TASK_CU_F1, ctxt_pP->module_id, message_p); @@ -3221,9 +3230,99 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha uint32_t incoming_teid = 0; + if(req->cu_to_du_rrc_information!=NULL){ + if(req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList!=NULL){ + LOG_I(NR_RRC, "Length of ue_CapabilityRAT_ContainerList is: %d \n", (int) req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length); + struct NR_UE_CapabilityRAT_ContainerList *ue_CapabilityRAT_ContainerList; + asn_dec_rval_t dec_rval = uper_decode_complete( NULL, + &asn_DEF_NR_UE_CapabilityRAT_ContainerList, + (void **)&ue_CapabilityRAT_ContainerList, + (uint8_t *)req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, + (int) req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length); + + if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { + AssertFatal(1==0,"UE Capability RAT ContainerList decode error\n"); + // free the memory + SEQUENCE_free( &asn_DEF_NR_UE_CapabilityRAT_ContainerList, ue_CapabilityRAT_ContainerList, 1 ); + return; + } + /*To fill ue_context.UE_Capability_MRDC, ue_context.UE_Capability_nr ...*/ + int NR_index = -1; + for(int i = 0;i < ue_CapabilityRAT_ContainerList->list.count; i++){ + if(ue_CapabilityRAT_ContainerList->list.array[i]->rat_Type == + NR_RAT_Type_nr){ + LOG_I(NR_RRC, "DU received NR_RAT_Type_nr UE capabilities Info through the UE Context Setup Request from the CU \n"); + if(ue_context_p->ue_context.UE_Capability_nr){ + ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability,ue_context_p->ue_context.UE_Capability_nr); + ue_context_p->ue_context.UE_Capability_nr = 0; + } + + dec_rval = uper_decode(NULL, + &asn_DEF_NR_UE_NR_Capability, + (void**)&ue_context_p->ue_context.UE_Capability_nr, + ue_CapabilityRAT_ContainerList->list.array[i]->ue_CapabilityRAT_Container.buf, + ue_CapabilityRAT_ContainerList->list.array[i]->ue_CapabilityRAT_Container.size, + 0,0); + if(LOG_DEBUGFLAG(DEBUG_ASN1)){ + xer_fprint(stdout,&asn_DEF_NR_UE_NR_Capability,ue_context_p->ue_context.UE_Capability_nr); + } + + if((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)){ + LOG_E(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" Failed to decode nr UE capabilities (%zu bytes)\n", + PROTOCOL_NR_RRC_CTXT_UE_ARGS(&ctxt),dec_rval.consumed); + ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability,ue_context_p->ue_context.UE_Capability_nr); + ue_context_p->ue_context.UE_Capability_nr = 0; + } + + ue_context_p->ue_context.UE_Capability_size = + ue_CapabilityRAT_ContainerList->list.array[i]->ue_CapabilityRAT_Container.size; + if(NR_index != -1){ + LOG_E(NR_RRC,"fatal: more than 1 eutra capability\n"); + exit(1); + } + NR_index = i; + } + + if(ue_CapabilityRAT_ContainerList->list.array[i]->rat_Type == + NR_RAT_Type_eutra_nr){ + LOG_I(NR_RRC, "DU received NR_RAT_Type_eutra_nr UE capabilities Info through the UE Context Setup Request from the CU \n"); + if(ue_context_p->ue_context.UE_Capability_MRDC){ + ASN_STRUCT_FREE(asn_DEF_NR_UE_MRDC_Capability,ue_context_p->ue_context.UE_Capability_MRDC); + ue_context_p->ue_context.UE_Capability_MRDC = 0; + } + dec_rval = uper_decode(NULL, + &asn_DEF_NR_UE_MRDC_Capability, + (void**)&ue_context_p->ue_context.UE_Capability_MRDC, + ue_CapabilityRAT_ContainerList->list.array[i]->ue_CapabilityRAT_Container.buf, + ue_CapabilityRAT_ContainerList->list.array[i]->ue_CapabilityRAT_Container.size, + 0,0); + if(LOG_DEBUGFLAG(DEBUG_ASN1)){ + xer_fprint(stdout,&asn_DEF_NR_UE_MRDC_Capability,ue_context_p->ue_context.UE_Capability_MRDC); + } + + if((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)){ + LOG_E(NR_RRC,PROTOCOL_NR_RRC_CTXT_FMT" Failed to decode nr UE capabilities (%zu bytes)\n", + PROTOCOL_NR_RRC_CTXT_UE_ARGS(&ctxt),dec_rval.consumed); + ASN_STRUCT_FREE(asn_DEF_NR_UE_MRDC_Capability,ue_context_p->ue_context.UE_Capability_MRDC); + ue_context_p->ue_context.UE_Capability_MRDC = 0; + } + ue_context_p->ue_context.UE_MRDC_Capability_size = + ue_CapabilityRAT_ContainerList->list.array[i]->ue_CapabilityRAT_Container.size; + } + + if(ue_CapabilityRAT_ContainerList->list.array[i]->rat_Type == + NR_RAT_Type_eutra){ + //TODO + } + } + } + } + + + NR_CellGroupConfig_t *cellGroupConfig; cellGroupConfig = calloc(1, sizeof(NR_CellGroupConfig_t)); - fill_mastercellGroupConfig(cellGroupConfig, ue_context_p->ue_context.masterCellGroup); + update_cellGroupConfig(cellGroupConfig, ue_context_p->ue_context.masterCellGroup); /* Configure SRB2 */ NR_SRB_ToAddMod_t *SRB2_config = NULL; @@ -3272,6 +3371,12 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha } } + if(req->srbs_to_be_setup_length>0 || req->drbs_to_be_setup_length>0){ + fill_mastercellGroupConfig(cellGroupConfig, ue_context_p->ue_context.masterCellGroup, + req->srbs_to_be_setup_length>0 ? 1:0, + req->drbs_to_be_setup_length>0 ? 1:0); + } + apply_macrlc_config(rrc, ue_context_p, &ctxt); /* Fill the UE context setup response ITTI message to send to F1AP */ resp->gNB_CU_ue_id = req->gNB_CU_ue_id; @@ -3307,6 +3412,10 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha else{ LOG_W(NR_RRC, "No SRB added upon reception of F1 UE Context setup request at the DU\n"); } + /* fixme: + * Here we should be probably be encoding to UE ctxt setup response the updates on cellgroupconfig (i.e., cellGroupConfig) + * instead of the whole masterCellGroup configuration stored at the UE context (i.e., ue_context_p->ue_context.masterCellGroup). + */ resp->du_to_cu_rrc_information = calloc(1,1024*sizeof(uint8_t)); asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, @@ -3357,6 +3466,12 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, const ch } xer_fprint(stdout,&asn_DEF_NR_CellGroupConfig, ue_context_p->ue_context.masterCellGroup); + if (ue_context_p->ue_context.established_pdu_sessions_flag == 1) { + rrc_gNB_generate_dedicatedRRCReconfiguration(&ctxt, ue_context_p, cellGroupConfig); + } else { + rrc_gNB_generate_defaultRRCReconfiguration(&ctxt, ue_context_p, NULL); + } + free(cellGroupConfig->rlc_BearerToAddModList); free(cellGroupConfig); diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index e8e5055cfe..7b2fb5ac10 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -1111,7 +1111,7 @@ rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ( // TEST // ue_context_p->ue_context.pdusession[0].status = PDU_SESSION_STATUS_DONE; // rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(&ctxt, ue_context_p, 0); - rrc_gNB_generate_dedicatedRRCReconfiguration(&ctxt, ue_context_p); + rrc_gNB_generate_dedicatedRRCReconfiguration(&ctxt, ue_context_p, NULL); return(0); } } From 36b8bb1b5bfbfd22d763dd0f94d811c79bfe69b9 Mon Sep 17 00:00:00 2001 From: matzakos Date: Tue, 5 Oct 2021 13:43:19 +0200 Subject: [PATCH 003/267] Trigger UE context modification request at the CU upon reception of PDU Session Resource setup request from the AMF -F1 message successfully encoded at the CU (including SRB2, DRB and F1-U tunnel configuration) and received from the DU. -Next steps: handling of UE context modification request at the DU and triggering the UE context setup response towards the CU. --- openair2/COMMON/f1ap_messages_def.h | 2 + openair2/COMMON/f1ap_messages_types.h | 10 +- openair2/F1AP/f1ap_cu_task.c | 6 + openair2/F1AP/f1ap_cu_ue_context_management.c | 402 +++++++++++++++--- openair2/F1AP/f1ap_cu_ue_context_management.h | 3 +- openair2/F1AP/f1ap_decoder.c | 4 + openair2/RRC/NR/rrc_gNB.c | 4 + openair2/RRC/NR/rrc_gNB_NGAP.c | 46 +- 8 files changed, 414 insertions(+), 63 deletions(-) diff --git a/openair2/COMMON/f1ap_messages_def.h b/openair2/COMMON/f1ap_messages_def.h index 0e857f3a83..f28e0e5ddf 100644 --- a/openair2/COMMON/f1ap_messages_def.h +++ b/openair2/COMMON/f1ap_messages_def.h @@ -46,6 +46,8 @@ MESSAGE_DEF(F1AP_DL_RRC_MESSAGE , MESSAGE_PRIORITY_MED, f1ap_dl_rrc //MESSAGE_DEF(F1AP_INITIAL_CONTEXT_SETUP_REQ , MESSAGE_PRIORITY_MED, f1ap_initial_context_setup_req_t , f1ap_initial_context_setup_req ) MESSAGE_DEF(F1AP_UE_CONTEXT_SETUP_REQ, MESSAGE_PRIORITY_MED, f1ap_ue_context_setup_t, f1ap_ue_context_setup_req) MESSAGE_DEF(F1AP_UE_CONTEXT_SETUP_RESP, MESSAGE_PRIORITY_MED, f1ap_ue_context_setup_t, f1ap_ue_context_setup_resp) +MESSAGE_DEF(F1AP_UE_CONTEXT_MODIFICATION_REQ, MESSAGE_PRIORITY_MED, f1ap_ue_context_setup_t, f1ap_ue_context_modification_req) +MESSAGE_DEF(F1AP_UE_CONTEXT_MODIFICATION_RESP, MESSAGE_PRIORITY_MED, f1ap_ue_context_setup_t, f1ap_ue_context_modification_resp) diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index 7116dd09c1..3a5b95408b 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -39,15 +39,15 @@ #define F1AP_INITIAL_UL_RRC_MESSAGE(mSGpTR) (mSGpTR)->ittiMsg.f1ap_initial_ul_rrc_message #define F1AP_UL_RRC_MESSAGE(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ul_rrc_message #define F1AP_UE_CONTEXT_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_setup_req -#define F1AP_UE_CONTEXT_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_setup_resp +#define F1AP_UE_CONTEXT_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_setup_resp #define F1AP_UE_CONTEXT_RELEASE_RESP(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_release_resp +#define F1AP_UE_CONTEXT_MODIFICATION_REQ(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_modification_req #define F1AP_UE_CONTEXT_MODIFICATION_RESP(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_modification_resp #define F1AP_UE_CONTEXT_MODIFICATION_FAIL(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_modification_fail #define F1AP_DL_RRC_MESSAGE(mSGpTR) (mSGpTR)->ittiMsg.f1ap_dl_rrc_message #define F1AP_UE_CONTEXT_RELEASE_REQ(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_release_req #define F1AP_UE_CONTEXT_RELEASE_CMD(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_release_req -#define F1AP_UE_CONTEXT_MODIFICATION_REQ(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_modification_req /* Length of the transport layer address string * 160 bits / 8 bits by char. @@ -352,6 +352,11 @@ typedef struct cu_to_du_rrc_information_s { uint8_t measConfig_length; }cu_to_du_rrc_information_t; +typedef enum QoS_information_e { + NG_RAN_QoS = 0, + EUTRAN_QoS = 1, +} QoS_information_t; + typedef struct f1ap_ue_context_setup_s { uint32_t gNB_CU_ue_id; // BK: need to replace by use from rnti uint32_t gNB_DU_ue_id; @@ -370,6 +375,7 @@ typedef struct f1ap_ue_context_setup_s { uint8_t du_to_cu_rrc_information_length; f1ap_drb_to_be_setup_t *drbs_to_be_setup; // BK: need to replace by s1ap_initial_context_setup_req uint8_t drbs_to_be_setup_length; // BK: need to replace by s1ap_initial_context_setup_req + QoS_information_t QoS_information_type; uint8_t drbs_failed_to_be_setup_length; f1ap_rb_failed_to_be_setup_t *drbs_failed_to_be_setup; f1ap_srb_to_be_setup_t *srbs_to_be_setup; diff --git a/openair2/F1AP/f1ap_cu_task.c b/openair2/F1AP/f1ap_cu_task.c index fbe0508f60..2ed80367f9 100644 --- a/openair2/F1AP/f1ap_cu_task.c +++ b/openair2/F1AP/f1ap_cu_task.c @@ -180,6 +180,12 @@ void * F1AP_CU_task(void *arg) { &F1AP_UE_CONTEXT_SETUP_REQ(received_msg)); break; + case F1AP_UE_CONTEXT_MODIFICATION_REQ: + LOG_I(F1AP, "CU Task received F1AP_UE_CONTEXT_MODIFICATION_REQ\n"); + CU_send_UE_CONTEXT_MODIFICATION_REQUEST(ITTI_MSG_DESTINATION_INSTANCE(received_msg), + &F1AP_UE_CONTEXT_MODIFICATION_REQ(received_msg)); + break; + case F1AP_UE_CONTEXT_RELEASE_CMD: // from rrc LOG_I(F1AP, "CU Task Received F1AP_UE_CONTEXT_RELEASE_CMD\n"); CU_send_UE_CONTEXT_RELEASE_COMMAND(ITTI_MSG_DESTINATION_INSTANCE(received_msg), diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index 0b72b2b5a4..40cac2398f 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -1016,7 +1016,7 @@ int CU_handle_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, return 0; } //void CU_send_UE_CONTEXT_MODIFICATION_REQUEST(F1AP_UEContextModificationRequest_t *UEContextModificationRequest) { -int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance) { +int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, f1ap_ue_context_setup_t *f1ap_ue_context_modification_req) { F1AP_F1AP_PDU_t pdu= {0}; F1AP_UEContextModificationRequest_t *out; uint8_t *buffer=NULL; @@ -1037,14 +1037,14 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance) { ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; ie1->criticality = F1AP_Criticality_reject; ie1->value.present = F1AP_UEContextModificationRequestIEs__value_PR_GNB_CU_UE_F1AP_ID; - ie1->value.choice.GNB_CU_UE_F1AP_ID = 126L; + ie1->value.choice.GNB_CU_UE_F1AP_ID = f1ap_get_cu_ue_f1ap_id(CUtype, instance, f1ap_ue_context_modification_req->rnti);; /* mandatory */ /* c2. GNB_DU_UE_F1AP_ID */ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie2); ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; ie2->criticality = F1AP_Criticality_reject; ie2->value.present = F1AP_UEContextModificationRequestIEs__value_PR_GNB_DU_UE_F1AP_ID; - ie2->value.choice.GNB_DU_UE_F1AP_ID = 651L; + ie2->value.choice.GNB_DU_UE_F1AP_ID = f1ap_get_du_ue_f1ap_id(CUtype, instance, f1ap_ue_context_modification_req->rnti);; /* optional */ /* c3. NRCGI */ @@ -1057,13 +1057,15 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance) { addnRCGI(ie3->value.choice.NRCGI, &hardCoded); } - /* mandatory */ + /* optional */ /* c4. ServCellIndex */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie4); - ie4->id = F1AP_ProtocolIE_ID_id_ServCellIndex; - ie4->criticality = F1AP_Criticality_reject; - ie4->value.present = F1AP_UEContextModificationRequestIEs__value_PR_ServCellIndex; - ie4->value.choice.ServCellIndex = 5L; + if(0){ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie4); + ie4->id = F1AP_ProtocolIE_ID_id_ServCellIndex; + ie4->criticality = F1AP_Criticality_reject; + ie4->value.present = F1AP_UEContextModificationRequestIEs__value_PR_ServCellIndex; + ie4->value.choice.ServCellIndex = 5L; + } /* optional */ /* c5. DRXCycle */ @@ -1076,7 +1078,7 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance) { if (0) { asn1cCallocOne(ie5->value.choice.DRXCycle.shortDRXCycleLength, - F1AP_ShortDRXCycleLength_ms2); // enum + F1AP_ShortDRXCycleLength_ms2); // enum } if (0) { @@ -1086,25 +1088,36 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance) { /* optional */ /* c5. CUtoDURRCInformation */ - if (1) { + if (f1ap_ue_context_modification_req->cu_to_du_rrc_information!=NULL) { asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie5); ie5->id = F1AP_ProtocolIE_ID_id_CUtoDURRCInformation; ie5->criticality = F1AP_Criticality_reject; ie5->value.present = F1AP_UEContextModificationRequestIEs__value_PR_CUtoDURRCInformation; - asn1cCalloc(ie5->value.choice.CUtoDURRCInformation.cG_ConfigInfo, tmp); + /* 6.1 cG_ConfigInfo */ + if(f1ap_ue_context_modification_req->cu_to_du_rrc_information->cG_ConfigInfo!=NULL){ + const char cG_ConfigInfoStr[]="asdsa1d32sa1d31asd31as"; + asn1cCalloc(ie5->value.choice.CUtoDURRCInformation.cG_ConfigInfo, cG_ConfigInfo); + OCTET_STRING_fromBuf(cG_ConfigInfo, cG_ConfigInfoStr, strlen(cG_ConfigInfoStr)) ; + } /* optional */ - OCTET_STRING_fromBuf(tmp, "asdsa1d32sa1d31asd31as", - strlen("asdsa1d32sa1d31asd31as")); - asn1cCalloc(ie5->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList, - tmp2); + /* 6.2 uE_CapabilityRAT_ContainerList */ + if(f1ap_ue_context_modification_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList!=NULL){ + asn1cCalloc(ie5->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList, uE_CapabilityRAT_ContainerList ); + OCTET_STRING_fromBuf(uE_CapabilityRAT_ContainerList, (const char *)f1ap_ue_context_modification_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, + f1ap_ue_context_modification_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length) ; + } /* optional */ - OCTET_STRING_fromBuf(tmp2, "asdsa1d32sa1d31asd31as", - strlen("asdsa1d32sa1d31asd31as")); + /* 6.3 measConfig */ + if(f1ap_ue_context_modification_req->cu_to_du_rrc_information->measConfig!=NULL){ + const char measConfigStr[]="asdsa1d32sa1d31asd31as"; + asn1cCalloc(ie5->value.choice.CUtoDURRCInformation.measConfig, measConfig); + OCTET_STRING_fromBuf(measConfig, measConfigStr, strlen(measConfigStr)) ; + } } /* optional */ /* c6. TransmissionActionIndicator */ - if (1) { + if (0) { asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie6); ie6->id = F1AP_ProtocolIE_ID_id_TransmissionActionIndicator; ie6->criticality = F1AP_Criticality_ignore; @@ -1125,7 +1138,7 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance) { /* optional */ /* c7. RRCRconfigurationCompleteIndicator */ - if (1) { + if (0) { asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie71); ie71->id = F1AP_ProtocolIE_ID_id_RRCReconfigurationCompleteIndicator; ie71->criticality = F1AP_Criticality_ignore; @@ -1135,7 +1148,7 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance) { /* optional */ /* c8. RRCContainer */ - if (1) { + if (0) { asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie8); ie8->id = F1AP_ProtocolIE_ID_id_RRCContainer; ie8->criticality = F1AP_Criticality_ignore; @@ -1144,8 +1157,9 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance) { strlen("asdsa1d32sa1d31asd31as")); } - /* mandatory */ + /* optional */ /* c9. SCell_ToBeSetupMod_List */ + if(0){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie9); ie9->id = F1AP_ProtocolIE_ID_id_SCell_ToBeSetupMod_List; ie9->criticality = F1AP_Criticality_ignore; @@ -1166,9 +1180,11 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance) { /* sCellIndex */ scell_toBeSetupMod_item->sCellIndex = 6; // issue here } + } - /* mandatory */ + /* optional */ /* c10. SCell_ToBeRemoved_List */ + if(0){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie10); ie10->id = F1AP_ProtocolIE_ID_id_SCell_ToBeRemoved_List; ie10->criticality = F1AP_Criticality_ignore; @@ -1189,37 +1205,44 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance) { /* - sCell_ID */ addnRCGI(scell_toBeRemoved_item->sCell_ID, &hardCoded); } + } /* mandatory */ /* c11. SRBs_ToBeSetupMod_List */ + if(f1ap_ue_context_modification_req->srbs_to_be_setup_length > 0){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie11); ie11->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_List; ie11->criticality = F1AP_Criticality_reject; ie11->value.present = F1AP_UEContextModificationRequestIEs__value_PR_SRBs_ToBeSetupMod_List; - for (int i=0; i<1; i++) { + for (int i=0; isrbs_to_be_setup_length; i++) { // - asn1cSequenceAdd(ie11->value.choice.SRBs_ToBeSetupMod_List.list, - F1AP_SRBs_ToBeSetupMod_ItemIEs_t, srbs_toBeSetupMod_item_ies); - srbs_toBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_Item; - srbs_toBeSetupMod_item_ies->criticality = F1AP_Criticality_ignore; + asn1cSequenceAdd(ie11->value.choice.SRBs_ToBeSetupMod_List, F1AP_SRBs_ToBeSetupMod_ItemIEs_t, srbs_toBeSetupMod_item_ies); + srbs_toBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_Item; // 73 + srbs_toBeSetupMod_item_ies->criticality = F1AP_Criticality_reject; srbs_toBeSetupMod_item_ies->value.present = F1AP_SRBs_ToBeSetupMod_ItemIEs__value_PR_SRBs_ToBeSetupMod_Item; - /* 9.1 SRBs_ToBeSetupMod_Item */ - F1AP_SRBs_ToBeSetupMod_Item_t *srbs_toBeSetupMod_item= - &srbs_toBeSetupMod_item_ies->value.choice.SRBs_ToBeSetupMod_Item; - /* - sRBID */ - srbs_toBeSetupMod_item->sRBID = 3L; + /* 11.1 SRBs_ToBeSetup_Item */ + F1AP_SRBs_ToBeSetupMod_Item_t *srbs_toBeSetupMod_item=&srbs_toBeSetupMod_item_ies->value.choice.SRBs_ToBeSetupMod_Item; + /* 11.1.1 sRBID */ + srbs_toBeSetupMod_item->sRBID = f1ap_ue_context_modification_req->srbs_to_be_setup[i].srb_id; + /* OPTIONAL */ + /* 11.1.2 duplicationIndication */ + //if (0) { + asn1cCallocOne(srbs_toBeSetupMod_item->duplicationIndication, + F1AP_DuplicationIndication_true); // enum + //} + } } /* mandatory */ /* c12. DRBs_ToBeSetupMod_List */ + if(f1ap_ue_context_modification_req->drbs_to_be_setup_length){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie12); ie12->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_List; ie12->criticality = F1AP_Criticality_reject; ie12->value.present = F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeSetupMod_List; - for (int i=0; i<1; i++) { - // + for (int i = 0; i < f1ap_ue_context_modification_req->drbs_to_be_setup_length; i++) { asn1cSequenceAdd(ie12->value.choice.DRBs_ToBeSetupMod_List.list, F1AP_DRBs_ToBeSetupMod_ItemIEs_t, drbs_toBeSetupMod_item_ies); drbs_toBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_Item; @@ -1229,39 +1252,295 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance) { F1AP_DRBs_ToBeSetupMod_Item_t *drbs_toBeSetupMod_item= &drbs_toBeSetupMod_item_ies->value.choice.DRBs_ToBeSetupMod_Item; /* dRBID */ - drbs_toBeSetupMod_item->dRBID = 30L; + drbs_toBeSetupMod_item->dRBID = f1ap_ue_context_modification_req->drbs_to_be_setup[i].drb_id; /* qoSInformation */ - drbs_toBeSetupMod_item->qoSInformation.present = F1AP_QoSInformation_PR_eUTRANQoS; - drbs_toBeSetupMod_item->qoSInformation.choice.eUTRANQoS = (F1AP_EUTRANQoS_t *)calloc(1, sizeof(F1AP_EUTRANQoS_t)); - drbs_toBeSetupMod_item->qoSInformation.choice.eUTRANQoS->qCI = 253L; - /* uLUPTNLInformation_ToBeSetup_List */ - int maxnoofULTunnels = 1; // 2; - for (int j=0; juLUPTNLInformation_ToBeSetup_List.list, + if(f1ap_ue_context_modification_req->QoS_information_type == EUTRAN_QoS){ + drbs_toBeSetupMod_item->qoSInformation.present = F1AP_QoSInformation_PR_eUTRANQoS; + drbs_toBeSetupMod_item->qoSInformation.choice.eUTRANQoS = (F1AP_EUTRANQoS_t *)calloc(1, sizeof(F1AP_EUTRANQoS_t)); + drbs_toBeSetupMod_item->qoSInformation.choice.eUTRANQoS->qCI = 253L; + /* uLUPTNLInformation_ToBeSetup_List */ + int maxnoofULTunnels = 1; // 2; + + for (int j=0; juLUPTNLInformation_ToBeSetup_List.list, F1AP_ULUPTNLInformation_ToBeSetup_Item_t, uLUPTNLInformation_ToBeSetup_Item); - uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; - asn1cCalloc(uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.choice.gTPTunnel, + uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; + asn1cCalloc(uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.choice.gTPTunnel, gTPTunnel) - /* transportLayerAddress */ - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(1234, &gTPTunnel->transportLayerAddress); - /* gTP_TEID */ - OCTET_STRING_fromBuf(&gTPTunnel->gTP_TEID, "4567", - strlen("4567")); + /* transportLayerAddress */ + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(1234, &gTPTunnel->transportLayerAddress); + /* gTP_TEID */ + OCTET_STRING_fromBuf(&gTPTunnel->gTP_TEID, "4567", + strlen("4567")); } - /* rLCMode */ - drbs_toBeSetupMod_item->rLCMode = F1AP_RLCMode_rlc_um_bidirectional; // enum + /* rLCMode */ + drbs_toBeSetupMod_item->rLCMode = F1AP_RLCMode_rlc_um_bidirectional; // enum + + /* OPTIONAL */ + /* ULConfiguration */ + if (0) { + drbs_toBeSetupMod_item->uLConfiguration = (F1AP_ULConfiguration_t *)calloc(1, sizeof(F1AP_ULConfiguration_t)); + } + } //QoS information + + else{ + /* 12.1.2 DRB_Information */ + drbs_toBeSetupMod_item->qoSInformation.present = F1AP_QoSInformation_PR_choice_extension; + F1AP_QoSInformation_ExtIEs_t *ie = (F1AP_QoSInformation_ExtIEs_t *)calloc(1, sizeof(*ie)); + ie->id = F1AP_ProtocolIE_ID_id_DRB_Information; + ie->criticality = F1AP_Criticality_reject; + ie->value.present = F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information; + F1AP_DRB_Information_t *DRB_Information = &ie->value.choice.DRB_Information; + drbs_toBeSetupMod_item->qoSInformation.choice.choice_extension = (struct F1AP_ProtocolIE_SingleContainer *)ie; + /* 12.1.2.1 dRB_QoS */ + { + /* qoS_Characteristics */ + { + int some_decide_qoS_characteristics = 0; // BK: Need Check + + if (some_decide_qoS_characteristics) { + DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI; + setQos(DRB_Information->dRB_QoS.qoS_Characteristics.choice.non_Dynamic_5QI); + } else { + DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_dynamic_5QI; + asn1cCalloc(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI, tmp); + /* qoSPriorityLevel */ + tmp->qoSPriorityLevel = 1L; + /* packetDelayBudget */ + tmp->packetDelayBudget = 1L; + /* packetErrorRate */ + tmp->packetErrorRate.pER_Scalar = 1L; + tmp->packetErrorRate.pER_Exponent = 6L; + + /* OPTIONAL */ + /* delayCritical */ + if (0) { + asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->delayCritical, 1L); + } + + /* OPTIONAL */ + /* averagingWindow */ + if (0) { + asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->averagingWindow, 1L); + } + + /* OPTIONAL */ + /* maxDataBurstVolume */ + if (0) { + asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->maxDataBurstVolume, 1L); + } + } // if some_decide_qoS_characteristics + + } // qoS_Characteristics + /* nGRANallocationRetentionPriority */ + { + DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum + DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_shall_not_trigger_pre_emption; // enum + DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum + } // nGRANallocationRetentionPriority + + /* OPTIONAL */ + /* gBR_QoS_Flow_Information */ + if (0) { + asn1cCalloc(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information, tmp); + asn_long2INTEGER(&tmp->maxFlowBitRateDownlink, 1L); + asn_long2INTEGER(&tmp->maxFlowBitRateUplink, 1L); + asn_long2INTEGER(&tmp->guaranteedFlowBitRateDownlink, 1L); + asn_long2INTEGER(&tmp->guaranteedFlowBitRateUplink, 1L); + + /* OPTIONAL */ + /* maxPacketLossRateDownlink */ + if (0) { + asn1cCallocOne(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information->maxPacketLossRateDownlink, 1L); + } + + /* OPTIONAL */ + /* maxPacketLossRateUplink */ + if (0) { + asn1cCallocOne(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information->maxPacketLossRateUplink, 1L); + } + } + + /* OPTIONAL */ + /* reflective_QoS_Attribute */ + if (0) { + asn1cCallocOne(DRB_Information->dRB_QoS.reflective_QoS_Attribute, 1L); + } + } // dRB_QoS + /* 12.1.2.2 sNSSAI */ + { + /* sST */ + + OCTET_STRING_fromBuf(&DRB_Information->sNSSAI.sST, "1", 1); + + /* OPTIONAL */ + /* sD */ + if (0) { + asn1cCalloc(DRB_Information->sNSSAI.sD, tmp); + OCTET_STRING_fromBuf(tmp, "asdsa1d32sa1d31asd31as", + strlen("asdsa1d32sa1d31asd31as")); + } + } /* OPTIONAL */ - /* ULConfiguration */ + /* 12.1.2.3 notificationControl */ if (0) { - drbs_toBeSetupMod_item->uLConfiguration = (F1AP_ULConfiguration_t *)calloc(1, sizeof(F1AP_ULConfiguration_t)); + asn1cCallocOne(DRB_Information->notificationControl, + F1AP_NotificationControl_active); // enum + } + + /* 12.1.2.4 flows_Mapped_To_DRB_List */ // BK: need verifiy + + for (int k = 0; k < 1; k ++) { + asn1cSequenceAdd(DRB_Information->flows_Mapped_To_DRB_List.list, + F1AP_Flows_Mapped_To_DRB_Item_t, flows_mapped_to_drb_item); + /* qoSFlowIndicator */ + flows_mapped_to_drb_item->qoSFlowIdentifier = 1L; + /* qoSFlowLevelQoSParameters */ + { + /* qoS_Characteristics */ + { + int some_decide_qoS_characteristics = 0; // BK: Need Check + F1AP_QoS_Characteristics_t *QosParams=&flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.qoS_Characteristics; + + if (some_decide_qoS_characteristics) { + QosParams->present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI; + setQos(QosParams->choice.non_Dynamic_5QI); + } else { + QosParams->present = F1AP_QoS_Characteristics_PR_dynamic_5QI; + asn1cCalloc(QosParams->choice.dynamic_5QI, tmp); + /* qoSPriorityLevel */ + tmp->qoSPriorityLevel = 1L; + /* packetDelayBudget */ + tmp->packetDelayBudget = 1L; + /* packetErrorRate */ + tmp->packetErrorRate.pER_Scalar = 1L; + tmp->packetErrorRate.pER_Exponent = 6L; + + /* OPTIONAL */ + /* delayCritical */ + if (0) { + asn1cCalloc(QosParams->choice.dynamic_5QI->delayCritical, tmp); + *tmp = 1L; + } + + /* OPTIONAL */ + /* averagingWindow */ + if (0) { + asn1cCalloc(QosParams->choice.dynamic_5QI->averagingWindow, tmp); + *tmp = 1L; + } + + /* OPTIONAL */ + /* maxDataBurstVolume */ + if (0) { + asn1cCalloc(QosParams->choice.dynamic_5QI->maxDataBurstVolume, tmp); + *tmp= 1L; + } + } // if some_decide_qoS_characteristics + + } // qoS_Characteristics + /* nGRANallocationRetentionPriority */ + { + flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum + flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_shall_not_trigger_pre_emption; // enum + flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum + } // nGRANallocationRetentionPriority + + /* OPTIONAL */ + /* gBR_QoS_Flow_Information */ + if (0) { + asn1cCalloc(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information, tmp); + asn_long2INTEGER(&tmp->maxFlowBitRateDownlink, 1L); + asn_long2INTEGER(&tmp->maxFlowBitRateUplink, 1L); + asn_long2INTEGER(&tmp->guaranteedFlowBitRateDownlink, 1L); + asn_long2INTEGER(&tmp->guaranteedFlowBitRateUplink, 1L); + + /* OPTIONAL */ + /* maxPacketLossRateDownlink */ + if (0) { + asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information->maxPacketLossRateDownlink, 1L); + } + + /* OPTIONAL */ + /* maxPacketLossRateUplink */ + if (0) { + asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information->maxPacketLossRateUplink, 1L); + } + } + + /* OPTIONAL */ + /* reflective_QoS_Attribute */ + if (0) { + asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.reflective_QoS_Attribute, 1L); + } + } // qoSFlowLevelQoSParameters + } + + } //QoS information + + /* 12.1.3 uLUPTNLInformation_ToBeSetup_List */ + for (int j = 0; j < f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl_length; j++) { + /*Use a dummy teid for the outgoing GTP-U tunnel (DU) which will be updated once we get the UE context setup response from the DU*/ + transport_layer_addr_t addr; + int sz=sizeof(f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_dl_tnl[0].tl_address); + memcpy(addr.buffer,&f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_dl_tnl[0].tl_address, sz); + addr.length = sz*8; + + f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl[j].teid= + newGtpuCreateTunnel(getCxt(CUtype, instance)->gtpInst, + f1ap_ue_context_modification_req->rnti, + f1ap_ue_context_modification_req->drbs_to_be_setup[i].drb_id, + f1ap_ue_context_modification_req->drbs_to_be_setup[i].drb_id, + 0xFFFF, // We will set the right value from DU answer + addr, + f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_dl_tnl[0].port, + cu_f1u_data_req); + /* 12.3.1 ULTunnels_ToBeSetup_Item */ + asn1cSequenceAdd(drbs_toBeSetupMod_item->uLUPTNLInformation_ToBeSetup_List.list, + F1AP_ULUPTNLInformation_ToBeSetup_Item_t, uLUPTNLInformation_ToBeSetup_Item); + uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; + asn1cCalloc( uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.choice.gTPTunnel, + gTPTunnel); + /* 12.3.1.1.1 transportLayerAddress */ + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl[j].tl_address, + &gTPTunnel->transportLayerAddress); + /* 12.3.1.1.2 gTP_TEID */ + INT32_TO_OCTET_STRING(f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl[j].teid, + &gTPTunnel->gTP_TEID); + } + /* 12.1.4 rLCMode */ + /* TODO use rlc_mode from f1ap_drb_to_be_setup */ + switch (f1ap_ue_context_modification_req->drbs_to_be_setup[i].rlc_mode) { + case RLC_MODE_AM: + drbs_toBeSetupMod_item->rLCMode = F1AP_RLCMode_rlc_am; + break; + + default: + drbs_toBeSetupMod_item->rLCMode = F1AP_RLCMode_rlc_um_bidirectional; + } + + /* OPTIONAL */ + /* 12.1.5 ULConfiguration */ + if (0) { + asn1cCalloc(drbs_toBeSetupMod_item->uLConfiguration, tmp); + tmp->uLUEConfiguration = F1AP_ULUEConfiguration_no_data; + } + + /* OPTIONAL */ + /* 12.1.6 duplicationActivation */ + if (0) { + asn1cCalloc(drbs_toBeSetupMod_item->duplicationActivation, tmp); + *tmp = F1AP_DuplicationActivation_active; // enum } } + } - /* mandatory */ + /* optional */ + if(0){ /* c13. DRBs_ToBeModified_List */ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie13); ie13->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeModified_List; @@ -1306,8 +1585,10 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance) { drbs_toBeModified_item->uLConfiguration = (F1AP_ULConfiguration_t *)calloc(1, sizeof(F1AP_ULConfiguration_t)); } } + } - /* mandatory */ + /* optional */ + if(0){ /* c14. SRBs_ToBeReleased_List */ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie14); ie14->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeReleased_List; @@ -1327,8 +1608,10 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance) { /* - sRBID */ srbs_toBeReleased_item->sRBID = 2L; } + } - /* mandatory */ + /* optional */ + if(0){ /* c15. DRBs_ToBeReleased_List */ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie15); ie15->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_List; @@ -1348,13 +1631,14 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance) { /* dRBID */ drbs_toBeReleased_item->dRBID = 30L; } + } /* encode */ if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { LOG_E(F1AP, "Failed to encode F1 UE CONTEXT_MODIFICATION REQUEST\n"); return -1; } - + f1ap_itti_send_sctp_data_req(true, instance, buffer, len, 0 /* BK: fix me*/); return 0; } diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.h b/openair2/F1AP/f1ap_cu_ue_context_management.h index 09af51ec54..87563e97b1 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.h +++ b/openair2/F1AP/f1ap_cu_ue_context_management.h @@ -72,7 +72,8 @@ int CU_handle_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, /* * UE Context Modification (gNB-CU initiated) */ -int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance); +int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, + f1ap_ue_context_setup_t *f1ap_ue_context_modification_req); int CU_handle_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, uint32_t assoc_id, uint32_t stream, diff --git a/openair2/F1AP/f1ap_decoder.c b/openair2/F1AP/f1ap_decoder.c index 6ebf1cc16d..f1e4410786 100644 --- a/openair2/F1AP/f1ap_decoder.c +++ b/openair2/F1AP/f1ap_decoder.c @@ -78,6 +78,10 @@ static int f1ap_decode_initiating_message(F1AP_F1AP_PDU_t *pdu) { case F1AP_ProcedureCode_id_UEContextSetup: LOG_I(F1AP, "%s(): F1AP_ProcedureCode_id_UEContextSetup\n", __func__); break; + + case F1AP_ProcedureCode_id_UEContextModification: + LOG_I(F1AP, "%s(): F1AP_ProcedureCode_id_UEContextModification\n", __func__); + break; // case F1AP_ProcedureCode_id_InitialContextSetup: // res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_F1AP_F1AP_PDU, pdu); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 0208cc4a57..f91d2a9ad0 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -3979,6 +3979,10 @@ void *rrc_gnb_task(void *args_p) { rrc_CU_process_ue_context_setup_response(msg_p, msg_name_p, instance); break; + case F1AP_UE_CONTEXT_MODIFICATION_REQ: + LOG_I(NR_RRC, "F1AP_UE_CONTEXT_MODIFICATION_REQ itti message received from the F1AP layer of the DU \n"); + break; + /* Messages from X2AP */ case X2AP_ENDC_SGNB_ADDITION_REQ: LOG_I(NR_RRC, "Received ENDC sgNB addition request from X2AP \n"); diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 7b2fb5ac10..69d3e4a52b 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -1111,7 +1111,51 @@ rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ( // TEST // ue_context_p->ue_context.pdusession[0].status = PDU_SESSION_STATUS_DONE; // rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(&ctxt, ue_context_p, 0); - rrc_gNB_generate_dedicatedRRCReconfiguration(&ctxt, ue_context_p, NULL); + if(!NODE_IS_CU(RC.nrrrc[ctxt.module_id]->node_type)){ + rrc_gNB_generate_dedicatedRRCReconfiguration(&ctxt, ue_context_p, NULL); + } + else{ + /*Generate a UE context modification request message towards the DU to instruct the DU + *for SRB2 and DRB configuration and get the updates on master cell group config from the DU*/ + MessageDef *message_p; + message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, F1AP_UE_CONTEXT_MODIFICATION_REQ); + f1ap_ue_context_setup_t *req=&F1AP_UE_CONTEXT_MODIFICATION_REQ (message_p); + //UE_IDs will be extracted from F1AP layer + req->gNB_CU_ue_id = 0; + req->gNB_DU_ue_id = 0; + req->rnti = ue_context_p->ue_context.rnti; + req->mcc = RC.nrrrc[ctxt.module_id]->configuration.mcc[0]; + req->mnc = RC.nrrrc[ctxt.module_id]->configuration.mnc[0]; + req->mnc_digit_length = RC.nrrrc[ctxt.module_id]->configuration.mnc_digit_length[0]; + req->nr_cellid = RC.nrrrc[ctxt.module_id]->nr_cellid; + + //if (ue_context_p->ue_context.established_pdu_sessions_flag == 1) { + /*Instruction towards the DU for SRB2 configuration*/ + req->srbs_to_be_setup = malloc(1*sizeof(f1ap_srb_to_be_setup_t)); + req->srbs_to_be_setup_length = 1; + f1ap_srb_to_be_setup_t *SRBs=req->srbs_to_be_setup; + SRBs[0].srb_id = 2; + SRBs[0].lcid = 2; + + /*Instruction towards the DU for DRB configuration and tunnel creation*/ + gtpv1u_gnb_create_tunnel_req_t create_tunnel_req; + memset(&create_tunnel_req, 0, sizeof(gtpv1u_gnb_create_tunnel_req_t)); + req->drbs_to_be_setup = malloc(1*sizeof(f1ap_drb_to_be_setup_t)); + req->drbs_to_be_setup_length = 1; + f1ap_drb_to_be_setup_t *DRBs=req->drbs_to_be_setup; + LOG_I(RRC, "Length of DRB list:%d \n", req->drbs_to_be_setup_length); + DRBs[0].drb_id = 1; + DRBs[0].rlc_mode = RLC_MODE_AM; + DRBs[0].up_ul_tnl[0].tl_address = inet_addr(RC.nrrrc[ctxt.module_id]->eth_params_s.my_addr); + DRBs[0].up_ul_tnl[0].port=RC.nrrrc[ctxt.module_id]->eth_params_s.my_portd; + DRBs[0].up_ul_tnl_length = 1; + DRBs[0].up_dl_tnl[0].tl_address = inet_addr(RC.nrrrc[ctxt.module_id]->eth_params_s.remote_addr); + DRBs[0].up_dl_tnl[0].port=RC.nrrrc[ctxt.module_id]->eth_params_s.remote_portd; + DRBs[0].up_dl_tnl_length = 1; + //} + + itti_send_msg_to_task (TASK_CU_F1, ctxt.module_id, message_p); + } return(0); } } From b3c0095f0726e5db0f6f794ad8e474733c6ba9a5 Mon Sep 17 00:00:00 2001 From: matzakos Date: Tue, 5 Oct 2021 17:24:16 +0200 Subject: [PATCH 004/267] Add handler function for UE context modification request message at F1AP layer of the DU -Fix indentation in UE context modification request message generation function at the CU --- openair2/COMMON/f1ap_messages_types.h | 6 + openair2/F1AP/f1ap_cu_ue_context_management.c | 744 +++++++++--------- openair2/F1AP/f1ap_du_ue_context_management.c | 151 +++- openair2/F1AP/f1ap_handlers.c | 2 +- 4 files changed, 529 insertions(+), 374 deletions(-) diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index 3a5b95408b..2881910b19 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -357,6 +357,11 @@ typedef enum QoS_information_e { EUTRAN_QoS = 1, } QoS_information_t; +typedef enum ReconfigurationCompl_e { + RRCreconf_failure = 0, + RRCreconf_success = 1, +} ReconfigurationCompl_t; + typedef struct f1ap_ue_context_setup_s { uint32_t gNB_CU_ue_id; // BK: need to replace by use from rnti uint32_t gNB_DU_ue_id; @@ -383,6 +388,7 @@ typedef struct f1ap_ue_context_setup_s { uint8_t srbs_failed_to_be_setup_length; f1ap_rb_failed_to_be_setup_t *srbs_failed_to_be_setup; s1ap_initial_context_setup_req_t *s1ap_initial_context_setup_req; + ReconfigurationCompl_t ReconfigComplOutcome; // coniatner for the rrc_eNB_generate_SecurityModeCommand message uint8_t *rrc_container; int rrc_container_length; diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index 40cac2398f..087d63d3f1 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -1160,338 +1160,338 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, f1ap_ue_context /* optional */ /* c9. SCell_ToBeSetupMod_List */ if(0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie9); - ie9->id = F1AP_ProtocolIE_ID_id_SCell_ToBeSetupMod_List; - ie9->criticality = F1AP_Criticality_ignore; - ie9->value.present = F1AP_UEContextModificationRequestIEs__value_PR_SCell_ToBeSetupMod_List; + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie9); + ie9->id = F1AP_ProtocolIE_ID_id_SCell_ToBeSetupMod_List; + ie9->criticality = F1AP_Criticality_ignore; + ie9->value.present = F1AP_UEContextModificationRequestIEs__value_PR_SCell_ToBeSetupMod_List; - for (int i=0; i<1; i++) { - // - asn1cSequenceAdd(ie9->value.choice.SCell_ToBeSetupMod_List.list, + for (int i=0; i<1; i++) { + // + asn1cSequenceAdd(ie9->value.choice.SCell_ToBeSetupMod_List.list, F1AP_SCell_ToBeSetupMod_ItemIEs_t, scell_toBeSetupMod_item_ies); - scell_toBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_SCell_ToBeSetupMod_Item; - scell_toBeSetupMod_item_ies->criticality = F1AP_Criticality_ignore; - scell_toBeSetupMod_item_ies->value.present = F1AP_SCell_ToBeSetupMod_ItemIEs__value_PR_SCell_ToBeSetupMod_Item; - /* 8.1 SCell_ToBeSetup_Item */ - F1AP_SCell_ToBeSetupMod_Item_t *scell_toBeSetupMod_item= - &scell_toBeSetupMod_item_ies->value.choice.SCell_ToBeSetupMod_Item; - // /* - sCell_ID */ - addnRCGI(scell_toBeSetupMod_item->sCell_ID, &hardCoded); - /* sCellIndex */ - scell_toBeSetupMod_item->sCellIndex = 6; // issue here - } + scell_toBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_SCell_ToBeSetupMod_Item; + scell_toBeSetupMod_item_ies->criticality = F1AP_Criticality_ignore; + scell_toBeSetupMod_item_ies->value.present = F1AP_SCell_ToBeSetupMod_ItemIEs__value_PR_SCell_ToBeSetupMod_Item; + /* 8.1 SCell_ToBeSetup_Item */ + F1AP_SCell_ToBeSetupMod_Item_t *scell_toBeSetupMod_item= + &scell_toBeSetupMod_item_ies->value.choice.SCell_ToBeSetupMod_Item; + // /* - sCell_ID */ + addnRCGI(scell_toBeSetupMod_item->sCell_ID, &hardCoded); + /* sCellIndex */ + scell_toBeSetupMod_item->sCellIndex = 6; // issue here + } } /* optional */ /* c10. SCell_ToBeRemoved_List */ if(0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie10); - ie10->id = F1AP_ProtocolIE_ID_id_SCell_ToBeRemoved_List; - ie10->criticality = F1AP_Criticality_ignore; - ie10->value.present = F1AP_UEContextModificationRequestIEs__value_PR_SCell_ToBeRemoved_List; + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie10); + ie10->id = F1AP_ProtocolIE_ID_id_SCell_ToBeRemoved_List; + ie10->criticality = F1AP_Criticality_ignore; + ie10->value.present = F1AP_UEContextModificationRequestIEs__value_PR_SCell_ToBeRemoved_List; - for (int i=0; i<1; i++) { - // - asn1cSequenceAdd(ie10->value.choice.SCell_ToBeRemoved_List.list, + for (int i=0; i<1; i++) { + // + asn1cSequenceAdd(ie10->value.choice.SCell_ToBeRemoved_List.list, F1AP_SCell_ToBeRemoved_ItemIEs_t, scell_toBeRemoved_item_ies); - scell_toBeRemoved_item_ies = (F1AP_SCell_ToBeRemoved_ItemIEs_t *)calloc(1, sizeof(F1AP_SCell_ToBeRemoved_ItemIEs_t)); - //memset((void *)&scell_toBeRemoved_item_ies, 0, sizeof(F1AP_SCell_ToBeRemoved_ItemIEs_t)); - scell_toBeRemoved_item_ies->id = F1AP_ProtocolIE_ID_id_SCell_ToBeRemoved_Item; - scell_toBeRemoved_item_ies->criticality = F1AP_Criticality_ignore; - scell_toBeRemoved_item_ies->value.present = F1AP_SCell_ToBeRemoved_ItemIEs__value_PR_SCell_ToBeRemoved_Item; - /* 10.1 SCell_ToBeRemoved_Item */ - F1AP_SCell_ToBeRemoved_Item_t *scell_toBeRemoved_item= - &scell_toBeRemoved_item_ies->value.choice.SCell_ToBeRemoved_Item; - /* - sCell_ID */ - addnRCGI(scell_toBeRemoved_item->sCell_ID, &hardCoded); - } + scell_toBeRemoved_item_ies = (F1AP_SCell_ToBeRemoved_ItemIEs_t *)calloc(1, sizeof(F1AP_SCell_ToBeRemoved_ItemIEs_t)); + //memset((void *)&scell_toBeRemoved_item_ies, 0, sizeof(F1AP_SCell_ToBeRemoved_ItemIEs_t)); + scell_toBeRemoved_item_ies->id = F1AP_ProtocolIE_ID_id_SCell_ToBeRemoved_Item; + scell_toBeRemoved_item_ies->criticality = F1AP_Criticality_ignore; + scell_toBeRemoved_item_ies->value.present = F1AP_SCell_ToBeRemoved_ItemIEs__value_PR_SCell_ToBeRemoved_Item; + /* 10.1 SCell_ToBeRemoved_Item */ + F1AP_SCell_ToBeRemoved_Item_t *scell_toBeRemoved_item= + &scell_toBeRemoved_item_ies->value.choice.SCell_ToBeRemoved_Item; + /* - sCell_ID */ + addnRCGI(scell_toBeRemoved_item->sCell_ID, &hardCoded); + } } /* mandatory */ /* c11. SRBs_ToBeSetupMod_List */ if(f1ap_ue_context_modification_req->srbs_to_be_setup_length > 0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie11); - ie11->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_List; - ie11->criticality = F1AP_Criticality_reject; - ie11->value.present = F1AP_UEContextModificationRequestIEs__value_PR_SRBs_ToBeSetupMod_List; + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie11); + ie11->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_List; + ie11->criticality = F1AP_Criticality_reject; + ie11->value.present = F1AP_UEContextModificationRequestIEs__value_PR_SRBs_ToBeSetupMod_List; - for (int i=0; isrbs_to_be_setup_length; i++) { - // - asn1cSequenceAdd(ie11->value.choice.SRBs_ToBeSetupMod_List, F1AP_SRBs_ToBeSetupMod_ItemIEs_t, srbs_toBeSetupMod_item_ies); - srbs_toBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_Item; // 73 - srbs_toBeSetupMod_item_ies->criticality = F1AP_Criticality_reject; - srbs_toBeSetupMod_item_ies->value.present = F1AP_SRBs_ToBeSetupMod_ItemIEs__value_PR_SRBs_ToBeSetupMod_Item; - /* 11.1 SRBs_ToBeSetup_Item */ - F1AP_SRBs_ToBeSetupMod_Item_t *srbs_toBeSetupMod_item=&srbs_toBeSetupMod_item_ies->value.choice.SRBs_ToBeSetupMod_Item; - /* 11.1.1 sRBID */ - srbs_toBeSetupMod_item->sRBID = f1ap_ue_context_modification_req->srbs_to_be_setup[i].srb_id; - /* OPTIONAL */ - /* 11.1.2 duplicationIndication */ - //if (0) { - asn1cCallocOne(srbs_toBeSetupMod_item->duplicationIndication, + for (int i=0; isrbs_to_be_setup_length; i++) { + // + asn1cSequenceAdd(ie11->value.choice.SRBs_ToBeSetupMod_List, F1AP_SRBs_ToBeSetupMod_ItemIEs_t, srbs_toBeSetupMod_item_ies); + srbs_toBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_Item; // 73 + srbs_toBeSetupMod_item_ies->criticality = F1AP_Criticality_reject; + srbs_toBeSetupMod_item_ies->value.present = F1AP_SRBs_ToBeSetupMod_ItemIEs__value_PR_SRBs_ToBeSetupMod_Item; + /* 11.1 SRBs_ToBeSetup_Item */ + F1AP_SRBs_ToBeSetupMod_Item_t *srbs_toBeSetupMod_item=&srbs_toBeSetupMod_item_ies->value.choice.SRBs_ToBeSetupMod_Item; + /* 11.1.1 sRBID */ + srbs_toBeSetupMod_item->sRBID = f1ap_ue_context_modification_req->srbs_to_be_setup[i].srb_id; + /* OPTIONAL */ + /* 11.1.2 duplicationIndication */ + //if (0) { + asn1cCallocOne(srbs_toBeSetupMod_item->duplicationIndication, F1AP_DuplicationIndication_true); // enum - //} - } + //} + } } /* mandatory */ /* c12. DRBs_ToBeSetupMod_List */ if(f1ap_ue_context_modification_req->drbs_to_be_setup_length){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie12); - ie12->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_List; - ie12->criticality = F1AP_Criticality_reject; - ie12->value.present = F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeSetupMod_List; + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie12); + ie12->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_List; + ie12->criticality = F1AP_Criticality_reject; + ie12->value.present = F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeSetupMod_List; - for (int i = 0; i < f1ap_ue_context_modification_req->drbs_to_be_setup_length; i++) { - asn1cSequenceAdd(ie12->value.choice.DRBs_ToBeSetupMod_List.list, + for (int i = 0; i < f1ap_ue_context_modification_req->drbs_to_be_setup_length; i++) { + asn1cSequenceAdd(ie12->value.choice.DRBs_ToBeSetupMod_List.list, F1AP_DRBs_ToBeSetupMod_ItemIEs_t, drbs_toBeSetupMod_item_ies); - drbs_toBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_Item; - drbs_toBeSetupMod_item_ies->criticality = F1AP_Criticality_reject; - drbs_toBeSetupMod_item_ies->value.present = F1AP_DRBs_ToBeSetupMod_ItemIEs__value_PR_DRBs_ToBeSetupMod_Item; - /* 12.1 DRBs_ToBeSetupMod_Item */ - F1AP_DRBs_ToBeSetupMod_Item_t *drbs_toBeSetupMod_item= - &drbs_toBeSetupMod_item_ies->value.choice.DRBs_ToBeSetupMod_Item; - /* dRBID */ - drbs_toBeSetupMod_item->dRBID = f1ap_ue_context_modification_req->drbs_to_be_setup[i].drb_id; - /* qoSInformation */ + drbs_toBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_Item; + drbs_toBeSetupMod_item_ies->criticality = F1AP_Criticality_reject; + drbs_toBeSetupMod_item_ies->value.present = F1AP_DRBs_ToBeSetupMod_ItemIEs__value_PR_DRBs_ToBeSetupMod_Item; + /* 12.1 DRBs_ToBeSetupMod_Item */ + F1AP_DRBs_ToBeSetupMod_Item_t *drbs_toBeSetupMod_item= + &drbs_toBeSetupMod_item_ies->value.choice.DRBs_ToBeSetupMod_Item; + /* dRBID */ + drbs_toBeSetupMod_item->dRBID = f1ap_ue_context_modification_req->drbs_to_be_setup[i].drb_id; + /* qoSInformation */ - if(f1ap_ue_context_modification_req->QoS_information_type == EUTRAN_QoS){ - drbs_toBeSetupMod_item->qoSInformation.present = F1AP_QoSInformation_PR_eUTRANQoS; - drbs_toBeSetupMod_item->qoSInformation.choice.eUTRANQoS = (F1AP_EUTRANQoS_t *)calloc(1, sizeof(F1AP_EUTRANQoS_t)); - drbs_toBeSetupMod_item->qoSInformation.choice.eUTRANQoS->qCI = 253L; - /* uLUPTNLInformation_ToBeSetup_List */ - int maxnoofULTunnels = 1; // 2; + if(f1ap_ue_context_modification_req->QoS_information_type == EUTRAN_QoS){ + drbs_toBeSetupMod_item->qoSInformation.present = F1AP_QoSInformation_PR_eUTRANQoS; + drbs_toBeSetupMod_item->qoSInformation.choice.eUTRANQoS = (F1AP_EUTRANQoS_t *)calloc(1, sizeof(F1AP_EUTRANQoS_t)); + drbs_toBeSetupMod_item->qoSInformation.choice.eUTRANQoS->qCI = 253L; + /* uLUPTNLInformation_ToBeSetup_List */ + int maxnoofULTunnels = 1; // 2; - for (int j=0; juLUPTNLInformation_ToBeSetup_List.list, + for (int j=0; juLUPTNLInformation_ToBeSetup_List.list, F1AP_ULUPTNLInformation_ToBeSetup_Item_t, uLUPTNLInformation_ToBeSetup_Item); - uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; - asn1cCalloc(uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.choice.gTPTunnel, + uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; + asn1cCalloc(uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.choice.gTPTunnel, gTPTunnel) - /* transportLayerAddress */ - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(1234, &gTPTunnel->transportLayerAddress); - /* gTP_TEID */ - OCTET_STRING_fromBuf(&gTPTunnel->gTP_TEID, "4567", + /* transportLayerAddress */ + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(1234, &gTPTunnel->transportLayerAddress); + /* gTP_TEID */ + OCTET_STRING_fromBuf(&gTPTunnel->gTP_TEID, "4567", strlen("4567")); - } - - /* rLCMode */ - drbs_toBeSetupMod_item->rLCMode = F1AP_RLCMode_rlc_um_bidirectional; // enum - - /* OPTIONAL */ - /* ULConfiguration */ - if (0) { - drbs_toBeSetupMod_item->uLConfiguration = (F1AP_ULConfiguration_t *)calloc(1, sizeof(F1AP_ULConfiguration_t)); - } - } //QoS information - - else{ - /* 12.1.2 DRB_Information */ - drbs_toBeSetupMod_item->qoSInformation.present = F1AP_QoSInformation_PR_choice_extension; - F1AP_QoSInformation_ExtIEs_t *ie = (F1AP_QoSInformation_ExtIEs_t *)calloc(1, sizeof(*ie)); - ie->id = F1AP_ProtocolIE_ID_id_DRB_Information; - ie->criticality = F1AP_Criticality_reject; - ie->value.present = F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information; - F1AP_DRB_Information_t *DRB_Information = &ie->value.choice.DRB_Information; - drbs_toBeSetupMod_item->qoSInformation.choice.choice_extension = (struct F1AP_ProtocolIE_SingleContainer *)ie; - /* 12.1.2.1 dRB_QoS */ - { - /* qoS_Characteristics */ - { - int some_decide_qoS_characteristics = 0; // BK: Need Check - - if (some_decide_qoS_characteristics) { - DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI; - setQos(DRB_Information->dRB_QoS.qoS_Characteristics.choice.non_Dynamic_5QI); - } else { - DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_dynamic_5QI; - asn1cCalloc(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI, tmp); - /* qoSPriorityLevel */ - tmp->qoSPriorityLevel = 1L; - /* packetDelayBudget */ - tmp->packetDelayBudget = 1L; - /* packetErrorRate */ - tmp->packetErrorRate.pER_Scalar = 1L; - tmp->packetErrorRate.pER_Exponent = 6L; - - /* OPTIONAL */ - /* delayCritical */ - if (0) { - asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->delayCritical, 1L); - } - - /* OPTIONAL */ - /* averagingWindow */ - if (0) { - asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->averagingWindow, 1L); - } - - /* OPTIONAL */ - /* maxDataBurstVolume */ - if (0) { - asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->maxDataBurstVolume, 1L); - } - } // if some_decide_qoS_characteristics - - } // qoS_Characteristics - /* nGRANallocationRetentionPriority */ - { - DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum - DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_shall_not_trigger_pre_emption; // enum - DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum - } // nGRANallocationRetentionPriority - - /* OPTIONAL */ - /* gBR_QoS_Flow_Information */ - if (0) { - asn1cCalloc(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information, tmp); - asn_long2INTEGER(&tmp->maxFlowBitRateDownlink, 1L); - asn_long2INTEGER(&tmp->maxFlowBitRateUplink, 1L); - asn_long2INTEGER(&tmp->guaranteedFlowBitRateDownlink, 1L); - asn_long2INTEGER(&tmp->guaranteedFlowBitRateUplink, 1L); - - /* OPTIONAL */ - /* maxPacketLossRateDownlink */ - if (0) { - asn1cCallocOne(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information->maxPacketLossRateDownlink, 1L); } + /* rLCMode */ + drbs_toBeSetupMod_item->rLCMode = F1AP_RLCMode_rlc_um_bidirectional; // enum + /* OPTIONAL */ - /* maxPacketLossRateUplink */ + /* ULConfiguration */ if (0) { - asn1cCallocOne(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information->maxPacketLossRateUplink, 1L); + drbs_toBeSetupMod_item->uLConfiguration = (F1AP_ULConfiguration_t *)calloc(1, sizeof(F1AP_ULConfiguration_t)); } - } + } //QoS information - /* OPTIONAL */ - /* reflective_QoS_Attribute */ - if (0) { - asn1cCallocOne(DRB_Information->dRB_QoS.reflective_QoS_Attribute, 1L); - } - } // dRB_QoS - /* 12.1.2.2 sNSSAI */ - { - /* sST */ - - OCTET_STRING_fromBuf(&DRB_Information->sNSSAI.sST, "1", 1); - - /* OPTIONAL */ - /* sD */ - if (0) { - asn1cCalloc(DRB_Information->sNSSAI.sD, tmp); - OCTET_STRING_fromBuf(tmp, "asdsa1d32sa1d31asd31as", - strlen("asdsa1d32sa1d31asd31as")); - } - } - - /* OPTIONAL */ - /* 12.1.2.3 notificationControl */ - if (0) { - asn1cCallocOne(DRB_Information->notificationControl, - F1AP_NotificationControl_active); // enum - } - - /* 12.1.2.4 flows_Mapped_To_DRB_List */ // BK: need verifiy - - for (int k = 0; k < 1; k ++) { - asn1cSequenceAdd(DRB_Information->flows_Mapped_To_DRB_List.list, - F1AP_Flows_Mapped_To_DRB_Item_t, flows_mapped_to_drb_item); - /* qoSFlowIndicator */ - flows_mapped_to_drb_item->qoSFlowIdentifier = 1L; - /* qoSFlowLevelQoSParameters */ - { - /* qoS_Characteristics */ + else{ + /* 12.1.2 DRB_Information */ + drbs_toBeSetupMod_item->qoSInformation.present = F1AP_QoSInformation_PR_choice_extension; + F1AP_QoSInformation_ExtIEs_t *ie = (F1AP_QoSInformation_ExtIEs_t *)calloc(1, sizeof(*ie)); + ie->id = F1AP_ProtocolIE_ID_id_DRB_Information; + ie->criticality = F1AP_Criticality_reject; + ie->value.present = F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information; + F1AP_DRB_Information_t *DRB_Information = &ie->value.choice.DRB_Information; + drbs_toBeSetupMod_item->qoSInformation.choice.choice_extension = (struct F1AP_ProtocolIE_SingleContainer *)ie; + /* 12.1.2.1 dRB_QoS */ { - int some_decide_qoS_characteristics = 0; // BK: Need Check - F1AP_QoS_Characteristics_t *QosParams=&flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.qoS_Characteristics; + /* qoS_Characteristics */ + { + int some_decide_qoS_characteristics = 0; // BK: Need Check - if (some_decide_qoS_characteristics) { - QosParams->present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI; - setQos(QosParams->choice.non_Dynamic_5QI); - } else { - QosParams->present = F1AP_QoS_Characteristics_PR_dynamic_5QI; - asn1cCalloc(QosParams->choice.dynamic_5QI, tmp); - /* qoSPriorityLevel */ - tmp->qoSPriorityLevel = 1L; - /* packetDelayBudget */ - tmp->packetDelayBudget = 1L; - /* packetErrorRate */ - tmp->packetErrorRate.pER_Scalar = 1L; - tmp->packetErrorRate.pER_Exponent = 6L; + if (some_decide_qoS_characteristics) { + DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI; + setQos(DRB_Information->dRB_QoS.qoS_Characteristics.choice.non_Dynamic_5QI); + } else { + DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_dynamic_5QI; + asn1cCalloc(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI, tmp); + /* qoSPriorityLevel */ + tmp->qoSPriorityLevel = 1L; + /* packetDelayBudget */ + tmp->packetDelayBudget = 1L; + /* packetErrorRate */ + tmp->packetErrorRate.pER_Scalar = 1L; + tmp->packetErrorRate.pER_Exponent = 6L; - /* OPTIONAL */ - /* delayCritical */ - if (0) { - asn1cCalloc(QosParams->choice.dynamic_5QI->delayCritical, tmp); - *tmp = 1L; - } + /* OPTIONAL */ + /* delayCritical */ + if (0) { + asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->delayCritical, 1L); + } - /* OPTIONAL */ - /* averagingWindow */ - if (0) { - asn1cCalloc(QosParams->choice.dynamic_5QI->averagingWindow, tmp); - *tmp = 1L; - } + /* OPTIONAL */ + /* averagingWindow */ + if (0) { + asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->averagingWindow, 1L); + } - /* OPTIONAL */ - /* maxDataBurstVolume */ - if (0) { - asn1cCalloc(QosParams->choice.dynamic_5QI->maxDataBurstVolume, tmp); - *tmp= 1L; - } - } // if some_decide_qoS_characteristics + /* OPTIONAL */ + /* maxDataBurstVolume */ + if (0) { + asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->maxDataBurstVolume, 1L); + } + } // if some_decide_qoS_characteristics - } // qoS_Characteristics - /* nGRANallocationRetentionPriority */ - { - flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum - flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_shall_not_trigger_pre_emption; // enum - flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum - } // nGRANallocationRetentionPriority + } // qoS_Characteristics + /* nGRANallocationRetentionPriority */ + { + DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum + DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_shall_not_trigger_pre_emption; // enum + DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum + } // nGRANallocationRetentionPriority - /* OPTIONAL */ - /* gBR_QoS_Flow_Information */ - if (0) { - asn1cCalloc(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information, tmp); - asn_long2INTEGER(&tmp->maxFlowBitRateDownlink, 1L); - asn_long2INTEGER(&tmp->maxFlowBitRateUplink, 1L); - asn_long2INTEGER(&tmp->guaranteedFlowBitRateDownlink, 1L); - asn_long2INTEGER(&tmp->guaranteedFlowBitRateUplink, 1L); + /* OPTIONAL */ + /* gBR_QoS_Flow_Information */ + if (0) { + asn1cCalloc(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information, tmp); + asn_long2INTEGER(&tmp->maxFlowBitRateDownlink, 1L); + asn_long2INTEGER(&tmp->maxFlowBitRateUplink, 1L); + asn_long2INTEGER(&tmp->guaranteedFlowBitRateDownlink, 1L); + asn_long2INTEGER(&tmp->guaranteedFlowBitRateUplink, 1L); /* OPTIONAL */ /* maxPacketLossRateDownlink */ if (0) { - asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information->maxPacketLossRateDownlink, 1L); + asn1cCallocOne(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information->maxPacketLossRateDownlink, 1L); } /* OPTIONAL */ /* maxPacketLossRateUplink */ if (0) { - asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information->maxPacketLossRateUplink, 1L); + asn1cCallocOne(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information->maxPacketLossRateUplink, 1L); } } /* OPTIONAL */ /* reflective_QoS_Attribute */ if (0) { - asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.reflective_QoS_Attribute, 1L); + asn1cCallocOne(DRB_Information->dRB_QoS.reflective_QoS_Attribute, 1L); } - } // qoSFlowLevelQoSParameters - } + } // dRB_QoS + /* 12.1.2.2 sNSSAI */ + { + /* sST */ - } //QoS information + OCTET_STRING_fromBuf(&DRB_Information->sNSSAI.sST, "1", 1); - /* 12.1.3 uLUPTNLInformation_ToBeSetup_List */ - for (int j = 0; j < f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl_length; j++) { - /*Use a dummy teid for the outgoing GTP-U tunnel (DU) which will be updated once we get the UE context setup response from the DU*/ - transport_layer_addr_t addr; - int sz=sizeof(f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_dl_tnl[0].tl_address); - memcpy(addr.buffer,&f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_dl_tnl[0].tl_address, sz); - addr.length = sz*8; + /* OPTIONAL */ + /* sD */ + if (0) { + asn1cCalloc(DRB_Information->sNSSAI.sD, tmp); + OCTET_STRING_fromBuf(tmp, "asdsa1d32sa1d31asd31as", + strlen("asdsa1d32sa1d31asd31as")); + } + } - f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl[j].teid= - newGtpuCreateTunnel(getCxt(CUtype, instance)->gtpInst, + /* OPTIONAL */ + /* 12.1.2.3 notificationControl */ + if (0) { + asn1cCallocOne(DRB_Information->notificationControl, + F1AP_NotificationControl_active); // enum + } + + /* 12.1.2.4 flows_Mapped_To_DRB_List */ // BK: need verifiy + + for (int k = 0; k < 1; k ++) { + asn1cSequenceAdd(DRB_Information->flows_Mapped_To_DRB_List.list, + F1AP_Flows_Mapped_To_DRB_Item_t, flows_mapped_to_drb_item); + /* qoSFlowIndicator */ + flows_mapped_to_drb_item->qoSFlowIdentifier = 1L; + /* qoSFlowLevelQoSParameters */ + { + /* qoS_Characteristics */ + { + int some_decide_qoS_characteristics = 0; // BK: Need Check + F1AP_QoS_Characteristics_t *QosParams=&flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.qoS_Characteristics; + + if (some_decide_qoS_characteristics) { + QosParams->present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI; + setQos(QosParams->choice.non_Dynamic_5QI); + } else { + QosParams->present = F1AP_QoS_Characteristics_PR_dynamic_5QI; + asn1cCalloc(QosParams->choice.dynamic_5QI, tmp); + /* qoSPriorityLevel */ + tmp->qoSPriorityLevel = 1L; + /* packetDelayBudget */ + tmp->packetDelayBudget = 1L; + /* packetErrorRate */ + tmp->packetErrorRate.pER_Scalar = 1L; + tmp->packetErrorRate.pER_Exponent = 6L; + + /* OPTIONAL */ + /* delayCritical */ + if (0) { + asn1cCalloc(QosParams->choice.dynamic_5QI->delayCritical, tmp); + *tmp = 1L; + } + + /* OPTIONAL */ + /* averagingWindow */ + if (0) { + asn1cCalloc(QosParams->choice.dynamic_5QI->averagingWindow, tmp); + *tmp = 1L; + } + + /* OPTIONAL */ + /* maxDataBurstVolume */ + if (0) { + asn1cCalloc(QosParams->choice.dynamic_5QI->maxDataBurstVolume, tmp); + *tmp= 1L; + } + } // if some_decide_qoS_characteristics + + } // qoS_Characteristics + /* nGRANallocationRetentionPriority */ + { + flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum + flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_shall_not_trigger_pre_emption; // enum + flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum + } // nGRANallocationRetentionPriority + + /* OPTIONAL */ + /* gBR_QoS_Flow_Information */ + if (0) { + asn1cCalloc(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information, tmp); + asn_long2INTEGER(&tmp->maxFlowBitRateDownlink, 1L); + asn_long2INTEGER(&tmp->maxFlowBitRateUplink, 1L); + asn_long2INTEGER(&tmp->guaranteedFlowBitRateDownlink, 1L); + asn_long2INTEGER(&tmp->guaranteedFlowBitRateUplink, 1L); + + /* OPTIONAL */ + /* maxPacketLossRateDownlink */ + if (0) { + asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information->maxPacketLossRateDownlink, 1L); + } + + /* OPTIONAL */ + /* maxPacketLossRateUplink */ + if (0) { + asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information->maxPacketLossRateUplink, 1L); + } + } + + /* OPTIONAL */ + /* reflective_QoS_Attribute */ + if (0) { + asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.reflective_QoS_Attribute, 1L); + } + } // qoSFlowLevelQoSParameters + } + + } //QoS information + + /* 12.1.3 uLUPTNLInformation_ToBeSetup_List */ + for (int j = 0; j < f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl_length; j++) { + /*Use a dummy teid for the outgoing GTP-U tunnel (DU) which will be updated once we get the UE context setup response from the DU*/ + transport_layer_addr_t addr; + int sz=sizeof(f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_dl_tnl[0].tl_address); + memcpy(addr.buffer,&f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_dl_tnl[0].tl_address, sz); + addr.length = sz*8; + + f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl[j].teid= + newGtpuCreateTunnel(getCxt(CUtype, instance)->gtpInst, f1ap_ue_context_modification_req->rnti, f1ap_ue_context_modification_req->drbs_to_be_setup[i].drb_id, f1ap_ue_context_modification_req->drbs_to_be_setup[i].drb_id, @@ -1499,138 +1499,138 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, f1ap_ue_context addr, f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_dl_tnl[0].port, cu_f1u_data_req); - /* 12.3.1 ULTunnels_ToBeSetup_Item */ - asn1cSequenceAdd(drbs_toBeSetupMod_item->uLUPTNLInformation_ToBeSetup_List.list, + /* 12.3.1 ULTunnels_ToBeSetup_Item */ + asn1cSequenceAdd(drbs_toBeSetupMod_item->uLUPTNLInformation_ToBeSetup_List.list, F1AP_ULUPTNLInformation_ToBeSetup_Item_t, uLUPTNLInformation_ToBeSetup_Item); - uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; - asn1cCalloc( uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.choice.gTPTunnel, + uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; + asn1cCalloc( uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.choice.gTPTunnel, gTPTunnel); - /* 12.3.1.1.1 transportLayerAddress */ - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl[j].tl_address, + /* 12.3.1.1.1 transportLayerAddress */ + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl[j].tl_address, &gTPTunnel->transportLayerAddress); - /* 12.3.1.1.2 gTP_TEID */ - INT32_TO_OCTET_STRING(f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl[j].teid, + /* 12.3.1.1.2 gTP_TEID */ + INT32_TO_OCTET_STRING(f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl[j].teid, &gTPTunnel->gTP_TEID); - } - /* 12.1.4 rLCMode */ - /* TODO use rlc_mode from f1ap_drb_to_be_setup */ - switch (f1ap_ue_context_modification_req->drbs_to_be_setup[i].rlc_mode) { - case RLC_MODE_AM: - drbs_toBeSetupMod_item->rLCMode = F1AP_RLCMode_rlc_am; - break; + } + /* 12.1.4 rLCMode */ + /* TODO use rlc_mode from f1ap_drb_to_be_setup */ + switch (f1ap_ue_context_modification_req->drbs_to_be_setup[i].rlc_mode) { + case RLC_MODE_AM: + drbs_toBeSetupMod_item->rLCMode = F1AP_RLCMode_rlc_am; + break; - default: - drbs_toBeSetupMod_item->rLCMode = F1AP_RLCMode_rlc_um_bidirectional; - } + default: + drbs_toBeSetupMod_item->rLCMode = F1AP_RLCMode_rlc_um_bidirectional; + } - /* OPTIONAL */ - /* 12.1.5 ULConfiguration */ - if (0) { - asn1cCalloc(drbs_toBeSetupMod_item->uLConfiguration, tmp); - tmp->uLUEConfiguration = F1AP_ULUEConfiguration_no_data; - } + /* OPTIONAL */ + /* 12.1.5 ULConfiguration */ + if (0) { + asn1cCalloc(drbs_toBeSetupMod_item->uLConfiguration, tmp); + tmp->uLUEConfiguration = F1AP_ULUEConfiguration_no_data; + } - /* OPTIONAL */ - /* 12.1.6 duplicationActivation */ - if (0) { - asn1cCalloc(drbs_toBeSetupMod_item->duplicationActivation, tmp); - *tmp = F1AP_DuplicationActivation_active; // enum + /* OPTIONAL */ + /* 12.1.6 duplicationActivation */ + if (0) { + asn1cCalloc(drbs_toBeSetupMod_item->duplicationActivation, tmp); + *tmp = F1AP_DuplicationActivation_active; // enum + } } } - } /* optional */ if(0){ - /* c13. DRBs_ToBeModified_List */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie13); - ie13->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeModified_List; - ie13->criticality = F1AP_Criticality_reject; - ie13->value.present = F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeModified_List; + /* c13. DRBs_ToBeModified_List */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie13); + ie13->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeModified_List; + ie13->criticality = F1AP_Criticality_reject; + ie13->value.present = F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeModified_List; - for (int i=0; i<1; i++) { - // - asn1cSequenceAdd( ie13->value.choice.DRBs_ToBeModified_List.list, + for (int i=0; i<1; i++) { + // + asn1cSequenceAdd( ie13->value.choice.DRBs_ToBeModified_List.list, F1AP_DRBs_ToBeModified_ItemIEs_t, drbs_toBeModified_item_ies); - drbs_toBeModified_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeModified_Item; - drbs_toBeModified_item_ies->criticality = F1AP_Criticality_reject; - drbs_toBeModified_item_ies->value.present = F1AP_DRBs_ToBeModified_ItemIEs__value_PR_DRBs_ToBeModified_Item; - /* 13.1 SRBs_ToBeModified_Item */ - F1AP_DRBs_ToBeModified_Item_t *drbs_toBeModified_item= - &drbs_toBeModified_item_ies->value.choice.DRBs_ToBeModified_Item; - /* dRBID */ - drbs_toBeModified_item->dRBID = 30L; - /* qoSInformation */ - asn1cCalloc(drbs_toBeModified_item->qoSInformation, tmp); - tmp->present = F1AP_QoSInformation_PR_eUTRANQoS; - tmp->choice.eUTRANQoS = (F1AP_EUTRANQoS_t *)calloc(1, sizeof(F1AP_EUTRANQoS_t)); - tmp->choice.eUTRANQoS->qCI = 254L; - /* ULTunnels_ToBeModified_List */ - int maxnoofULTunnels = 1; // 2; + drbs_toBeModified_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeModified_Item; + drbs_toBeModified_item_ies->criticality = F1AP_Criticality_reject; + drbs_toBeModified_item_ies->value.present = F1AP_DRBs_ToBeModified_ItemIEs__value_PR_DRBs_ToBeModified_Item; + /* 13.1 SRBs_ToBeModified_Item */ + F1AP_DRBs_ToBeModified_Item_t *drbs_toBeModified_item= + &drbs_toBeModified_item_ies->value.choice.DRBs_ToBeModified_Item; + /* dRBID */ + drbs_toBeModified_item->dRBID = 30L; + /* qoSInformation */ + asn1cCalloc(drbs_toBeModified_item->qoSInformation, tmp); + tmp->present = F1AP_QoSInformation_PR_eUTRANQoS; + tmp->choice.eUTRANQoS = (F1AP_EUTRANQoS_t *)calloc(1, sizeof(F1AP_EUTRANQoS_t)); + tmp->choice.eUTRANQoS->qCI = 254L; + /* ULTunnels_ToBeModified_List */ + int maxnoofULTunnels = 1; // 2; - for (int j=0; juLUPTNLInformation_ToBeSetup_List.list, + for (int j=0; juLUPTNLInformation_ToBeSetup_List.list, F1AP_ULUPTNLInformation_ToBeSetup_Item_t, uLUPTNLInformation_ToBeSetup_Item); - uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; - asn1cCalloc(uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.choice.gTPTunnel, + uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; + asn1cCalloc(uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.choice.gTPTunnel, gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(1234, &gTPTunnel->transportLayerAddress); - OCTET_STRING_fromBuf(&gTPTunnel->gTP_TEID, "1204", + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(1234, &gTPTunnel->transportLayerAddress); + OCTET_STRING_fromBuf(&gTPTunnel->gTP_TEID, "1204", strlen("1204")); - } + } - /* OPTIONAL */ - /* ULConfiguration */ - if (0) { - drbs_toBeModified_item->uLConfiguration = (F1AP_ULConfiguration_t *)calloc(1, sizeof(F1AP_ULConfiguration_t)); + /* OPTIONAL */ + /* ULConfiguration */ + if (0) { + drbs_toBeModified_item->uLConfiguration = (F1AP_ULConfiguration_t *)calloc(1, sizeof(F1AP_ULConfiguration_t)); + } } } - } /* optional */ if(0){ - /* c14. SRBs_ToBeReleased_List */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie14); - ie14->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeReleased_List; - ie14->criticality = F1AP_Criticality_reject; - ie14->value.present = F1AP_UEContextModificationRequestIEs__value_PR_SRBs_ToBeReleased_List; + /* c14. SRBs_ToBeReleased_List */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie14); + ie14->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeReleased_List; + ie14->criticality = F1AP_Criticality_reject; + ie14->value.present = F1AP_UEContextModificationRequestIEs__value_PR_SRBs_ToBeReleased_List; - for (int i=0; i<1; i++) { - // - asn1cSequenceAdd(ie14->value.choice.SRBs_ToBeReleased_List.list, + for (int i=0; i<1; i++) { + // + asn1cSequenceAdd(ie14->value.choice.SRBs_ToBeReleased_List.list, F1AP_SRBs_ToBeReleased_ItemIEs_t, srbs_toBeReleased_item_ies); - srbs_toBeReleased_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeReleased_Item; - srbs_toBeReleased_item_ies->criticality = F1AP_Criticality_ignore; - srbs_toBeReleased_item_ies->value.present = F1AP_SRBs_ToBeReleased_ItemIEs__value_PR_SRBs_ToBeReleased_Item; - /* 9.1 SRBs_ToBeReleased_Item */ - F1AP_SRBs_ToBeReleased_Item_t *srbs_toBeReleased_item= - &srbs_toBeReleased_item_ies->value.choice.SRBs_ToBeReleased_Item; - /* - sRBID */ - srbs_toBeReleased_item->sRBID = 2L; - } + srbs_toBeReleased_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeReleased_Item; + srbs_toBeReleased_item_ies->criticality = F1AP_Criticality_ignore; + srbs_toBeReleased_item_ies->value.present = F1AP_SRBs_ToBeReleased_ItemIEs__value_PR_SRBs_ToBeReleased_Item; + /* 9.1 SRBs_ToBeReleased_Item */ + F1AP_SRBs_ToBeReleased_Item_t *srbs_toBeReleased_item= + &srbs_toBeReleased_item_ies->value.choice.SRBs_ToBeReleased_Item; + /* - sRBID */ + srbs_toBeReleased_item->sRBID = 2L; + } } /* optional */ if(0){ - /* c15. DRBs_ToBeReleased_List */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie15); - ie15->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_List; - ie15->criticality = F1AP_Criticality_reject; - ie15->value.present = F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeReleased_List; + /* c15. DRBs_ToBeReleased_List */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie15); + ie15->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_List; + ie15->criticality = F1AP_Criticality_reject; + ie15->value.present = F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeReleased_List; - for (int i=0; i<1; i++) { - // - asn1cSequenceAdd(ie15->value.choice.DRBs_ToBeReleased_List.list, + for (int i=0; i<1; i++) { + // + asn1cSequenceAdd(ie15->value.choice.DRBs_ToBeReleased_List.list, F1AP_DRBs_ToBeReleased_ItemIEs_t, drbs_toBeReleased_item_ies); - drbs_toBeReleased_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_Item; - drbs_toBeReleased_item_ies->criticality = F1AP_Criticality_reject; - drbs_toBeReleased_item_ies->value.present = F1AP_DRBs_ToBeReleased_ItemIEs__value_PR_DRBs_ToBeReleased_Item; - /* 14.1 SRBs_ToBeReleased_Item */ - F1AP_DRBs_ToBeReleased_Item_t *drbs_toBeReleased_item= - &drbs_toBeReleased_item_ies->value.choice.DRBs_ToBeReleased_Item; - /* dRBID */ - drbs_toBeReleased_item->dRBID = 30L; - } + drbs_toBeReleased_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_Item; + drbs_toBeReleased_item_ies->criticality = F1AP_Criticality_reject; + drbs_toBeReleased_item_ies->value.present = F1AP_DRBs_ToBeReleased_ItemIEs__value_PR_DRBs_ToBeReleased_Item; + /* 14.1 SRBs_ToBeReleased_Item */ + F1AP_DRBs_ToBeReleased_Item_t *drbs_toBeReleased_item= + &drbs_toBeReleased_item_ies->value.choice.DRBs_ToBeReleased_Item; + /* dRBID */ + drbs_toBeReleased_item->dRBID = 30L; + } } /* encode */ diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index f779637d7e..cbbe563285 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -907,8 +907,157 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, uint32_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { - AssertFatal(1==0,"Not implemented yet\n"); + + MessageDef *msg_p; // message to RRC + F1AP_UEContextModificationRequest_t *container; + int i; + DevAssert(pdu); + msg_p = itti_alloc_new_message(TASK_DU_F1, 0, F1AP_UE_CONTEXT_MODIFICATION_REQ); + f1ap_ue_context_setup_t *f1ap_ue_context_modification_req = &F1AP_UE_CONTEXT_MODIFICATION_REQ(msg_p); + container = &pdu->choice.initiatingMessage->value.choice.UEContextModificationRequest; + + /* mandatory */ + /* GNB_CU_UE_F1AP_ID */ + F1AP_UEContextModificationRequestIEs_t *ieCU; + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, ieCU, container, + F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); + f1ap_ue_context_modification_req->gNB_CU_ue_id = ieCU->value.choice.GNB_CU_UE_F1AP_ID; + + /* mandatory */ + /* GNB_DU_UE_F1AP_ID */ + F1AP_UEContextSetupRequestIEs_t *ieDU_UE; + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupRequestIEs_t, ieDU_UE, container, + F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); + f1ap_ue_context_modification_req->gNB_DU_ue_id = ieDU_UE->value.choice.GNB_DU_UE_F1AP_ID; + f1ap_ue_context_modification_req->rnti = f1ap_get_rnti_by_du_id(DUtype, instance, f1ap_ue_context_modification_req->gNB_DU_ue_id); + + if(f1ap_ue_context_modification_req->rnti<0) + LOG_E(F1AP, "Could not retrieve UE rnti based on the DU UE id \n"); + else + LOG_I(F1AP, "Retrieved rnti is: %d \n", f1ap_ue_context_modification_req->rnti); + + /* SRB */ + F1AP_UEContextModificationRequestIEs_t *ieSrb; + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, ieSrb, container, + F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_List, false); + + if(ieSrb != NULL) { + f1ap_ue_context_modification_req->srbs_to_be_setup_length = ieSrb->value.choice.SRBs_ToBeSetupMod_List.list.count; + f1ap_ue_context_modification_req->srbs_to_be_setup = calloc(f1ap_ue_context_modification_req->srbs_to_be_setup_length, + sizeof(f1ap_srb_to_be_setup_t)); + AssertFatal(f1ap_ue_context_modification_req->srbs_to_be_setup, + "could not allocate memory for f1ap_ue_context_setup_req->srbs_to_be_setup\n"); + + for (i = 0; i < f1ap_ue_context_modification_req->srbs_to_be_setup_length; ++i) { + f1ap_srb_to_be_setup_t *srb_p = &f1ap_ue_context_modification_req->srbs_to_be_setup[i]; + F1AP_SRBs_ToBeSetupMod_Item_t *srbs_tobesetupmod_item_p; + srbs_tobesetupmod_item_p = &((F1AP_SRBs_ToBeSetupMod_ItemIEs_t *)ieSrb->value.choice.SRBs_ToBeSetupMod_List.list.array[i])->value.choice.SRBs_ToBeSetupMod_Item; + srb_p->srb_id = srbs_tobesetupmod_item_p->sRBID; + } + } + + /* DRB */ + F1AP_UEContextModificationRequestIEs_t *ieDrb; + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, ieDrb, container, + F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_List, false); + + if(ieDrb!=NULL) { + f1ap_ue_context_modification_req->drbs_to_be_setup_length = ieDrb->value.choice.DRBs_ToBeSetupMod_List.list.count; + f1ap_ue_context_modification_req->drbs_to_be_setup = calloc(f1ap_ue_context_modification_req->drbs_to_be_setup_length, + sizeof(f1ap_drb_to_be_setup_t)); + AssertFatal(f1ap_ue_context_modification_req->drbs_to_be_setup, + "could not allocate memory for f1ap_ue_context_setup_req->drbs_to_be_setup\n"); + + for (i = 0; i < f1ap_ue_context_modification_req->drbs_to_be_setup_length; ++i) { + f1ap_drb_to_be_setup_t *drb_p = &f1ap_ue_context_modification_req->drbs_to_be_setup[i]; + F1AP_DRBs_ToBeSetup_Item_t *drbs_tobesetup_item_p = + &((F1AP_DRBs_ToBeSetup_ItemIEs_t *)ieDrb->value.choice.DRBs_ToBeSetupMod_List.list.array[i])->value.choice.DRBs_ToBeSetup_Item; + drb_p->drb_id = drbs_tobesetup_item_p->dRBID; + /* TODO in the following, assume only one UP UL TNL is present. + * this matches/assumes OAI CU implementation, can be up to 2! */ + drb_p->up_ul_tnl_length = 1; + AssertFatal(drbs_tobesetup_item_p->uLUPTNLInformation_ToBeSetup_List.list.count > 0, + "no UL UP TNL Information in DRBs to be Setup list\n"); + F1AP_ULUPTNLInformation_ToBeSetup_Item_t *ul_up_tnl_info_p = (F1AP_ULUPTNLInformation_ToBeSetup_Item_t *)drbs_tobesetup_item_p->uLUPTNLInformation_ToBeSetup_List.list.array[0]; + F1AP_GTPTunnel_t *ul_up_tnl0 = ul_up_tnl_info_p->uLUPTNLInformation.choice.gTPTunnel; + BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&ul_up_tnl0->transportLayerAddress, drb_p->up_ul_tnl[0].tl_address); + OCTET_STRING_TO_INT32(&ul_up_tnl0->gTP_TEID, drb_p->up_ul_tnl[0].teid); + + switch (drbs_tobesetup_item_p->rLCMode) { + case F1AP_RLCMode_rlc_am: + drb_p->rlc_mode = RLC_MODE_AM; + break; + + default: + drb_p->rlc_mode = RLC_MODE_TM; + break; + } + if (!(RC.nrrrc && RC.nrrrc[instance]->node_type == ngran_gNB_DU)) { + transport_layer_addr_t addr; + memcpy(addr.buffer, &drb_p->up_ul_tnl[0].tl_address, sizeof(drb_p->up_ul_tnl[0].tl_address)); + addr.length=sizeof(drb_p->up_ul_tnl[0].tl_address)*8; + drb_p->up_dl_tnl[0].teid=newGtpuCreateTunnel(INSTANCE_DEFAULT, + f1ap_ue_context_modification_req->rnti, + drb_p->drb_id, + drb_p->drb_id, + drb_p->up_ul_tnl[0].teid, + addr, + 2152, + lteDURecvCb); + drb_p->up_dl_tnl_length++; + } + } + } + /* RRC Reconfiguration Complete indicator */ + F1AP_UEContextModificationRequestIEs_t *ieReconf; + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, ieReconf, container, + F1AP_ProtocolIE_ID_id_RRCReconfigurationCompleteIndicator, false); + + if(ieReconf) { + switch(ieReconf->value.choice.RRCReconfigurationCompleteIndicator){ + case F1AP_RRCReconfigurationCompleteIndicator_true: + f1ap_ue_context_modification_req->ReconfigComplOutcome = RRCreconf_success; + break; + + case F1AP_RRCReconfigurationCompleteIndicator_failure: + f1ap_ue_context_modification_req->ReconfigComplOutcome = RRCreconf_failure; + break; + } + } + + /* RRCContainer */ + F1AP_UEContextModificationRequestIEs_t *ieRRC; + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, ieRRC, container, + F1AP_ProtocolIE_ID_id_RRCContainer, false); + + if (ieRRC) { + /* correct here */ + if ( ieRRC->value.choice.RRCContainer.size ) { + f1ap_ue_context_modification_req->rrc_container = malloc(ieRRC->value.choice.RRCContainer.size); + memcpy(f1ap_ue_context_modification_req->rrc_container, + ieRRC->value.choice.RRCContainer.buf, ieRRC->value.choice.RRCContainer.size); + // AssertFatal(0, "check configuration, send to appropriate handler\n"); + protocol_ctxt_t ctxt; + // decode RRC Container and act on the message type + //FIXME + //rnti_t rnti = f1ap_get_rnti_by_du_id(DUtype, instance, du_ue_f1ap_id); + ctxt.instance = instance; + ctxt.instance = instance; + ctxt.enb_flag = 1; + mem_block_t *pdcp_pdu_p = get_free_mem_block(ieRRC->value.choice.RRCContainer.size, __func__); + memcpy(&pdcp_pdu_p->data[0], ieRRC->value.choice.RRCContainer.buf, ieRRC->value.choice.RRCContainer.size); + du_rlc_data_req(&ctxt, 1, 0x00, 1, 1, 0, ieRRC->value.choice.RRCContainer.size, pdcp_pdu_p); + } else { + LOG_E(F1AP, " RRCContainer in UEContextSetupRequestIEs size id 0\n"); + } + } else { + LOG_W(F1AP, "can't find RRCContainer in UEContextSetupRequestIEs by id %ld \n", F1AP_ProtocolIE_ID_id_RRCContainer); + } + + itti_send_msg_to_task(TASK_RRC_GNB, instance, msg_p); + return 0; } + //void DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(F1AP_UEContextModificationResponse_t *UEContextModificationResponse) { int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance) { F1AP_F1AP_PDU_t pdu= {0}; diff --git a/openair2/F1AP/f1ap_handlers.c b/openair2/F1AP/f1ap_handlers.c index fec03bb0b9..6bbf1c796d 100644 --- a/openair2/F1AP/f1ap_handlers.c +++ b/openair2/F1AP/f1ap_handlers.c @@ -50,7 +50,7 @@ f1ap_message_processing_t f1ap_messages_processing[][3] = { { DU_handle_gNB_CU_CONFIGURATION_UPDATE, CU_handle_gNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE, CU_handle_gNB_CU_CONFIGURATION_UPDATE_FAILURE }, /* gNBCUConfigurationUpdate */ { DU_handle_UE_CONTEXT_SETUP_REQUEST, CU_handle_UE_CONTEXT_SETUP_RESPONSE, 0 }, /* UEContextSetup */ { DU_handle_UE_CONTEXT_RELEASE_COMMAND, CU_handle_UE_CONTEXT_RELEASE_COMPLETE, 0 }, /* UEContextRelease */ - { 0, 0, 0 }, /* UEContextModification */ + { DU_handle_UE_CONTEXT_MODIFICATION_REQUEST, 0, 0 }, /* UEContextModification */ { 0, 0, 0 }, /* UEContextModificationRequired */ { 0, 0, 0 }, /* UEMobilityCommand */ { CU_handle_UE_CONTEXT_RELEASE_REQUEST, 0, 0 }, /* UEContextReleaseRequest */ From f068fb4ef31b81af21ade6480b1bd2d3c238a1b3 Mon Sep 17 00:00:00 2001 From: matzakos Date: Wed, 6 Oct 2021 18:43:10 +0200 Subject: [PATCH 005/267] Add handling of UE context modification request at RRC layer of the DU and trigger UE context modification response -Next step: Proper generation of UE context modification response at F1AP layer --- openair2/COMMON/f1ap_messages_types.h | 5 +- openair2/F1AP/f1ap_du_task.c | 5 + openair2/RRC/NR/rrc_gNB.c | 157 +++++++++++++++++++++++--- 3 files changed, 151 insertions(+), 16 deletions(-) diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index 2881910b19..ecf5307dc0 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -358,8 +358,9 @@ typedef enum QoS_information_e { } QoS_information_t; typedef enum ReconfigurationCompl_e { - RRCreconf_failure = 0, - RRCreconf_success = 1, + RRCreconf_info_not_present = 0, + RRCreconf_failure = 1, + RRCreconf_success = 2, } ReconfigurationCompl_t; typedef struct f1ap_ue_context_setup_s { diff --git a/openair2/F1AP/f1ap_du_task.c b/openair2/F1AP/f1ap_du_task.c index 6c5094d248..915858d7da 100644 --- a/openair2/F1AP/f1ap_du_task.c +++ b/openair2/F1AP/f1ap_du_task.c @@ -209,6 +209,11 @@ void *F1AP_DU_task(void *arg) { DU_send_UE_CONTEXT_SETUP_RESPONSE(myInstance, &F1AP_UE_CONTEXT_SETUP_RESP(msg)); break; + case F1AP_UE_CONTEXT_MODIFICATION_RESP: + LOG_I(F1AP, "DU task received itti message from RRC for F1AP_UE_CONTEXT_MODIFICATION_RESP message generation \n"); + //DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(myInstance, &F1AP_UE_CONTEXT_MODIFICATION_RESP(msg)); + break; + case F1AP_UE_CONTEXT_RELEASE_REQ: // from MAC LOG_I(F1AP, "DU Task Received F1AP_UE_CONTEXT_RELEASE_REQ\n"); DU_send_UE_CONTEXT_RELEASE_REQUEST(myInstance, diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index f91d2a9ad0..92c6fe62d4 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -3318,8 +3318,6 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha } } - - NR_CellGroupConfig_t *cellGroupConfig; cellGroupConfig = calloc(1, sizeof(NR_CellGroupConfig_t)); update_cellGroupConfig(cellGroupConfig, ue_context_p->ue_context.masterCellGroup); @@ -3426,6 +3424,137 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha itti_send_msg_to_task (TASK_DU_F1, ctxt.module_id, message_p); } +static void rrc_DU_process_ue_context_modification_request(MessageDef *msg_p, const char *msg_name, instance_t instance){ + + f1ap_ue_context_setup_t * req=&F1AP_UE_CONTEXT_MODIFICATION_REQ(msg_p); + protocol_ctxt_t ctxt; + ctxt.rnti = req->rnti; + ctxt.module_id = instance; + ctxt.instance = instance; + ctxt.enb_flag = 1; + gNB_RRC_INST *rrc = RC.nrrrc[ctxt.module_id]; + gNB_MAC_INST *mac = RC.nrmac[ctxt.module_id]; + struct rrc_gNB_ue_context_s *ue_context_p = + rrc_gNB_get_ue_context(rrc, ctxt.rnti); + MessageDef *message_p; + message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, F1AP_UE_CONTEXT_MODIFICATION_RESP); + f1ap_ue_context_setup_t * resp=&F1AP_UE_CONTEXT_MODIFICATION_RESP(message_p); + uint32_t incoming_teid = 0; + NR_CellGroupConfig_t *cellGroupConfig = NULL; + + /* Configure SRB2 */ + NR_SRB_ToAddMod_t *SRB2_config = NULL; + NR_SRB_ToAddModList_t *SRB_configList = NULL; + uint8_t SRBs_before_new_addition = 0; + + if(req->srbs_to_be_setup_length>0){ + if(ue_context_p->ue_context.SRB_configList == NULL){ + LOG_W(NR_RRC, "The SRB list of the UE context is empty before the addition of new SRB at the DU \n"); + ue_context_p->ue_context.SRB_configList = CALLOC(1, sizeof(*ue_context_p->ue_context.SRB_configList)); + } + SRB_configList = ue_context_p->ue_context.SRB_configList; + SRBs_before_new_addition = SRB_configList->list.count; + for (int i=0; isrbs_to_be_setup_length; i++){ + SRB2_config = CALLOC(1, sizeof(*SRB2_config)); + SRB2_config->srb_Identity = req->srbs_to_be_setup[i].srb_id; + ASN_SEQUENCE_ADD(&SRB_configList->list, SRB2_config); + } + } + + /* Configure DRB */ + NR_DRB_ToAddMod_t *DRB_config = NULL; + NR_DRB_ToAddModList_t *DRB_configList = NULL; + if(req->drbs_to_be_setup_length>0){ + if(ue_context_p->ue_context.DRB_configList == NULL){ + ue_context_p->ue_context.DRB_configList = CALLOC(1, sizeof(*ue_context_p->ue_context.DRB_configList)); + } + DRB_configList = ue_context_p->ue_context.DRB_configList; + for (int i=0; idrbs_to_be_setup_length; i++){ + DRB_config = CALLOC(1, sizeof(*DRB_config)); + DRB_config->drb_Identity = req->drbs_to_be_setup[i].drb_id; + ASN_SEQUENCE_ADD(&DRB_configList->list, DRB_config); + f1ap_drb_to_be_setup_t drb_p = req->drbs_to_be_setup[i]; + transport_layer_addr_t addr; + memcpy(addr.buffer, &drb_p.up_ul_tnl[0].tl_address, sizeof(drb_p.up_ul_tnl[0].tl_address)); + addr.length=sizeof(drb_p.up_ul_tnl[0].tl_address)*8; + extern instance_t DUuniqInstance; + incoming_teid=newGtpuCreateTunnel(DUuniqInstance, + req->rnti, + drb_p.drb_id, + drb_p.drb_id, + drb_p.up_ul_tnl[0].teid, + addr, + 2152, + DURecvCb); + } + } + + if(req->srbs_to_be_setup_length>0 || req->drbs_to_be_setup_length>0){ + cellGroupConfig = calloc(1, sizeof(NR_CellGroupConfig_t)); + fill_mastercellGroupConfig(cellGroupConfig, ue_context_p->ue_context.masterCellGroup, + req->srbs_to_be_setup_length>0 ? 1:0, + req->drbs_to_be_setup_length>0 ? 1:0); + nr_rrc_rlc_config_asn1_req(&ctxt, + ue_context_p->ue_context.SRB_configList, + ue_context_p->ue_context.DRB_configList, + NULL, + NULL, + get_softmodem_params()->sa ? ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList : NULL); + } + if(req->ReconfigComplOutcome == RRCreconf_failure){ + LOG_W(NR_RRC, "CU reporting RRC Reconfiguration failure \n"); + } + else if(req->ReconfigComplOutcome == RRCreconf_success){ + LOG_I(NR_RRC, "CU reporting RRC Reconfiguration success \n"); + } + + /* Fill the UE context setup response ITTI message to send to F1AP */ + resp->gNB_CU_ue_id = req->gNB_CU_ue_id; + resp->rnti = ctxt.rnti; + if(DRB_configList){ + if(DRB_configList->list.count > 0){ + resp->drbs_to_be_setup = calloc(1,DRB_configList->list.count*sizeof(f1ap_drb_to_be_setup_t)); + resp->drbs_to_be_setup_length = DRB_configList->list.count; + for (int i=0; ilist.count; i++){ + resp->drbs_to_be_setup[i].drb_id = DRB_configList->list.array[i]->drb_Identity; + resp->drbs_to_be_setup[i].rlc_mode = RLC_MODE_AM; + resp->drbs_to_be_setup[i].up_dl_tnl[0].teid = incoming_teid; + resp->drbs_to_be_setup[i].up_dl_tnl[0].tl_address = inet_addr(mac->eth_params_n.my_addr); + resp->drbs_to_be_setup[i].up_dl_tnl_length = 1; + } + } + else{ + LOG_W(NR_RRC, "No DRB added upon reception of F1 UE context modification request with a DRB to setup list\n"); + } + } + if(SRB_configList){ + if(SRB_configList->list.count >0 && SRBs_before_new_addition < SRB_configList->list.count){ + resp->srbs_to_be_setup = calloc(1,req->srbs_to_be_setup_length*sizeof(f1ap_srb_to_be_setup_t)); + resp->srbs_to_be_setup_length = req->srbs_to_be_setup_length; + for (int i=SRBs_before_new_addition; ilist.count; i++){ + resp->srbs_to_be_setup[i-SRBs_before_new_addition].srb_id = SRB_configList->list.array[i]->srb_Identity; + } + } + else{ + LOG_W(NR_RRC, "No SRB added upon reception of F1 UE Context modification request at the DU\n"); + } + } + else{ + LOG_W(NR_RRC, "No SRB added upon reception of F1 UE Context modification request at the DU\n"); + } + + if(cellGroupConfig != NULL) { + resp->du_to_cu_rrc_information = calloc(1,1024*sizeof(uint8_t)); + asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, + NULL, + (void *)cellGroupConfig, + resp->du_to_cu_rrc_information, + 1024); + resp->du_to_cu_rrc_information_length = (enc_rval.encoded+7)>>3; + } + itti_send_msg_to_task (TASK_DU_F1, ctxt.module_id, message_p); +} + static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, const char *msg_name, instance_t instance){ f1ap_ue_context_setup_t * resp=&F1AP_UE_CONTEXT_SETUP_RESP(msg_p); @@ -3967,21 +4096,21 @@ void *rrc_gnb_task(void *args_p) { rrc_gNB_process_f1_setup_req(&F1AP_SETUP_REQ(msg_p)); break; - case NR_DU_RRC_DL_INDICATION: - rrc_process_DU_DL(msg_p, msg_name_p, instance); - break; + case NR_DU_RRC_DL_INDICATION: + rrc_process_DU_DL(msg_p, msg_name_p, instance); + break; - case F1AP_UE_CONTEXT_SETUP_REQ: - rrc_DU_process_ue_context_setup_request(msg_p, msg_name_p, instance); - break; + case F1AP_UE_CONTEXT_SETUP_REQ: + rrc_DU_process_ue_context_setup_request(msg_p, msg_name_p, instance); + break; - case F1AP_UE_CONTEXT_SETUP_RESP: - rrc_CU_process_ue_context_setup_response(msg_p, msg_name_p, instance); - break; + case F1AP_UE_CONTEXT_SETUP_RESP: + rrc_CU_process_ue_context_setup_response(msg_p, msg_name_p, instance); + break; - case F1AP_UE_CONTEXT_MODIFICATION_REQ: - LOG_I(NR_RRC, "F1AP_UE_CONTEXT_MODIFICATION_REQ itti message received from the F1AP layer of the DU \n"); - break; + case F1AP_UE_CONTEXT_MODIFICATION_REQ: + rrc_DU_process_ue_context_modification_request(msg_p, msg_name_p, instance); + break; /* Messages from X2AP */ case X2AP_ENDC_SGNB_ADDITION_REQ: From a1b2d222ddc068c4af110fec06089a8823f58c45 Mon Sep 17 00:00:00 2001 From: matzakos Date: Fri, 8 Oct 2021 10:31:53 +0200 Subject: [PATCH 006/267] Generation of UE context modification response at F1AP layer of the DU -Fix some indentations --- openair2/F1AP/f1ap_decoder.c | 4 + openair2/F1AP/f1ap_du_task.c | 2 +- openair2/F1AP/f1ap_du_ue_context_management.c | 357 ++++++++++-------- openair2/F1AP/f1ap_du_ue_context_management.h | 2 +- 4 files changed, 209 insertions(+), 156 deletions(-) diff --git a/openair2/F1AP/f1ap_decoder.c b/openair2/F1AP/f1ap_decoder.c index f1e4410786..60b3f94310 100644 --- a/openair2/F1AP/f1ap_decoder.c +++ b/openair2/F1AP/f1ap_decoder.c @@ -127,6 +127,10 @@ static int f1ap_decode_successful_outcome(F1AP_F1AP_PDU_t *pdu) { LOG_I(F1AP, "%s(): F1AP_ProcedureCode_id_UEContextSetup\n", __func__); break; + case F1AP_ProcedureCode_id_UEContextModification: + LOG_I(F1AP, "%s(): F1AP_ProcedureCode_id_UEContextModification\n", __func__); + break; + default: LOG_E(F1AP,"Unknown procedure ID (%d) for successfull outcome message\n", (int)pdu->choice.successfulOutcome->procedureCode); diff --git a/openair2/F1AP/f1ap_du_task.c b/openair2/F1AP/f1ap_du_task.c index 915858d7da..1609fda459 100644 --- a/openair2/F1AP/f1ap_du_task.c +++ b/openair2/F1AP/f1ap_du_task.c @@ -211,7 +211,7 @@ void *F1AP_DU_task(void *arg) { case F1AP_UE_CONTEXT_MODIFICATION_RESP: LOG_I(F1AP, "DU task received itti message from RRC for F1AP_UE_CONTEXT_MODIFICATION_RESP message generation \n"); - //DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(myInstance, &F1AP_UE_CONTEXT_MODIFICATION_RESP(msg)); + DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(myInstance, &F1AP_UE_CONTEXT_MODIFICATION_RESP(msg)); break; case F1AP_UE_CONTEXT_RELEASE_REQ: // from MAC diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index cbbe563285..5f904330ad 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -253,7 +253,7 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, return 0; } -int DU_send_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, f1ap_ue_context_setup_t *req) { +int DU_send_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, f1ap_ue_context_setup_t *resp) { F1AP_F1AP_PDU_t pdu= {0}; F1AP_UEContextSetupResponse_t *out; uint8_t *buffer=NULL; @@ -272,42 +272,40 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, f1ap_ue_context_setup ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; ie1->criticality = F1AP_Criticality_reject; ie1->value.present = F1AP_UEContextSetupResponseIEs__value_PR_GNB_CU_UE_F1AP_ID; - ie1->value.choice.GNB_CU_UE_F1AP_ID = req->gNB_CU_ue_id; + ie1->value.choice.GNB_CU_UE_F1AP_ID = resp->gNB_CU_ue_id; /* mandatory */ /* c2. GNB_DU_UE_F1AP_ID */ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie2); ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; ie2->criticality = F1AP_Criticality_reject; ie2->value.present = F1AP_UEContextSetupResponseIEs__value_PR_GNB_DU_UE_F1AP_ID; - ie2->value.choice.GNB_DU_UE_F1AP_ID = f1ap_get_du_ue_f1ap_id(DUtype, instance, req->rnti); + ie2->value.choice.GNB_DU_UE_F1AP_ID = f1ap_get_du_ue_f1ap_id(DUtype, instance, resp->rnti); /* mandatory */ /* c3. DUtoCURRCInformation */ - //if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie3); - ie3->id = F1AP_ProtocolIE_ID_id_DUtoCURRCInformation; - ie3->criticality = F1AP_Criticality_reject; - ie3->value.present = F1AP_UEContextSetupResponseIEs__value_PR_DUtoCURRCInformation; - { - /* cellGroupConfig */ - OCTET_STRING_fromBuf(&ie3->value.choice.DUtoCURRCInformation.cellGroupConfig, (const char *)req->du_to_cu_rrc_information, - req->du_to_cu_rrc_information_length); + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie3); + ie3->id = F1AP_ProtocolIE_ID_id_DUtoCURRCInformation; + ie3->criticality = F1AP_Criticality_reject; + ie3->value.present = F1AP_UEContextSetupResponseIEs__value_PR_DUtoCURRCInformation; + { + /* cellGroupConfig */ + OCTET_STRING_fromBuf(&ie3->value.choice.DUtoCURRCInformation.cellGroupConfig, (const char *)resp->du_to_cu_rrc_information, + resp->du_to_cu_rrc_information_length); - /* OPTIONAL */ - /* measGapConfig */ - if (0) { - asn1cCalloc(ie3->value.choice.DUtoCURRCInformation.measGapConfig, tmp); - OCTET_STRING_fromBuf(tmp, "asdsa", strlen("asdsa")); - } - - /* OPTIONAL */ - /* requestedP_MaxFR1 */ - if (0) { - asn1cCalloc(ie3->value.choice.DUtoCURRCInformation.requestedP_MaxFR1, tmp); - OCTET_STRING_fromBuf(tmp, "asdsa", strlen("asdsa")); - } + /* OPTIONAL */ + /* measGapConfig */ + if (0) { + asn1cCalloc(ie3->value.choice.DUtoCURRCInformation.measGapConfig, tmp); + OCTET_STRING_fromBuf(tmp, "asdsa", strlen("asdsa")); } - //} + + /* OPTIONAL */ + /* requestedP_MaxFR1 */ + if (0) { + asn1cCalloc(ie3->value.choice.DUtoCURRCInformation.requestedP_MaxFR1, tmp); + OCTET_STRING_fromBuf(tmp, "asdsa", strlen("asdsa")); + } + } /* optional */ /* c4. C_RNTI */ @@ -317,7 +315,7 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, f1ap_ue_context_setup ie4->criticality = F1AP_Criticality_ignore; ie4->value.present = F1AP_UEContextSetupResponseIEs__value_PR_C_RNTI; //C_RNTI_TO_BIT_STRING(rntiP, &ie->value.choice.C_RNTI); - ie4->value.choice.C_RNTI=req->rnti; + ie4->value.choice.C_RNTI=resp->rnti; LOG_E(F1AP,"RNTI to code!\n"); } @@ -344,95 +342,95 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, f1ap_ue_context_setup /* mandatory */ /* c7. DRBs_Setup_List */ - if(req->drbs_to_be_setup_length > 0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie7); - ie7->id = F1AP_ProtocolIE_ID_id_DRBs_Setup_List; - ie7->criticality = F1AP_Criticality_ignore; - ie7->value.present = F1AP_UEContextSetupResponseIEs__value_PR_DRBs_Setup_List; - for (int i=0; i< req->drbs_to_be_setup_length; i++) { - // - asn1cSequenceAdd(ie7->value.choice.DRBs_Setup_List.list, - F1AP_DRBs_Setup_ItemIEs_t, drbs_setup_item_ies); - drbs_setup_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_Setup_Item; - drbs_setup_item_ies->criticality = F1AP_Criticality_ignore; - drbs_setup_item_ies->value.present = F1AP_SRBs_FailedToBeSetup_ItemIEs__value_PR_SRBs_FailedToBeSetup_Item; - /* 7.1 DRBs_Setup_Item */ - /* ADD */ - F1AP_DRBs_Setup_Item_t *drbs_setup_item=&drbs_setup_item_ies->value.choice.DRBs_Setup_Item; - /* dRBID */ - drbs_setup_item->dRBID = req->drbs_to_be_setup[i].drb_id; - - /* OPTIONAL */ - /* lCID */ - //drbs_setup_item.lCID = (F1AP_LCID_t *)calloc(1, sizeof(F1AP_LCID_t)); - //drbs_setup_item.lCID = 1L; - - for (int j=0; jdrbs_to_be_setup[i].up_dl_tnl_length; j++) { + if(resp->drbs_to_be_setup_length > 0){ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie7); + ie7->id = F1AP_ProtocolIE_ID_id_DRBs_Setup_List; + ie7->criticality = F1AP_Criticality_ignore; + ie7->value.present = F1AP_UEContextSetupResponseIEs__value_PR_DRBs_Setup_List; + for (int i=0; i< resp->drbs_to_be_setup_length; i++) { + // + asn1cSequenceAdd(ie7->value.choice.DRBs_Setup_List.list, + F1AP_DRBs_Setup_ItemIEs_t, drbs_setup_item_ies); + drbs_setup_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_Setup_Item; + drbs_setup_item_ies->criticality = F1AP_Criticality_ignore; + drbs_setup_item_ies->value.present = F1AP_DRBs_Setup_ItemIEs__value_PR_DRBs_Setup_Item; + /* 7.1 DRBs_Setup_Item */ /* ADD */ - asn1cSequenceAdd(drbs_setup_item->dLUPTNLInformation_ToBeSetup_List.list, + F1AP_DRBs_Setup_Item_t *drbs_setup_item=&drbs_setup_item_ies->value.choice.DRBs_Setup_Item; + /* dRBID */ + drbs_setup_item->dRBID = resp->drbs_to_be_setup[i].drb_id; + + /* OPTIONAL */ + /* lCID */ + //drbs_setup_item.lCID = (F1AP_LCID_t *)calloc(1, sizeof(F1AP_LCID_t)); + //drbs_setup_item.lCID = 1L; + + for (int j=0; jdrbs_to_be_setup[i].up_dl_tnl_length; j++) { + /* ADD */ + asn1cSequenceAdd(drbs_setup_item->dLUPTNLInformation_ToBeSetup_List.list, F1AP_DLUPTNLInformation_ToBeSetup_Item_t, dLUPTNLInformation_ToBeSetup_Item); - dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; - /* gTPTunnel */ - asn1cCalloc(dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.choice.gTPTunnel,gTPTunnel); - /* transportLayerAddress */ - struct sockaddr_in addr= {0}; - inet_pton(AF_INET, getCxt(false,instance)->setupReq.DU_f1_ip_address.ipv4_address, - &addr.sin_addr.s_addr); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(addr.sin_addr.s_addr, - &gTPTunnel->transportLayerAddress); - /* gTP_TEID */ - INT32_TO_OCTET_STRING(req->drbs_to_be_setup[i].up_dl_tnl[j].teid, &gTPTunnel->gTP_TEID); - } // for j - } // for i + dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; + /* gTPTunnel */ + asn1cCalloc(dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.choice.gTPTunnel,gTPTunnel); + /* transportLayerAddress */ + struct sockaddr_in addr= {0}; + inet_pton(AF_INET, getCxt(false,instance)->setupReq.DU_f1_ip_address.ipv4_address, + &addr.sin_addr.s_addr); + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(addr.sin_addr.s_addr, + &gTPTunnel->transportLayerAddress); + /* gTP_TEID */ + INT32_TO_OCTET_STRING(resp->drbs_to_be_setup[i].up_dl_tnl[j].teid, &gTPTunnel->gTP_TEID); + } // for j + } // for i + } /* mandatory */ /* c8. SRBs_FailedToBeSetup_List */ if(0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie8); - ie8->id = F1AP_ProtocolIE_ID_id_SRBs_FailedToBeSetup_List; - ie8->criticality = F1AP_Criticality_ignore; - ie8->value.present = F1AP_UEContextSetupResponseIEs__value_PR_SRBs_FailedToBeSetup_List; + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie8); + ie8->id = F1AP_ProtocolIE_ID_id_SRBs_FailedToBeSetup_List; + ie8->criticality = F1AP_Criticality_ignore; + ie8->value.present = F1AP_UEContextSetupResponseIEs__value_PR_SRBs_FailedToBeSetup_List; - for (int i=0; i<1; i++) { - // - asn1cSequenceAdd(ie8->value.choice.SRBs_FailedToBeSetup_List.list, - F1AP_SRBs_FailedToBeSetup_ItemIEs_t, srbs_failedToBeSetup_item_ies); - srbs_failedToBeSetup_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_FailedToBeSetup_Item; - srbs_failedToBeSetup_item_ies->criticality = F1AP_Criticality_ignore; - srbs_failedToBeSetup_item_ies->value.present = F1AP_SRBs_FailedToBeSetup_ItemIEs__value_PR_SRBs_FailedToBeSetup_Item; - /* 8.1 SRBs_Setup_Item */ - F1AP_SRBs_FailedToBeSetup_Item_t *srbs_failedToBeSetup_item= - &srbs_failedToBeSetup_item_ies->value.choice.SRBs_FailedToBeSetup_Item; - /* sRBID */ - srbs_failedToBeSetup_item->sRBID = 13L; - /* cause */ - asn1cCalloc(srbs_failedToBeSetup_item->cause, tmp); - // dummy value - tmp->present = F1AP_Cause_PR_radioNetwork; + for (int i=0; i<1; i++) { + // + asn1cSequenceAdd(ie8->value.choice.SRBs_FailedToBeSetup_List.list, + F1AP_SRBs_FailedToBeSetup_ItemIEs_t, srbs_failedToBeSetup_item_ies); + srbs_failedToBeSetup_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_FailedToBeSetup_Item; + srbs_failedToBeSetup_item_ies->criticality = F1AP_Criticality_ignore; + srbs_failedToBeSetup_item_ies->value.present = F1AP_SRBs_FailedToBeSetup_ItemIEs__value_PR_SRBs_FailedToBeSetup_Item; + /* 8.1 SRBs_Setup_Item */ + F1AP_SRBs_FailedToBeSetup_Item_t *srbs_failedToBeSetup_item= + &srbs_failedToBeSetup_item_ies->value.choice.SRBs_FailedToBeSetup_Item; + /* sRBID */ + srbs_failedToBeSetup_item->sRBID = 13L; + /* cause */ + asn1cCalloc(srbs_failedToBeSetup_item->cause, tmp); + // dummy value + tmp->present = F1AP_Cause_PR_radioNetwork; - switch(tmp->present) { - case F1AP_Cause_PR_radioNetwork: - tmp->choice.radioNetwork = F1AP_CauseRadioNetwork_unspecified; - break; + switch(tmp->present) { + case F1AP_Cause_PR_radioNetwork: + tmp->choice.radioNetwork = F1AP_CauseRadioNetwork_unspecified; + break; + case F1AP_Cause_PR_transport: + tmp->choice.transport = F1AP_CauseTransport_unspecified; + break; - case F1AP_Cause_PR_transport: - tmp->choice.transport = F1AP_CauseTransport_unspecified; - break; + case F1AP_Cause_PR_protocol: + tmp->choice.protocol = F1AP_CauseProtocol_unspecified; + break; - case F1AP_Cause_PR_protocol: - tmp->choice.protocol = F1AP_CauseProtocol_unspecified; - break; + case F1AP_Cause_PR_misc: + tmp->choice.misc = F1AP_CauseMisc_unspecified; + break; - case F1AP_Cause_PR_misc: - tmp->choice.misc = F1AP_CauseMisc_unspecified; - break; - - case F1AP_Cause_PR_NOTHING: - default: - break; - } // switch - } // for i + case F1AP_Cause_PR_NOTHING: + default: + break; + } // switch + } // for i } /* */ @@ -534,13 +532,13 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, f1ap_ue_context_setup /* mandatory */ /* c11. SRBs_Setup_List */ - if(req->srbs_to_be_setup_length > 0){ + if(resp->srbs_to_be_setup_length > 0){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie11); ie11->id = F1AP_ProtocolIE_ID_id_SRBs_Setup_List; ie11->criticality = F1AP_Criticality_ignore; ie11->value.present = F1AP_UEContextSetupResponseIEs__value_PR_SRBs_Setup_List; - for (int i=0; i< req->srbs_to_be_setup_length; i++) {// + for (int i=0; i< resp->srbs_to_be_setup_length; i++) {// asn1cSequenceAdd(ie11->value.choice.SRBs_Setup_List.list, F1AP_SRBs_Setup_ItemIEs_t, srbs_setup_item_ies); srbs_setup_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_Setup_Item; @@ -550,7 +548,7 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, f1ap_ue_context_setup /* ADD */ F1AP_SRBs_Setup_Item_t *srbs_setup_item=&srbs_setup_item_ies->value.choice.SRBs_Setup_Item; /* sRBID */ - srbs_setup_item->sRBID = req->srbs_to_be_setup[i].srb_id; + srbs_setup_item->sRBID = resp->srbs_to_be_setup[i].srb_id; } } @@ -925,8 +923,8 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, /* mandatory */ /* GNB_DU_UE_F1AP_ID */ - F1AP_UEContextSetupRequestIEs_t *ieDU_UE; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupRequestIEs_t, ieDU_UE, container, + F1AP_UEContextModificationRequestIEs_t *ieDU_UE; + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, ieDU_UE, container, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); f1ap_ue_context_modification_req->gNB_DU_ue_id = ieDU_UE->value.choice.GNB_DU_UE_F1AP_ID; f1ap_ue_context_modification_req->rnti = f1ap_get_rnti_by_du_id(DUtype, instance, f1ap_ue_context_modification_req->gNB_DU_ue_id); @@ -959,7 +957,7 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, /* DRB */ F1AP_UEContextModificationRequestIEs_t *ieDrb; F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, ieDrb, container, - F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_List, false); + F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_List, false); if(ieDrb!=NULL) { f1ap_ue_context_modification_req->drbs_to_be_setup_length = ieDrb->value.choice.DRBs_ToBeSetupMod_List.list.count; @@ -1059,7 +1057,7 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, } //void DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(F1AP_UEContextModificationResponse_t *UEContextModificationResponse) { -int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance) { +int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, f1ap_ue_context_setup_t *resp) { F1AP_F1AP_PDU_t pdu= {0}; F1AP_UEContextModificationResponse_t *out; uint8_t *buffer=NULL; @@ -1078,14 +1076,14 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance) { ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; ie1->criticality = F1AP_Criticality_reject; ie1->value.present = F1AP_UEContextModificationResponseIEs__value_PR_GNB_CU_UE_F1AP_ID; - ie1->value.choice.GNB_CU_UE_F1AP_ID = 126L; + ie1->value.choice.GNB_CU_UE_F1AP_ID = resp->gNB_CU_ue_id; /* mandatory */ /* c2. GNB_DU_UE_F1AP_ID */ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie2); ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; ie2->criticality = F1AP_Criticality_reject; ie2->value.present = F1AP_UEContextModificationResponseIEs__value_PR_GNB_DU_UE_F1AP_ID; - ie2->value.choice.GNB_DU_UE_F1AP_ID = 651L; + ie2->value.choice.GNB_DU_UE_F1AP_ID = f1ap_get_du_ue_f1ap_id(DUtype, instance, resp->rnti); /* optional */ /* c3. ResourceCoordinationTransferContainer */ @@ -1098,61 +1096,80 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance) { strlen("asdsa1d32sa1d31asd31as")); } - /* optional */ - /* c4. DUtoCURRCInformation */ - if (0) { + /* mandatory */ + /* c3. DUtoCURRCInformation */ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie4); ie4->id = F1AP_ProtocolIE_ID_id_DUtoCURRCInformation; ie4->criticality = F1AP_Criticality_reject; ie4->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DUtoCURRCInformation; - OCTET_STRING_fromBuf(&ie4->value.choice.DUtoCURRCInformation.cellGroupConfig, "asdsa1d32sa1d31asd31as", - strlen("asdsa1d32sa1d31asd31as")); + { + /* cellGroupConfig */ + OCTET_STRING_fromBuf(&ie4->value.choice.DUtoCURRCInformation.cellGroupConfig, (const char *)resp->du_to_cu_rrc_information, + resp->du_to_cu_rrc_information_length); - /* OPTIONAL */ - if (1) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie41); - ie41->value.choice.DUtoCURRCInformation.measGapConfig = (F1AP_MeasGapConfig_t *)calloc(1, sizeof(F1AP_MeasGapConfig_t)); - OCTET_STRING_fromBuf( ie41->value.choice.DUtoCURRCInformation.measGapConfig, "asdsa1d32sa1d31asd31as", - strlen("asdsa1d32sa1d31asd31as")); + /* OPTIONAL */ + /* measGapConfig */ + if (0) { + asn1cCalloc(ie4->value.choice.DUtoCURRCInformation.measGapConfig, tmp); + OCTET_STRING_fromBuf(tmp, "asdsa", strlen("asdsa")); + } + + /* OPTIONAL */ + /* requestedP_MaxFR1 */ + if (0) { + asn1cCalloc(ie4->value.choice.DUtoCURRCInformation.requestedP_MaxFR1, tmp); + OCTET_STRING_fromBuf(tmp, "asdsa", strlen("asdsa")); + } } - } - /* mandatory */ - /* c5. DRBs_SetupMod_List */ + + /* optional */ + /* c5. DRBs_Setup_List */ + if(resp->drbs_to_be_setup_length > 0){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie5); ie5->id = F1AP_ProtocolIE_ID_id_DRBs_SetupMod_List; - ie5->criticality = F1AP_Criticality_reject; + ie5->criticality = F1AP_Criticality_ignore; ie5->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DRBs_SetupMod_List; - - for (int i=0; i<1; i++) { + for (int i=0; i< resp->drbs_to_be_setup_length; i++) { // asn1cSequenceAdd(ie5->value.choice.DRBs_SetupMod_List.list, - F1AP_DRBs_SetupMod_ItemIEs_t, drbs_setupMod_item_ies); - drbs_setupMod_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_SetupMod_Item; - drbs_setupMod_item_ies->criticality = F1AP_Criticality_reject; - drbs_setupMod_item_ies->value.present = F1AP_DRBs_SetupMod_ItemIEs__value_PR_DRBs_SetupMod_Item; - /* 10.1 DRBs_SetupMod_Item */ - F1AP_DRBs_SetupMod_Item_t *drbs_setupMod_item=&drbs_setupMod_item_ies->value.choice.DRBs_SetupMod_Item; + F1AP_DRBs_SetupMod_ItemIEs_t, drbs_setupmod_item_ies); + drbs_setupmod_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_SetupMod_Item; + drbs_setupmod_item_ies->criticality = F1AP_Criticality_ignore; + drbs_setupmod_item_ies->value.present = F1AP_DRBs_SetupMod_ItemIEs__value_PR_DRBs_SetupMod_Item; + /* 7.1 DRBs_Setup_Item */ + /* ADD */ + F1AP_DRBs_SetupMod_Item_t *drbs_setupmod_item=&drbs_setupmod_item_ies->value.choice.DRBs_SetupMod_Item; /* dRBID */ - drbs_setupMod_item->dRBID = 30L; - /* DLTunnels_SetupMod_List */ - int maxnoofDLUPTNLInformation = 1; // 2; + drbs_setupmod_item->dRBID = resp->drbs_to_be_setup[i].drb_id; - for (int j=0; jvalue.choice.DRBs_SetupMod_List.list, + /* OPTIONAL */ + /* lCID */ + //drbs_setup_item.lCID = (F1AP_LCID_t *)calloc(1, sizeof(F1AP_LCID_t)); + //drbs_setup_item.lCID = 1L; + + for (int j=0; jdrbs_to_be_setup[i].up_dl_tnl_length; j++) { + /* ADD */ + asn1cSequenceAdd(drbs_setupmod_item->dLUPTNLInformation_ToBeSetup_List.list, F1AP_DLUPTNLInformation_ToBeSetup_Item_t, dLUPTNLInformation_ToBeSetup_Item); dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; - asn1cCalloc(dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.choice.gTPTunnel, - gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(1234, &gTPTunnel->transportLayerAddress); - OCTET_STRING_fromBuf(&gTPTunnel->gTP_TEID, "1204", - strlen("1204")); - } + /* gTPTunnel */ + asn1cCalloc(dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.choice.gTPTunnel,gTPTunnel); + /* transportLayerAddress */ + struct sockaddr_in addr= {0}; + inet_pton(AF_INET, getCxt(false,instance)->setupReq.DU_f1_ip_address.ipv4_address, + &addr.sin_addr.s_addr); + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(addr.sin_addr.s_addr, + &gTPTunnel->transportLayerAddress); + /* gTP_TEID */ + INT32_TO_OCTET_STRING(resp->drbs_to_be_setup[i].up_dl_tnl[j].teid, &gTPTunnel->gTP_TEID); + } // for j + } // for i } - /* mandatory */ + /* optional */ /* c6. DRBs_Modified_List */ + if(0){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie6); ie6->id = F1AP_ProtocolIE_ID_id_DRBs_Modified_List; ie6->criticality = F1AP_Criticality_reject; @@ -1184,9 +1201,11 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance) { OCTET_STRING_fromBuf(&gTPTunnel->gTP_TEID, "1204", strlen("1204")); } } + } - /* mandatory */ + /* optional */ /* c7. SRBs_FailedToBeSetupMod_List */ + if(0){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie7); ie7->id = F1AP_ProtocolIE_ID_id_SRBs_FailedToBeSetupMod_List; ie7->criticality = F1AP_Criticality_reject; @@ -1208,9 +1227,11 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance) { tmp->present = F1AP_Cause_PR_radioNetwork; tmp->choice.radioNetwork = F1AP_CauseRadioNetwork_unknown_or_already_allocated_gnb_du_ue_f1ap_id; } + } - /* mandatory */ + /* optional */ /* c8. DRBs_FailedToBeSetupMod_List */ + if(0){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie8); ie8->id = F1AP_ProtocolIE_ID_id_DRBs_FailedToBeSetupMod_List; ie8->criticality = F1AP_Criticality_reject; @@ -1232,9 +1253,11 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance) { drbs_failedToBeSetupMod_item->cause->present = F1AP_Cause_PR_radioNetwork; drbs_failedToBeSetupMod_item->cause->choice.radioNetwork = F1AP_CauseRadioNetwork_unknown_or_already_allocated_gnb_du_ue_f1ap_id; } + } - /* mandatory */ + /* optional */ /* c9. SCell_FailedtoSetupMod_List */ + if(0){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie9); ie9->id = F1AP_ProtocolIE_ID_id_SCell_FailedtoSetupMod_List; ie9->criticality = F1AP_Criticality_ignore; @@ -1255,9 +1278,11 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance) { tmp->present = F1AP_Cause_PR_radioNetwork; tmp->choice.radioNetwork = F1AP_CauseRadioNetwork_unknown_or_already_allocated_gnb_du_ue_f1ap_id; } + } - /* mandatory */ + /* optional */ /* c10. DRBs_FailedToBeModified_List */ + if(0){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie10); ie10->id = F1AP_ProtocolIE_ID_id_DRBs_FailedToBeModified_List; ie10->criticality = F1AP_Criticality_reject; @@ -1279,6 +1304,7 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance) { tmp->present = F1AP_Cause_PR_radioNetwork; tmp->choice.radioNetwork = F1AP_CauseRadioNetwork_unknown_or_already_allocated_gnb_du_ue_f1ap_id; } + } // /* */ /* c11. CriticalityDiagnostics */ @@ -1328,6 +1354,28 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance) { } } } + /* optional */ + /* c12. SRBs_Setup_List */ + if(resp->srbs_to_be_setup_length > 0){ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie12); + ie12->id = F1AP_ProtocolIE_ID_id_SRBs_SetupMod_List; + ie12->criticality = F1AP_Criticality_ignore; + ie12->value.present = F1AP_UEContextModificationResponseIEs__value_PR_SRBs_SetupMod_List; + + for (int i=0; i< resp->srbs_to_be_setup_length; i++) {// + asn1cSequenceAdd(ie12->value.choice.SRBs_SetupMod_List.list, + F1AP_SRBs_SetupMod_ItemIEs_t, srbs_setupmod_item_ies); + srbs_setupmod_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_SetupMod_Item; + srbs_setupmod_item_ies->criticality = F1AP_Criticality_ignore; + srbs_setupmod_item_ies->value.present = F1AP_SRBs_SetupMod_ItemIEs__value_PR_SRBs_SetupMod_Item; + /* 11.1 SRBs_Setup_Item */ + /* ADD */ + F1AP_SRBs_SetupMod_Item_t *srbs_setupmod_item=&srbs_setupmod_item_ies->value.choice.SRBs_SetupMod_Item; + /* sRBID */ + srbs_setupmod_item->sRBID = resp->srbs_to_be_setup[i].srb_id; + srbs_setupmod_item->lCID = resp->srbs_to_be_setup[i].srb_id; + } + } /* encode */ if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { @@ -1335,9 +1383,10 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance) { return -1; } - //f1ap_itti_send_sctp_data_req(false, instance, buffer, len, 0); + f1ap_itti_send_sctp_data_req(false, instance, buffer, len, getCxt(false, instance)->default_sctp_stream_id); return 0; } + int DU_send_UE_CONTEXT_MODIFICATION_FAILURE(instance_t instance) { AssertFatal(1==0,"Not implemented yet\n"); } diff --git a/openair2/F1AP/f1ap_du_ue_context_management.h b/openair2/F1AP/f1ap_du_ue_context_management.h index 82643fa933..acf74f69d7 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.h +++ b/openair2/F1AP/f1ap_du_ue_context_management.h @@ -74,7 +74,7 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, uint32_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu); -int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance); +int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, f1ap_ue_context_setup_t *resp); int DU_send_UE_CONTEXT_MODIFICATION_FAILURE(instance_t instance); From d3899a21a6bfbeb538a92bb66c047b03147e15a7 Mon Sep 17 00:00:00 2001 From: matzakos Date: Fri, 8 Oct 2021 13:37:46 +0200 Subject: [PATCH 007/267] Add implementation of UE context modification response handler at F1AP layer of the CU --- openair2/F1AP/f1ap_cu_ue_context_management.c | 126 +++++++++++++++++- openair2/F1AP/f1ap_handlers.c | 2 +- openair2/RRC/NR/rrc_gNB.c | 8 ++ 3 files changed, 134 insertions(+), 2 deletions(-) diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index 087d63d3f1..02cfb80ac7 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -1646,7 +1646,131 @@ int CU_handle_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, uint32_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { - AssertFatal(1==0,"Not implemented yet\n"); + + MessageDef *msg_p; + F1AP_UEContextModificationResponse_t *container; + F1AP_UEContextModificationResponseIEs_t *ie; + DevAssert(pdu); + msg_p = itti_alloc_new_message(TASK_DU_F1, 0, F1AP_UE_CONTEXT_MODIFICATION_RESP); + f1ap_ue_context_setup_t *f1ap_ue_context_modification_resp = &F1AP_UE_CONTEXT_MODIFICATION_RESP(msg_p); + container = &pdu->choice.successfulOutcome->value.choice.UEContextModificationResponse; + int i; + + /* GNB_CU_UE_F1AP_ID */ + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, + F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, false); + f1ap_ue_context_modification_resp->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID; + + LOG_D(F1AP, "f1ap_ue_context_setup_resp->gNB_CU_ue_id is: %d \n", f1ap_ue_context_modification_resp->gNB_CU_ue_id); + + /* GNB_DU_UE_F1AP_ID */ + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, + F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); + f1ap_ue_context_modification_resp->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; + + LOG_D(F1AP, "f1ap_ue_context_setup_resp->gNB_DU_ue_id is: %d \n", f1ap_ue_context_modification_resp->gNB_DU_ue_id); + + f1ap_ue_context_modification_resp->rnti = + f1ap_get_rnti_by_du_id(CUtype, instance, f1ap_ue_context_modification_resp->gNB_DU_ue_id); + + // DUtoCURRCInformation + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, + F1AP_ProtocolIE_ID_id_DUtoCURRCInformation, true); + if (ie == NULL){ + LOG_E(F1AP,"%s %d: ie is a NULL pointer \n",__FILE__,__LINE__); + return -1; + } + f1ap_ue_context_modification_resp->du_to_cu_rrc_information = (uint8_t *)calloc(1,ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size); + + memcpy(f1ap_ue_context_modification_resp->du_to_cu_rrc_information, ie->value.choice.DUtoCURRCInformation.cellGroupConfig.buf, ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size); + f1ap_ue_context_modification_resp->du_to_cu_rrc_information_length = ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size; + + // DRBs_SetupMod_List + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, + F1AP_ProtocolIE_ID_id_DRBs_SetupMod_List, false); + if(ie!=NULL){ + f1ap_ue_context_modification_resp->drbs_to_be_setup_length = ie->value.choice.DRBs_SetupMod_List.list.count; + f1ap_ue_context_modification_resp->drbs_to_be_setup = calloc(f1ap_ue_context_modification_resp->drbs_to_be_setup_length, + sizeof(f1ap_drb_to_be_setup_t)); + AssertFatal(f1ap_ue_context_modification_resp->drbs_to_be_setup, + "could not allocate memory for f1ap_ue_context_setup_resp->drbs_setup\n"); + for (i = 0; i < f1ap_ue_context_modification_resp->drbs_to_be_setup_length; ++i) { + f1ap_drb_to_be_setup_t *drb_p = &f1ap_ue_context_modification_resp->drbs_to_be_setup[i]; + F1AP_DRBs_SetupMod_Item_t *drbs_setupmod_item_p; + drbs_setupmod_item_p = &((F1AP_DRBs_SetupMod_ItemIEs_t *)ie->value.choice.DRBs_SetupMod_List.list.array[i])->value.choice.DRBs_SetupMod_Item; + drb_p->drb_id = drbs_setupmod_item_p->dRBID; + // TODO in the following, assume only one UP UL TNL is present. + // this matches/assumes OAI CU/DU implementation, can be up to 2! + drb_p->up_dl_tnl_length = 1; + AssertFatal(drbs_setupmod_item_p->dLUPTNLInformation_ToBeSetup_List.list.count > 0, + "no DL UP TNL Information in DRBs to be Setup list\n"); + F1AP_DLUPTNLInformation_ToBeSetup_Item_t *dl_up_tnl_info_p = (F1AP_DLUPTNLInformation_ToBeSetup_Item_t *)drbs_setupmod_item_p->dLUPTNLInformation_ToBeSetup_List.list.array[0]; + F1AP_GTPTunnel_t *dl_up_tnl0 = dl_up_tnl_info_p->dLUPTNLInformation.choice.gTPTunnel; + BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&dl_up_tnl0->transportLayerAddress, drb_p->up_dl_tnl[0].tl_address); + OCTET_STRING_TO_INT32(&dl_up_tnl0->gTP_TEID, drb_p->up_dl_tnl[0].teid); + GtpuUpdateTunnelOutgoingTeid(getCxt(CUtype, instance)->gtpInst, + f1ap_ue_context_modification_resp->rnti, + (ebi_t)drbs_setupmod_item_p->dRBID, + drb_p->up_dl_tnl[0].teid); + } + } + // SRBs_FailedToBeSetupMod_List + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, + F1AP_ProtocolIE_ID_id_SRBs_FailedToBeSetupMod_List, false); + if(ie!=NULL){ + f1ap_ue_context_modification_resp->srbs_failed_to_be_setup_length = ie->value.choice.SRBs_FailedToBeSetupMod_List.list.count; + f1ap_ue_context_modification_resp->srbs_failed_to_be_setup = calloc(f1ap_ue_context_modification_resp->srbs_failed_to_be_setup_length, + sizeof(f1ap_rb_failed_to_be_setup_t)); + AssertFatal(f1ap_ue_context_modification_resp->srbs_failed_to_be_setup, + "could not allocate memory for f1ap_ue_context_setup_resp->srbs_failed_to_be_setup\n"); + for (i = 0; i < f1ap_ue_context_modification_resp->srbs_failed_to_be_setup_length; ++i) { + f1ap_rb_failed_to_be_setup_t *srb_p = &f1ap_ue_context_modification_resp->srbs_failed_to_be_setup[i]; + srb_p->rb_id = ((F1AP_SRBs_FailedToBeSetupMod_Item_t *)ie->value.choice.SRBs_FailedToBeSetupMod_List.list.array[i])->sRBID; + } + + } + // DRBs_FailedToBeSetupMod_List + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, + F1AP_ProtocolIE_ID_id_DRBs_FailedToBeSetupMod_List, false); + if(ie!=NULL){ + f1ap_ue_context_modification_resp->drbs_failed_to_be_setup_length = ie->value.choice.DRBs_FailedToBeSetupMod_List.list.count; + f1ap_ue_context_modification_resp->drbs_failed_to_be_setup = calloc(f1ap_ue_context_modification_resp->drbs_failed_to_be_setup_length, + sizeof(f1ap_rb_failed_to_be_setup_t)); + AssertFatal(f1ap_ue_context_modification_resp->drbs_failed_to_be_setup, + "could not allocate memory for f1ap_ue_context_setup_resp->drbs_failed_to_be_setup\n"); + for (i = 0; i < f1ap_ue_context_modification_resp->drbs_failed_to_be_setup_length; ++i) { + f1ap_rb_failed_to_be_setup_t *drb_p = &f1ap_ue_context_modification_resp->drbs_failed_to_be_setup[i]; + drb_p->rb_id = ((F1AP_DRBs_FailedToBeSetupMod_Item_t *)ie->value.choice.DRBs_FailedToBeSetupMod_List.list.array[i])->dRBID; + } + } + + // SCell_FailedtoSetupMod_List + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, + F1AP_ProtocolIE_ID_id_SCell_FailedtoSetupMod_List, false); + if(ie!=NULL){ + LOG_E (F1AP, "Not supporting handling of SCell_FailedtoSetupMod_List \n"); + } + + // SRBs_Setup_List + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, + F1AP_ProtocolIE_ID_id_SRBs_SetupMod_List, false); + if(ie!=NULL){ + f1ap_ue_context_modification_resp->srbs_to_be_setup_length = ie->value.choice.SRBs_SetupMod_List.list.count; + f1ap_ue_context_modification_resp->srbs_to_be_setup = calloc(f1ap_ue_context_modification_resp->srbs_to_be_setup_length, + sizeof(f1ap_srb_to_be_setup_t)); + AssertFatal(f1ap_ue_context_modification_resp->srbs_to_be_setup, + "could not allocate memory for f1ap_ue_context_setup_resp->drbs_setup\n"); + for (i = 0; i < f1ap_ue_context_modification_resp->srbs_to_be_setup_length; ++i) { + f1ap_srb_to_be_setup_t *srb_p = &f1ap_ue_context_modification_resp->srbs_to_be_setup[i]; + F1AP_SRBs_SetupMod_Item_t *srbs_setup_item_p; + srbs_setup_item_p = &((F1AP_SRBs_SetupMod_ItemIEs_t *)ie->value.choice.SRBs_SetupMod_List.list.array[i])->value.choice.SRBs_SetupMod_Item; + srb_p->srb_id = srbs_setup_item_p->sRBID; + srb_p->lcid = srbs_setup_item_p->lCID; + } + } + + itti_send_msg_to_task(TASK_RRC_GNB, instance, msg_p); + return 0; } int CU_handle_UE_CONTEXT_MODIFICATION_FAILURE(instance_t instance, diff --git a/openair2/F1AP/f1ap_handlers.c b/openair2/F1AP/f1ap_handlers.c index 6bbf1c796d..0812a976f6 100644 --- a/openair2/F1AP/f1ap_handlers.c +++ b/openair2/F1AP/f1ap_handlers.c @@ -50,7 +50,7 @@ f1ap_message_processing_t f1ap_messages_processing[][3] = { { DU_handle_gNB_CU_CONFIGURATION_UPDATE, CU_handle_gNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE, CU_handle_gNB_CU_CONFIGURATION_UPDATE_FAILURE }, /* gNBCUConfigurationUpdate */ { DU_handle_UE_CONTEXT_SETUP_REQUEST, CU_handle_UE_CONTEXT_SETUP_RESPONSE, 0 }, /* UEContextSetup */ { DU_handle_UE_CONTEXT_RELEASE_COMMAND, CU_handle_UE_CONTEXT_RELEASE_COMPLETE, 0 }, /* UEContextRelease */ - { DU_handle_UE_CONTEXT_MODIFICATION_REQUEST, 0, 0 }, /* UEContextModification */ + { DU_handle_UE_CONTEXT_MODIFICATION_REQUEST, CU_handle_UE_CONTEXT_MODIFICATION_RESPONSE, 0 }, /* UEContextModification */ { 0, 0, 0 }, /* UEContextModificationRequired */ { 0, 0, 0 }, /* UEMobilityCommand */ { CU_handle_UE_CONTEXT_RELEASE_REQUEST, 0, 0 }, /* UEContextReleaseRequest */ diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 92c6fe62d4..30f4ba6f6a 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -3606,6 +3606,10 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, const ch } +static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, const char *msg_name, instance_t instance){ + LOG_I(NR_RRC, "RRC processing of F1 ue_context modification response at the CU is pending \n"); +} + unsigned int mask_flip(unsigned int x) { return((((x>>8) + (x<<8))&0xffff)>>6); } @@ -4108,6 +4112,10 @@ void *rrc_gnb_task(void *args_p) { rrc_CU_process_ue_context_setup_response(msg_p, msg_name_p, instance); break; + case F1AP_UE_CONTEXT_MODIFICATION_RESP: + rrc_CU_process_ue_context_modification_response(msg_p, msg_name_p, instance); + break; + case F1AP_UE_CONTEXT_MODIFICATION_REQ: rrc_DU_process_ue_context_modification_request(msg_p, msg_name_p, instance); break; From e2c88f91afcd8e76a71b6122e9eae12097c3355f Mon Sep 17 00:00:00 2001 From: matzakos Date: Fri, 8 Oct 2021 18:29:39 +0200 Subject: [PATCH 008/267] Trigger dedicated RRC Reconfiguration after processing F1 UE context modification response at RRC layer of the CU -Successful user-plane traffic over F1-U upon completion of UE context modification procedures --- openair2/F1AP/f1ap_cu_ue_context_management.c | 14 +++-- openair2/RRC/NR/rrc_gNB.c | 54 ++++++++++++++++--- 2 files changed, 53 insertions(+), 15 deletions(-) diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index 02cfb80ac7..085367e64f 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -1675,15 +1675,13 @@ int CU_handle_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, // DUtoCURRCInformation F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_DUtoCURRCInformation, true); - if (ie == NULL){ - LOG_E(F1AP,"%s %d: ie is a NULL pointer \n",__FILE__,__LINE__); - return -1; - } - f1ap_ue_context_modification_resp->du_to_cu_rrc_information = (uint8_t *)calloc(1,ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size); + F1AP_ProtocolIE_ID_id_DUtoCURRCInformation, false); + if(ie!=NULL){ + f1ap_ue_context_modification_resp->du_to_cu_rrc_information = (uint8_t *)calloc(1,ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size); - memcpy(f1ap_ue_context_modification_resp->du_to_cu_rrc_information, ie->value.choice.DUtoCURRCInformation.cellGroupConfig.buf, ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size); - f1ap_ue_context_modification_resp->du_to_cu_rrc_information_length = ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size; + memcpy(f1ap_ue_context_modification_resp->du_to_cu_rrc_information, ie->value.choice.DUtoCURRCInformation.cellGroupConfig.buf, ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size); + f1ap_ue_context_modification_resp->du_to_cu_rrc_information_length = ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size; + } // DRBs_SetupMod_List F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 30f4ba6f6a..30dd2e11d2 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -3494,12 +3494,7 @@ static void rrc_DU_process_ue_context_modification_request(MessageDef *msg_p, co fill_mastercellGroupConfig(cellGroupConfig, ue_context_p->ue_context.masterCellGroup, req->srbs_to_be_setup_length>0 ? 1:0, req->drbs_to_be_setup_length>0 ? 1:0); - nr_rrc_rlc_config_asn1_req(&ctxt, - ue_context_p->ue_context.SRB_configList, - ue_context_p->ue_context.DRB_configList, - NULL, - NULL, - get_softmodem_params()->sa ? ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList : NULL); + apply_macrlc_config(rrc, ue_context_p, &ctxt); } if(req->ReconfigComplOutcome == RRCreconf_failure){ LOG_W(NR_RRC, "CU reporting RRC Reconfiguration failure \n"); @@ -3607,7 +3602,52 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, const ch } static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, const char *msg_name, instance_t instance){ - LOG_I(NR_RRC, "RRC processing of F1 ue_context modification response at the CU is pending \n"); + + f1ap_ue_context_setup_t * resp=&F1AP_UE_CONTEXT_SETUP_RESP(msg_p); + protocol_ctxt_t ctxt; + ctxt.rnti = resp->rnti; + ctxt.module_id = instance; + ctxt.instance = instance; + ctxt.enb_flag = 1; + ctxt.eNB_index = instance; + gNB_RRC_INST *rrc = RC.nrrrc[ctxt.module_id]; + struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_get_ue_context(rrc, ctxt.rnti); + NR_CellGroupConfig_t *cellGroupConfig = NULL; + + if(resp->du_to_cu_rrc_information!=NULL){ + asn_dec_rval_t dec_rval = uper_decode_complete( NULL, + &asn_DEF_NR_CellGroupConfig, + (void **)&cellGroupConfig, + (uint8_t *)resp->du_to_cu_rrc_information, + (int) resp->du_to_cu_rrc_information_length); + + if((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { + AssertFatal(1==0,"Cell group config decode error\n"); + // free the memory + SEQUENCE_free( &asn_DEF_NR_CellGroupConfig, cellGroupConfig, 1 ); + return; + } + //xer_fprint(stdout,&asn_DEF_NR_CellGroupConfig, cellGroupConfig); + + if(ue_context_p->ue_context.masterCellGroup == NULL){ + ue_context_p->ue_context.masterCellGroup = calloc(1, sizeof(NR_CellGroupConfig_t)); + } + if(cellGroupConfig->rlc_BearerToAddModList!=NULL){ + if(ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList != NULL){ + LOG_I(NR_RRC, "rlc_BearerToAddModList not empty before filling it \n"); + free(ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList); + } + ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList = calloc(1, sizeof(*cellGroupConfig->rlc_BearerToAddModList)); + memcpy(ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList, cellGroupConfig->rlc_BearerToAddModList, + sizeof(*cellGroupConfig->rlc_BearerToAddModList)); + } + xer_fprint(stdout,&asn_DEF_NR_CellGroupConfig, ue_context_p->ue_context.masterCellGroup); + + rrc_gNB_generate_dedicatedRRCReconfiguration(&ctxt, ue_context_p, cellGroupConfig); + + free(cellGroupConfig->rlc_BearerToAddModList); + free(cellGroupConfig); + } } unsigned int mask_flip(unsigned int x) { From 1a40b36193fb9635a8109c5fb0ac98e96dc76d5b Mon Sep 17 00:00:00 2001 From: matzakos Date: Tue, 12 Oct 2021 19:38:19 +0200 Subject: [PATCH 009/267] Use correct SCTP port number for F1AP according to standards --- openair2/F1AP/f1ap_default_values.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/F1AP/f1ap_default_values.h b/openair2/F1AP/f1ap_default_values.h index 91a1179624..7c64614f50 100644 --- a/openair2/F1AP/f1ap_default_values.h +++ b/openair2/F1AP/f1ap_default_values.h @@ -40,7 +40,7 @@ #define ENB_NAME "Eurecom ENB" #define ENB_NAME_FORMAT (ENB_NAME" %u") -#define F1AP_PORT_NUMBER (30923) +#define F1AP_PORT_NUMBER (38472) #define F1AP_SCTP_PPID (62) #endif /* F1AP_DEFAULT_VALUES_H_ */ From b37195ad1fc66d30f4e140c7ddc3ad9bf37b35da Mon Sep 17 00:00:00 2001 From: matzakos Date: Wed, 13 Oct 2021 14:36:38 +0200 Subject: [PATCH 010/267] Few updates on handling master cell group configuration updates coming from the DU --- openair2/RRC/NR/rrc_gNB.c | 40 ++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index c47131e3e4..2d5b9466f7 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1124,6 +1124,7 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( fill_mastercellGroupConfig(cellGroupConfig, ue_context_pP->ue_context.masterCellGroup,1,1); } else{ + LOG_I(NR_RRC, "Master cell group originating from the DU \n"); cellGroupConfig = cell_groupConfig_from_DU; } size = do_RRCReconfiguration(ctxt_pP, buffer, @@ -3411,8 +3412,8 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha LOG_W(NR_RRC, "No SRB added upon reception of F1 UE Context setup request at the DU\n"); } /* fixme: - * Here we should be probably be encoding to UE ctxt setup response the updates on cellgroupconfig (i.e., cellGroupConfig) - * instead of the whole masterCellGroup configuration stored at the UE context (i.e., ue_context_p->ue_context.masterCellGroup). + * Here we should be encoding the updates on cellgroupconfig. Currently the content of + * celGroupConfig is empty because update_cellGroupConfig() function that is previously called is empty. */ resp->du_to_cu_rrc_information = calloc(1,1024*sizeof(uint8_t)); asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, @@ -3420,6 +3421,10 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha (void *)cellGroupConfig, resp->du_to_cu_rrc_information, 1024); + if (enc_rval.encoded == -1) { + LOG_E(F1AP,"Could not encode ue_context.masterCellGroup, failed element %s\n",enc_rval.failed_type->name); + exit(-1); + } resp->du_to_cu_rrc_information_length = (enc_rval.encoded+7)>>3; free(cellGroupConfig); itti_send_msg_to_task (TASK_DU_F1, ctxt.module_id, message_p); @@ -3582,12 +3587,18 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, const ch } if(cellGroupConfig->rlc_BearerToAddModList!=NULL){ if(ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList != NULL){ - LOG_I(NR_RRC, "rlc_BearerToAddModList not empty before filling it \n"); - free(ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList); + int ue_ctxt_rlc_Bearers = ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList->list.count; + for(int i=ue_ctxt_rlc_Bearers; irlc_BearerToAddModList->list.count; i++){ + ASN_SEQUENCE_ADD(&ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList->list, + cellGroupConfig->rlc_BearerToAddModList->list.array[i-ue_ctxt_rlc_Bearers]); + } } - ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList = calloc(1, sizeof(*cellGroupConfig->rlc_BearerToAddModList)); - memcpy(ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList, cellGroupConfig->rlc_BearerToAddModList, + else{ + LOG_W(NR_RRC, "Empty rlc_BearerToAddModList at ue_context of the CU before filling the updates from UE context setup response \n"); + ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList = calloc(1, sizeof(*cellGroupConfig->rlc_BearerToAddModList)); + memcpy(ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList, cellGroupConfig->rlc_BearerToAddModList, sizeof(*cellGroupConfig->rlc_BearerToAddModList)); + } } xer_fprint(stdout,&asn_DEF_NR_CellGroupConfig, ue_context_p->ue_context.masterCellGroup); @@ -3633,7 +3644,7 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, c if(ue_context_p->ue_context.masterCellGroup == NULL){ ue_context_p->ue_context.masterCellGroup = calloc(1, sizeof(NR_CellGroupConfig_t)); } - if(cellGroupConfig->rlc_BearerToAddModList!=NULL){ + /*if(cellGroupConfig->rlc_BearerToAddModList!=NULL){ if(ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList != NULL){ LOG_I(NR_RRC, "rlc_BearerToAddModList not empty before filling it \n"); free(ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList); @@ -3641,6 +3652,21 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, c ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList = calloc(1, sizeof(*cellGroupConfig->rlc_BearerToAddModList)); memcpy(ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList, cellGroupConfig->rlc_BearerToAddModList, sizeof(*cellGroupConfig->rlc_BearerToAddModList)); + }*/ + if(cellGroupConfig->rlc_BearerToAddModList!=NULL){ + if(ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList != NULL){ + int ue_ctxt_rlc_Bearers = ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList->list.count; + for(int i=ue_ctxt_rlc_Bearers; irlc_BearerToAddModList->list.count; i++){ + ASN_SEQUENCE_ADD(&ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList->list, + cellGroupConfig->rlc_BearerToAddModList->list.array[i-ue_ctxt_rlc_Bearers]); + } + } + else{ + LOG_W(NR_RRC, "Empty rlc_BearerToAddModList at ue_context of the CU before filling the updates from UE context setup response \n"); + ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList = calloc(1, sizeof(*cellGroupConfig->rlc_BearerToAddModList)); + memcpy(ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList, cellGroupConfig->rlc_BearerToAddModList, + sizeof(*cellGroupConfig->rlc_BearerToAddModList)); + } } xer_fprint(stdout,&asn_DEF_NR_CellGroupConfig, ue_context_p->ue_context.masterCellGroup); From 40b131be13c5305cc31b517c3cc205c363a626ee Mon Sep 17 00:00:00 2001 From: matzakos Date: Wed, 13 Oct 2021 16:45:42 +0200 Subject: [PATCH 011/267] Small corrections in F1AP UE context management messages and indentation fixes --- openair2/F1AP/f1ap_cu_ue_context_management.c | 60 ++-- openair2/F1AP/f1ap_du_ue_context_management.c | 331 +++++++++--------- openair2/RRC/NR/rrc_gNB.c | 1 + 3 files changed, 193 insertions(+), 199 deletions(-) diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index 065b0fd57e..2e2ee1e0ac 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -1090,52 +1090,52 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, f1ap_ue_context } /* optional */ - /* c5. CUtoDURRCInformation */ + /* c6. CUtoDURRCInformation */ if (f1ap_ue_context_modification_req->cu_to_du_rrc_information!=NULL) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie5); - ie5->id = F1AP_ProtocolIE_ID_id_CUtoDURRCInformation; - ie5->criticality = F1AP_Criticality_reject; - ie5->value.present = F1AP_UEContextModificationRequestIEs__value_PR_CUtoDURRCInformation; + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie6); + ie6->id = F1AP_ProtocolIE_ID_id_CUtoDURRCInformation; + ie6->criticality = F1AP_Criticality_reject; + ie6->value.present = F1AP_UEContextModificationRequestIEs__value_PR_CUtoDURRCInformation; /* 6.1 cG_ConfigInfo */ if(f1ap_ue_context_modification_req->cu_to_du_rrc_information->cG_ConfigInfo!=NULL){ - const char cG_ConfigInfoStr[]="asdsa1d32sa1d31asd31as"; - asn1cCalloc(ie5->value.choice.CUtoDURRCInformation.cG_ConfigInfo, cG_ConfigInfo); - OCTET_STRING_fromBuf(cG_ConfigInfo, cG_ConfigInfoStr, strlen(cG_ConfigInfoStr)) ; + asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.cG_ConfigInfo, cG_ConfigInfo); + OCTET_STRING_fromBuf(cG_ConfigInfo, (const char *)f1ap_ue_context_modification_req->cu_to_du_rrc_information->cG_ConfigInfo, + f1ap_ue_context_modification_req->cu_to_du_rrc_information->cG_ConfigInfo_length); } /* optional */ /* 6.2 uE_CapabilityRAT_ContainerList */ if(f1ap_ue_context_modification_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList!=NULL){ - asn1cCalloc(ie5->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList, uE_CapabilityRAT_ContainerList ); + asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList, uE_CapabilityRAT_ContainerList ); OCTET_STRING_fromBuf(uE_CapabilityRAT_ContainerList, (const char *)f1ap_ue_context_modification_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, f1ap_ue_context_modification_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length) ; } /* optional */ /* 6.3 measConfig */ if(f1ap_ue_context_modification_req->cu_to_du_rrc_information->measConfig!=NULL){ - const char measConfigStr[]="asdsa1d32sa1d31asd31as"; - asn1cCalloc(ie5->value.choice.CUtoDURRCInformation.measConfig, measConfig); - OCTET_STRING_fromBuf(measConfig, measConfigStr, strlen(measConfigStr)) ; + asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.measConfig, measConfig); + OCTET_STRING_fromBuf(measConfig, (const char *)f1ap_ue_context_modification_req->cu_to_du_rrc_information->measConfig, + f1ap_ue_context_modification_req->cu_to_du_rrc_information->measConfig_length); } } /* optional */ - /* c6. TransmissionActionIndicator */ + /* c7. TransmissionActionIndicator */ if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie6); - ie6->id = F1AP_ProtocolIE_ID_id_TransmissionActionIndicator; - ie6->criticality = F1AP_Criticality_ignore; - ie6->value.present = F1AP_UEContextModificationRequestIEs__value_PR_TransmissionActionIndicator; - ie6->value.choice.TransmissionActionIndicator = F1AP_TransmissionActionIndicator_stop; + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie7); + ie7->id = F1AP_ProtocolIE_ID_id_TransmissionActionIndicator; + ie7->criticality = F1AP_Criticality_ignore; + ie7->value.present = F1AP_UEContextModificationRequestIEs__value_PR_TransmissionActionIndicator; + ie7->value.choice.TransmissionActionIndicator = F1AP_TransmissionActionIndicator_stop; } /* optional */ - /* c7. ResourceCoordinationTransferContainer */ + /* c8. ResourceCoordinationTransferContainer */ if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie7); - ie7->id = F1AP_ProtocolIE_ID_id_ResourceCoordinationTransferContainer; - ie7->criticality = F1AP_Criticality_ignore; - ie7->value.present = F1AP_UEContextModificationRequestIEs__value_PR_ResourceCoordinationTransferContainer; - OCTET_STRING_fromBuf(&ie7->value.choice.ResourceCoordinationTransferContainer, "asdsa1d32sa1d31asd31as", + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie8); + ie8->id = F1AP_ProtocolIE_ID_id_ResourceCoordinationTransferContainer; + ie8->criticality = F1AP_Criticality_ignore; + ie8->value.present = F1AP_UEContextModificationRequestIEs__value_PR_ResourceCoordinationTransferContainer; + OCTET_STRING_fromBuf(&ie8->value.choice.ResourceCoordinationTransferContainer, "asdsa1d32sa1d31asd31as", strlen("asdsa1d32sa1d31asd31as")); } @@ -1152,11 +1152,11 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, f1ap_ue_context /* optional */ /* c8. RRCContainer */ if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie8); - ie8->id = F1AP_ProtocolIE_ID_id_RRCContainer; - ie8->criticality = F1AP_Criticality_ignore; - ie8->value.present = F1AP_UEContextModificationRequestIEs__value_PR_RRCContainer; - OCTET_STRING_fromBuf(&ie8->value.choice.RRCContainer, "asdsa1d32sa1d31asd31as", + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie81); + ie81->id = F1AP_ProtocolIE_ID_id_RRCContainer; + ie81->criticality = F1AP_Criticality_ignore; + ie81->value.present = F1AP_UEContextModificationRequestIEs__value_PR_RRCContainer; + OCTET_STRING_fromBuf(&ie81->value.choice.RRCContainer, "asdsa1d32sa1d31asd31as", strlen("asdsa1d32sa1d31asd31as")); } @@ -1661,7 +1661,7 @@ int CU_handle_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, /* GNB_CU_UE_F1AP_ID */ F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, false); + F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); f1ap_ue_context_modification_resp->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID; LOG_D(F1AP, "f1ap_ue_context_setup_resp->gNB_CU_ue_id is: %d \n", f1ap_ue_context_modification_resp->gNB_CU_ue_id); diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index e0ff41d71e..ce47fec196 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -970,20 +970,20 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, for (i = 0; i < f1ap_ue_context_modification_req->drbs_to_be_setup_length; ++i) { f1ap_drb_to_be_setup_t *drb_p = &f1ap_ue_context_modification_req->drbs_to_be_setup[i]; - F1AP_DRBs_ToBeSetup_Item_t *drbs_tobesetup_item_p = - &((F1AP_DRBs_ToBeSetup_ItemIEs_t *)ieDrb->value.choice.DRBs_ToBeSetupMod_List.list.array[i])->value.choice.DRBs_ToBeSetup_Item; - drb_p->drb_id = drbs_tobesetup_item_p->dRBID; + F1AP_DRBs_ToBeSetupMod_Item_t *drbs_tobesetupmod_item_p = + &((F1AP_DRBs_ToBeSetupMod_ItemIEs_t *)ieDrb->value.choice.DRBs_ToBeSetupMod_List.list.array[i])->value.choice.DRBs_ToBeSetupMod_Item; + drb_p->drb_id = drbs_tobesetupmod_item_p->dRBID; /* TODO in the following, assume only one UP UL TNL is present. * this matches/assumes OAI CU implementation, can be up to 2! */ drb_p->up_ul_tnl_length = 1; - AssertFatal(drbs_tobesetup_item_p->uLUPTNLInformation_ToBeSetup_List.list.count > 0, + AssertFatal(drbs_tobesetupmod_item_p->uLUPTNLInformation_ToBeSetup_List.list.count > 0, "no UL UP TNL Information in DRBs to be Setup list\n"); - F1AP_ULUPTNLInformation_ToBeSetup_Item_t *ul_up_tnl_info_p = (F1AP_ULUPTNLInformation_ToBeSetup_Item_t *)drbs_tobesetup_item_p->uLUPTNLInformation_ToBeSetup_List.list.array[0]; + F1AP_ULUPTNLInformation_ToBeSetup_Item_t *ul_up_tnl_info_p = (F1AP_ULUPTNLInformation_ToBeSetup_Item_t *)drbs_tobesetupmod_item_p->uLUPTNLInformation_ToBeSetup_List.list.array[0]; F1AP_GTPTunnel_t *ul_up_tnl0 = ul_up_tnl_info_p->uLUPTNLInformation.choice.gTPTunnel; BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&ul_up_tnl0->transportLayerAddress, drb_p->up_ul_tnl[0].tl_address); OCTET_STRING_TO_INT32(&ul_up_tnl0->gTP_TEID, drb_p->up_ul_tnl[0].teid); - switch (drbs_tobesetup_item_p->rLCMode) { + switch (drbs_tobesetupmod_item_p->rLCMode) { case F1AP_RLCMode_rlc_am: drb_p->rlc_mode = RLC_MODE_AM; break; @@ -1042,8 +1042,9 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, //FIXME //rnti_t rnti = f1ap_get_rnti_by_du_id(DUtype, instance, du_ue_f1ap_id); ctxt.instance = instance; - ctxt.instance = instance; + ctxt.module_id = instance; ctxt.enb_flag = 1; + ctxt.eNB_index = instance; mem_block_t *pdcp_pdu_p = get_free_mem_block(ieRRC->value.choice.RRCContainer.size, __func__); memcpy(&pdcp_pdu_p->data[0], ieRRC->value.choice.RRCContainer.buf, ieRRC->value.choice.RRCContainer.size); du_rlc_data_req(&ctxt, 1, 0x00, 1, 1, 0, ieRRC->value.choice.RRCContainer.size, pdcp_pdu_p); @@ -1099,7 +1100,7 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, f1ap_ue_contex } /* mandatory */ - /* c3. DUtoCURRCInformation */ + /* c4. DUtoCURRCInformation */ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie4); ie4->id = F1AP_ProtocolIE_ID_id_DUtoCURRCInformation; ie4->criticality = F1AP_Criticality_reject; @@ -1127,185 +1128,177 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, f1ap_ue_contex /* optional */ /* c5. DRBs_Setup_List */ - if(resp->drbs_to_be_setup_length > 0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie5); - ie5->id = F1AP_ProtocolIE_ID_id_DRBs_SetupMod_List; - ie5->criticality = F1AP_Criticality_ignore; - ie5->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DRBs_SetupMod_List; - for (int i=0; i< resp->drbs_to_be_setup_length; i++) { - // - asn1cSequenceAdd(ie5->value.choice.DRBs_SetupMod_List.list, - F1AP_DRBs_SetupMod_ItemIEs_t, drbs_setupmod_item_ies); - drbs_setupmod_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_SetupMod_Item; - drbs_setupmod_item_ies->criticality = F1AP_Criticality_ignore; - drbs_setupmod_item_ies->value.present = F1AP_DRBs_SetupMod_ItemIEs__value_PR_DRBs_SetupMod_Item; - /* 7.1 DRBs_Setup_Item */ - /* ADD */ - F1AP_DRBs_SetupMod_Item_t *drbs_setupmod_item=&drbs_setupmod_item_ies->value.choice.DRBs_SetupMod_Item; - /* dRBID */ - drbs_setupmod_item->dRBID = resp->drbs_to_be_setup[i].drb_id; - - /* OPTIONAL */ - /* lCID */ - //drbs_setup_item.lCID = (F1AP_LCID_t *)calloc(1, sizeof(F1AP_LCID_t)); - //drbs_setup_item.lCID = 1L; - - for (int j=0; jdrbs_to_be_setup[i].up_dl_tnl_length; j++) { + if(resp->drbs_to_be_setup_length > 0) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie5); + ie5->id = F1AP_ProtocolIE_ID_id_DRBs_SetupMod_List; + ie5->criticality = F1AP_Criticality_ignore; + ie5->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DRBs_SetupMod_List; + for (int i=0; i< resp->drbs_to_be_setup_length; i++) { + asn1cSequenceAdd(ie5->value.choice.DRBs_SetupMod_List.list, F1AP_DRBs_SetupMod_ItemIEs_t, drbs_setupmod_item_ies); + drbs_setupmod_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_SetupMod_Item; + drbs_setupmod_item_ies->criticality = F1AP_Criticality_ignore; + drbs_setupmod_item_ies->value.present = F1AP_DRBs_SetupMod_ItemIEs__value_PR_DRBs_SetupMod_Item; + /* 7.1 DRBs_Setup_Item */ /* ADD */ - asn1cSequenceAdd(drbs_setupmod_item->dLUPTNLInformation_ToBeSetup_List.list, - F1AP_DLUPTNLInformation_ToBeSetup_Item_t, dLUPTNLInformation_ToBeSetup_Item); - dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; - /* gTPTunnel */ - asn1cCalloc(dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.choice.gTPTunnel,gTPTunnel); - /* transportLayerAddress */ - struct sockaddr_in addr= {0}; - inet_pton(AF_INET, getCxt(false,instance)->setupReq.DU_f1_ip_address.ipv4_address, - &addr.sin_addr.s_addr); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(addr.sin_addr.s_addr, + F1AP_DRBs_SetupMod_Item_t *drbs_setupmod_item=&drbs_setupmod_item_ies->value.choice.DRBs_SetupMod_Item; + /* dRBID */ + drbs_setupmod_item->dRBID = resp->drbs_to_be_setup[i].drb_id; + + /* OPTIONAL */ + /* lCID */ + //drbs_setup_item.lCID = (F1AP_LCID_t *)calloc(1, sizeof(F1AP_LCID_t)); + //drbs_setup_item.lCID = 1L; + + for (int j=0; jdrbs_to_be_setup[i].up_dl_tnl_length; j++) { + /* ADD */ + asn1cSequenceAdd(drbs_setupmod_item->dLUPTNLInformation_ToBeSetup_List.list, + F1AP_DLUPTNLInformation_ToBeSetup_Item_t, dLUPTNLInformation_ToBeSetup_Item); + dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; + /* gTPTunnel */ + asn1cCalloc(dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.choice.gTPTunnel,gTPTunnel); + /* transportLayerAddress */ + struct sockaddr_in addr= {0}; + inet_pton(AF_INET, getCxt(false,instance)->setupReq.DU_f1_ip_address.ipv4_address, + &addr.sin_addr.s_addr); + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(addr.sin_addr.s_addr, &gTPTunnel->transportLayerAddress); - /* gTP_TEID */ - INT32_TO_OCTET_STRING(resp->drbs_to_be_setup[i].up_dl_tnl[j].teid, &gTPTunnel->gTP_TEID); - } // for j - } // for i + /* gTP_TEID */ + INT32_TO_OCTET_STRING(resp->drbs_to_be_setup[i].up_dl_tnl[j].teid, &gTPTunnel->gTP_TEID); + } // for j + } // for i } /* optional */ /* c6. DRBs_Modified_List */ if(0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie6); - ie6->id = F1AP_ProtocolIE_ID_id_DRBs_Modified_List; - ie6->criticality = F1AP_Criticality_reject; - ie6->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DRBs_Modified_List; + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie6); + ie6->id = F1AP_ProtocolIE_ID_id_DRBs_Modified_List; + ie6->criticality = F1AP_Criticality_reject; + ie6->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DRBs_Modified_List; - for (int i=0; i<1; i++) { - // - asn1cSequenceAdd(ie6->value.choice.DRBs_Modified_List.list, - F1AP_DRBs_Modified_ItemIEs_t, drbs_modified_item_ies); - drbs_modified_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_Modified_Item; - drbs_modified_item_ies->criticality = F1AP_Criticality_reject; - drbs_modified_item_ies->value.present = F1AP_DRBs_Modified_ItemIEs__value_PR_DRBs_Modified_Item; - /* 13.1 SRBs_modified_Item */ - F1AP_DRBs_Modified_Item_t *drbs_modified_item= - &drbs_modified_item_ies->value.choice.DRBs_Modified_Item; - /* dRBID */ - drbs_modified_item->dRBID = 25L; - /* ULTunnels_Modified_List */ - int maxnoofULTunnels = 1; // 2; + for (int i=0; i<1; i++) { + asn1cSequenceAdd(ie6->value.choice.DRBs_Modified_List.list, + F1AP_DRBs_Modified_ItemIEs_t, drbs_modified_item_ies); + drbs_modified_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_Modified_Item; + drbs_modified_item_ies->criticality = F1AP_Criticality_reject; + drbs_modified_item_ies->value.present = F1AP_DRBs_Modified_ItemIEs__value_PR_DRBs_Modified_Item; + /* DRBs_modified_Item */ + F1AP_DRBs_Modified_Item_t *drbs_modified_item= &drbs_modified_item_ies->value.choice.DRBs_Modified_Item; + /* dRBID */ + drbs_modified_item->dRBID = 25L; + /* ULTunnels_Modified_List */ + int maxnoofULTunnels = 1; // 2; - for (int j=0; jdLUPTNLInformation_ToBeSetup_List.list, - F1AP_DLUPTNLInformation_ToBeSetup_Item_t, dLUPTNLInformation_ToBeSetup_Item); - asn1cCalloc(dLUPTNLInformation_ToBeSetup_Item, tmp); - tmp->dLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; - asn1cCalloc(dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.choice.gTPTunnel, gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(1234, &gTPTunnel->transportLayerAddress); - OCTET_STRING_fromBuf(&gTPTunnel->gTP_TEID, "1204", strlen("1204")); + for (int j=0; jdLUPTNLInformation_ToBeSetup_List.list, + F1AP_DLUPTNLInformation_ToBeSetup_Item_t, dLUPTNLInformation_ToBeSetup_Item); + asn1cCalloc(dLUPTNLInformation_ToBeSetup_Item, tmp); + tmp->dLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; + asn1cCalloc(dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.choice.gTPTunnel, gTPTunnel); + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(1234, &gTPTunnel->transportLayerAddress); + OCTET_STRING_fromBuf(&gTPTunnel->gTP_TEID, "1204", strlen("1204")); + } } } - } /* optional */ /* c7. SRBs_FailedToBeSetupMod_List */ if(0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie7); - ie7->id = F1AP_ProtocolIE_ID_id_SRBs_FailedToBeSetupMod_List; - ie7->criticality = F1AP_Criticality_reject; - ie7->value.present = F1AP_UEContextModificationResponseIEs__value_PR_SRBs_FailedToBeSetupMod_List; + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie7); + ie7->id = F1AP_ProtocolIE_ID_id_SRBs_FailedToBeSetupMod_List; + ie7->criticality = F1AP_Criticality_reject; + ie7->value.present = F1AP_UEContextModificationResponseIEs__value_PR_SRBs_FailedToBeSetupMod_List; - for (int i=0; i<1; i++) { - // - asn1cSequenceAdd(ie7->value.choice.SRBs_FailedToBeSetupMod_List.list, - F1AP_SRBs_FailedToBeSetupMod_ItemIEs_t, srbs_failedToBeSetupMod_item_ies); - srbs_failedToBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_FailedToBeSetupMod_Item; - srbs_failedToBeSetupMod_item_ies->criticality = F1AP_Criticality_ignore; - srbs_failedToBeSetupMod_item_ies->value.present = F1AP_SRBs_FailedToBeSetupMod_ItemIEs__value_PR_SRBs_FailedToBeSetupMod_Item; - /* 9.1 SRBs_FailedToBeSetupMod_Item */ - F1AP_SRBs_FailedToBeSetupMod_Item_t *srbs_failedToBeSetupMod_item= - &srbs_failedToBeSetupMod_item_ies->value.choice.SRBs_FailedToBeSetupMod_Item; - /* - sRBID */ - srbs_failedToBeSetupMod_item->sRBID = 50L; - asn1cCalloc(srbs_failedToBeSetupMod_item->cause, tmp) - tmp->present = F1AP_Cause_PR_radioNetwork; - tmp->choice.radioNetwork = F1AP_CauseRadioNetwork_unknown_or_already_allocated_gnb_du_ue_f1ap_id; - } + for (int i=0; i<1; i++) { + asn1cSequenceAdd(ie7->value.choice.SRBs_FailedToBeSetupMod_List.list, + F1AP_SRBs_FailedToBeSetupMod_ItemIEs_t, srbs_failedToBeSetupMod_item_ies); + srbs_failedToBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_FailedToBeSetupMod_Item; + srbs_failedToBeSetupMod_item_ies->criticality = F1AP_Criticality_ignore; + srbs_failedToBeSetupMod_item_ies->value.present = F1AP_SRBs_FailedToBeSetupMod_ItemIEs__value_PR_SRBs_FailedToBeSetupMod_Item; + /* 9.1 SRBs_FailedToBeSetupMod_Item */ + F1AP_SRBs_FailedToBeSetupMod_Item_t *srbs_failedToBeSetupMod_item= + &srbs_failedToBeSetupMod_item_ies->value.choice.SRBs_FailedToBeSetupMod_Item; + /* - sRBID */ + srbs_failedToBeSetupMod_item->sRBID = 50L; + asn1cCalloc(srbs_failedToBeSetupMod_item->cause, tmp) + tmp->present = F1AP_Cause_PR_radioNetwork; + tmp->choice.radioNetwork = F1AP_CauseRadioNetwork_unknown_or_already_allocated_gnb_du_ue_f1ap_id; + } } /* optional */ /* c8. DRBs_FailedToBeSetupMod_List */ if(0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie8); - ie8->id = F1AP_ProtocolIE_ID_id_DRBs_FailedToBeSetupMod_List; - ie8->criticality = F1AP_Criticality_reject; - ie8->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DRBs_FailedToBeSetupMod_List; + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie8); + ie8->id = F1AP_ProtocolIE_ID_id_DRBs_FailedToBeSetupMod_List; + ie8->criticality = F1AP_Criticality_reject; + ie8->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DRBs_FailedToBeSetupMod_List; - for (int i=0; i<1; i++) { - // - asn1cSequenceAdd(ie8->value.choice.DRBs_FailedToBeSetupMod_List.list, - F1AP_DRBs_FailedToBeSetupMod_ItemIEs_t, drbs_failedToBeSetupMod_item_ies); - drbs_failedToBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_FailedToBeSetupMod_Item; - drbs_failedToBeSetupMod_item_ies->criticality = F1AP_Criticality_reject; - drbs_failedToBeSetupMod_item_ies->value.present = F1AP_DRBs_FailedToBeSetupMod_ItemIEs__value_PR_DRBs_FailedToBeSetupMod_Item; - /* 10.1 DRBs_ToBeSetupMod_Item */ - F1AP_DRBs_FailedToBeSetupMod_Item_t *drbs_failedToBeSetupMod_item= - &drbs_failedToBeSetupMod_item_ies->value.choice.DRBs_FailedToBeSetupMod_Item; - /* dRBID */ - drbs_failedToBeSetupMod_item->dRBID = 30L; - drbs_failedToBeSetupMod_item->cause = (F1AP_Cause_t *)calloc(1, sizeof(F1AP_Cause_t)); - drbs_failedToBeSetupMod_item->cause->present = F1AP_Cause_PR_radioNetwork; - drbs_failedToBeSetupMod_item->cause->choice.radioNetwork = F1AP_CauseRadioNetwork_unknown_or_already_allocated_gnb_du_ue_f1ap_id; - } + for (int i=0; i<1; i++) { + asn1cSequenceAdd(ie8->value.choice.DRBs_FailedToBeSetupMod_List.list, + F1AP_DRBs_FailedToBeSetupMod_ItemIEs_t, drbs_failedToBeSetupMod_item_ies); + drbs_failedToBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_FailedToBeSetupMod_Item; + drbs_failedToBeSetupMod_item_ies->criticality = F1AP_Criticality_reject; + drbs_failedToBeSetupMod_item_ies->value.present = F1AP_DRBs_FailedToBeSetupMod_ItemIEs__value_PR_DRBs_FailedToBeSetupMod_Item; + /* DRBs_FailedToBeSetupMod_Item */ + F1AP_DRBs_FailedToBeSetupMod_Item_t *drbs_failedToBeSetupMod_item= + &drbs_failedToBeSetupMod_item_ies->value.choice.DRBs_FailedToBeSetupMod_Item; + /* dRBID */ + drbs_failedToBeSetupMod_item->dRBID = 30L; + drbs_failedToBeSetupMod_item->cause = (F1AP_Cause_t *)calloc(1, sizeof(F1AP_Cause_t)); + drbs_failedToBeSetupMod_item->cause->present = F1AP_Cause_PR_radioNetwork; + drbs_failedToBeSetupMod_item->cause->choice.radioNetwork = F1AP_CauseRadioNetwork_unknown_or_already_allocated_gnb_du_ue_f1ap_id; + } } /* optional */ /* c9. SCell_FailedtoSetupMod_List */ if(0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie9); - ie9->id = F1AP_ProtocolIE_ID_id_SCell_FailedtoSetupMod_List; - ie9->criticality = F1AP_Criticality_ignore; - ie9->value.present = F1AP_UEContextModificationResponseIEs__value_PR_SCell_FailedtoSetupMod_List; + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie9); + ie9->id = F1AP_ProtocolIE_ID_id_SCell_FailedtoSetupMod_List; + ie9->criticality = F1AP_Criticality_ignore; + ie9->value.present = F1AP_UEContextModificationResponseIEs__value_PR_SCell_FailedtoSetupMod_List; - for (int i=0; i<1; i++) { - // - asn1cSequenceAdd(ie9->value.choice.SCell_FailedtoSetupMod_List.list, - F1AP_SCell_FailedtoSetupMod_ItemIEs_t, scell_failedtoSetupMod_item_ies); - scell_failedtoSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_SCell_FailedtoSetupMod_Item; - scell_failedtoSetupMod_item_ies->criticality = F1AP_Criticality_ignore; - scell_failedtoSetupMod_item_ies->value.present = F1AP_SCell_FailedtoSetupMod_ItemIEs__value_PR_SCell_FailedtoSetupMod_Item; - /* 8.1 SCell_ToBeSetup_Item */ - F1AP_SCell_FailedtoSetupMod_Item_t *scell_failedtoSetupMod_item=&scell_failedtoSetupMod_item_ies->value.choice.SCell_FailedtoSetupMod_Item; - /* - sCell_ID */ - addnRCGI(scell_failedtoSetupMod_item->sCell_ID, &f1ap_req(false, instance)->cell[i]); - asn1cCalloc(scell_failedtoSetupMod_item->cause, tmp); - tmp->present = F1AP_Cause_PR_radioNetwork; - tmp->choice.radioNetwork = F1AP_CauseRadioNetwork_unknown_or_already_allocated_gnb_du_ue_f1ap_id; - } + for (int i=0; i<1; i++) { + asn1cSequenceAdd(ie9->value.choice.SCell_FailedtoSetupMod_List.list, + F1AP_SCell_FailedtoSetupMod_ItemIEs_t, scell_failedtoSetupMod_item_ies); + scell_failedtoSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_SCell_FailedtoSetupMod_Item; + scell_failedtoSetupMod_item_ies->criticality = F1AP_Criticality_ignore; + scell_failedtoSetupMod_item_ies->value.present = F1AP_SCell_FailedtoSetupMod_ItemIEs__value_PR_SCell_FailedtoSetupMod_Item; + /* 8.1 SCell_ToBeSetup_Item */ + F1AP_SCell_FailedtoSetupMod_Item_t *scell_failedtoSetupMod_item=&scell_failedtoSetupMod_item_ies->value.choice.SCell_FailedtoSetupMod_Item; + /* - sCell_ID */ + addnRCGI(scell_failedtoSetupMod_item->sCell_ID, &f1ap_req(false, instance)->cell[i]); + asn1cCalloc(scell_failedtoSetupMod_item->cause, tmp); + tmp->present = F1AP_Cause_PR_radioNetwork; + tmp->choice.radioNetwork = F1AP_CauseRadioNetwork_unknown_or_already_allocated_gnb_du_ue_f1ap_id; + } } /* optional */ /* c10. DRBs_FailedToBeModified_List */ if(0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie10); - ie10->id = F1AP_ProtocolIE_ID_id_DRBs_FailedToBeModified_List; - ie10->criticality = F1AP_Criticality_reject; - ie10->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DRBs_FailedToBeModified_List; + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie10); + ie10->id = F1AP_ProtocolIE_ID_id_DRBs_FailedToBeModified_List; + ie10->criticality = F1AP_Criticality_reject; + ie10->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DRBs_FailedToBeModified_List; - for (int i=0; i<1; i++) { - // - asn1cSequenceAdd(ie10->value.choice.DRBs_FailedToBeModified_List.list, - F1AP_DRBs_FailedToBeModified_ItemIEs_t, drbs_failedToBeModified_item_ies); - drbs_failedToBeModified_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_FailedToBeModified_Item; - drbs_failedToBeModified_item_ies->criticality = F1AP_Criticality_reject; - drbs_failedToBeModified_item_ies->value.present = F1AP_DRBs_FailedToBeModified_ItemIEs__value_PR_DRBs_FailedToBeModified_Item; - /* 13.1 DRBs_FailedToBeModified_Item */ - F1AP_DRBs_FailedToBeModified_Item_t *drbs_failedToBeModified_item= - &drbs_failedToBeModified_item_ies->value.choice.DRBs_FailedToBeModified_Item ; - /* dRBID */ - drbs_failedToBeModified_item->dRBID = 30L; - asn1cCalloc(drbs_failedToBeModified_item->cause, tmp); - tmp->present = F1AP_Cause_PR_radioNetwork; - tmp->choice.radioNetwork = F1AP_CauseRadioNetwork_unknown_or_already_allocated_gnb_du_ue_f1ap_id; - } + for (int i=0; i<1; i++) { + asn1cSequenceAdd(ie10->value.choice.DRBs_FailedToBeModified_List.list, + F1AP_DRBs_FailedToBeModified_ItemIEs_t, drbs_failedToBeModified_item_ies); + drbs_failedToBeModified_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_FailedToBeModified_Item; + drbs_failedToBeModified_item_ies->criticality = F1AP_Criticality_reject; + drbs_failedToBeModified_item_ies->value.present = F1AP_DRBs_FailedToBeModified_ItemIEs__value_PR_DRBs_FailedToBeModified_Item; + /* 13.1 DRBs_FailedToBeModified_Item */ + F1AP_DRBs_FailedToBeModified_Item_t *drbs_failedToBeModified_item= + &drbs_failedToBeModified_item_ies->value.choice.DRBs_FailedToBeModified_Item ; + /* dRBID */ + drbs_failedToBeModified_item->dRBID = 30L; + asn1cCalloc(drbs_failedToBeModified_item->cause, tmp); + tmp->present = F1AP_Cause_PR_radioNetwork; + tmp->choice.radioNetwork = F1AP_CauseRadioNetwork_unknown_or_already_allocated_gnb_du_ue_f1ap_id; + } } // /* */ @@ -1359,24 +1352,24 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, f1ap_ue_contex /* optional */ /* c12. SRBs_Setup_List */ if(resp->srbs_to_be_setup_length > 0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie12); - ie12->id = F1AP_ProtocolIE_ID_id_SRBs_SetupMod_List; - ie12->criticality = F1AP_Criticality_ignore; - ie12->value.present = F1AP_UEContextModificationResponseIEs__value_PR_SRBs_SetupMod_List; + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie12); + ie12->id = F1AP_ProtocolIE_ID_id_SRBs_SetupMod_List; + ie12->criticality = F1AP_Criticality_ignore; + ie12->value.present = F1AP_UEContextModificationResponseIEs__value_PR_SRBs_SetupMod_List; - for (int i=0; i< resp->srbs_to_be_setup_length; i++) {// - asn1cSequenceAdd(ie12->value.choice.SRBs_SetupMod_List.list, + for (int i=0; i< resp->srbs_to_be_setup_length; i++) {// + asn1cSequenceAdd(ie12->value.choice.SRBs_SetupMod_List.list, F1AP_SRBs_SetupMod_ItemIEs_t, srbs_setupmod_item_ies); - srbs_setupmod_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_SetupMod_Item; - srbs_setupmod_item_ies->criticality = F1AP_Criticality_ignore; - srbs_setupmod_item_ies->value.present = F1AP_SRBs_SetupMod_ItemIEs__value_PR_SRBs_SetupMod_Item; - /* 11.1 SRBs_Setup_Item */ - /* ADD */ - F1AP_SRBs_SetupMod_Item_t *srbs_setupmod_item=&srbs_setupmod_item_ies->value.choice.SRBs_SetupMod_Item; - /* sRBID */ - srbs_setupmod_item->sRBID = resp->srbs_to_be_setup[i].srb_id; - srbs_setupmod_item->lCID = resp->srbs_to_be_setup[i].srb_id; - } + srbs_setupmod_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_SetupMod_Item; + srbs_setupmod_item_ies->criticality = F1AP_Criticality_ignore; + srbs_setupmod_item_ies->value.present = F1AP_SRBs_SetupMod_ItemIEs__value_PR_SRBs_SetupMod_Item; + /* 11.1 SRBs_Setup_Item */ + /* ADD */ + F1AP_SRBs_SetupMod_Item_t *srbs_setupmod_item=&srbs_setupmod_item_ies->value.choice.SRBs_SetupMod_Item; + /* sRBID */ + srbs_setupmod_item->sRBID = resp->srbs_to_be_setup[i].srb_id; + srbs_setupmod_item->lCID = resp->srbs_to_be_setup[i].srb_id; + } } /* encode */ diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 2d5b9466f7..d4e1ff8941 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -3668,6 +3668,7 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, c sizeof(*cellGroupConfig->rlc_BearerToAddModList)); } } + LOG_I(NR_RRC, "Updated master cell group configuration stored at the UE context of the CU:\n"); xer_fprint(stdout,&asn_DEF_NR_CellGroupConfig, ue_context_p->ue_context.masterCellGroup); rrc_gNB_generate_dedicatedRRCReconfiguration(&ctxt, ue_context_p, cellGroupConfig); From 85faedfcbe2f74173246af6fa464d764ae939c03 Mon Sep 17 00:00:00 2001 From: matzakos Date: Mon, 18 Oct 2021 18:32:57 +0200 Subject: [PATCH 012/267] Add triggering of F1 UE Context release command -Add also a temporary artificial trigger just to be able to test with OAI UE -Comment out most of the part of the UE context release command handler function at the DU in order to separate properly the RRC from F1AP functionality later. --- openair2/F1AP/f1ap_cu_ue_context_management.c | 12 +++--- openair2/F1AP/f1ap_du_ue_context_management.c | 22 +++++----- openair2/RRC/NR/rrc_gNB.c | 40 +++++++++++++++---- 3 files changed, 50 insertions(+), 24 deletions(-) diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index 2e2ee1e0ac..141d89ac51 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -907,12 +907,14 @@ int CU_send_UE_CONTEXT_RELEASE_COMMAND(instance_t instance, /* optional */ /* c4. RRCContainer */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie4); - ie4->id = F1AP_ProtocolIE_ID_id_RRCContainer; - ie4->criticality = F1AP_Criticality_ignore; - ie4->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_RRCContainer; - OCTET_STRING_fromBuf(&ie4->value.choice.RRCContainer, (const char *)cmd->rrc_container, + if(cmd->rrc_container!=NULL){ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie4); + ie4->id = F1AP_ProtocolIE_ID_id_RRCContainer; + ie4->criticality = F1AP_Criticality_ignore; + ie4->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_RRCContainer; + OCTET_STRING_fromBuf(&ie4->value.choice.RRCContainer, (const char *)cmd->rrc_container, cmd->rrc_container_length); + } /* encode */ if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index ce47fec196..77f8b9d046 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -683,14 +683,14 @@ int DU_handle_UE_CONTEXT_RELEASE_COMMAND(instance_t instance, protocol_ctxt_t ctxt; DevAssert(pdu); container = &pdu->choice.initiatingMessage->value.choice.UEContextReleaseCommand; - /* GNB_CU_UE_F1AP_ID */ + // GNB_CU_UE_F1AP_ID F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseCommandIEs_t, ie, container, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); ctxt.rnti = f1ap_get_rnti_by_cu_id(DUtype, instance, ie->value.choice.GNB_CU_UE_F1AP_ID); ctxt.instance = instance; ctxt.module_id = instance; ctxt.enb_flag = 1; - /* GNB_DU_UE_F1AP_ID */ + // GNB_DU_UE_F1AP_ID F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseCommandIEs_t, ie, container, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); const rnti_t rnti = f1ap_get_rnti_by_du_id(DUtype, instance, @@ -700,7 +700,7 @@ int DU_handle_UE_CONTEXT_RELEASE_COMMAND(instance_t instance, rnti, ctxt.rnti); int UE_out_of_sync = 0; - if (RC.nrrrc && RC.nrrrc[instance]->node_type == ngran_gNB_DU) { + /*if (RC.nrrrc && RC.nrrrc[instance]->node_type == ngran_gNB_DU) { for (int n = 0; n < MAX_MOBILES_PER_GNB; ++n) { if (RC.nrmac[instance]->UE_info.active[n] == TRUE && rnti == RC.nrmac[instance]->UE_info.rnti[n]) { @@ -718,13 +718,13 @@ int DU_handle_UE_CONTEXT_RELEASE_COMMAND(instance_t instance, } } - /* We don't need the Cause */ - /* Optional RRC Container: if present, send to UE */ + // We don't need the Cause + // Optional RRC Container: if present, send to UE F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseCommandIEs_t, ie, container, F1AP_ProtocolIE_ID_id_RRCContainer, false); if (ie && !UE_out_of_sync) { - /* RRC message and UE is reachable, send message */ + // RRC message and UE is reachable, send message const sdu_size_t sdu_len = ie->value.choice.RRCContainer.size; mem_block_t *pdu_p = NULL; pdu_p = get_free_mem_block(sdu_len, __func__); @@ -775,8 +775,8 @@ int DU_handle_UE_CONTEXT_RELEASE_COMMAND(instance_t instance, ue_context_p = rrc_eNB_get_ue_context(RC.rrc[ctxt.instance], ctxt.rnti); if (ue_context_p && !UE_out_of_sync) { - /* UE exists and is in sync so we start a timer before releasing the - * connection */ + // UE exists and is in sync so we start a timer before releasing the + // connection pthread_mutex_lock(&rrc_release_freelist); for (uint16_t release_num = 0; release_num < NUMBER_OF_UE_MAX; release_num++) { @@ -800,18 +800,18 @@ int DU_handle_UE_CONTEXT_RELEASE_COMMAND(instance_t instance, pthread_mutex_unlock(&rrc_release_freelist); ue_context_p->ue_context.ue_release_timer_s1 = 0; } else if (ue_context_p && UE_out_of_sync) { - /* UE exists and is out of sync, drop the connection */ + // UE exists and is out of sync, drop the connection mac_eNB_rrc_ul_failure(instance, 0, 0, 0, rnti); } else { LOG_E(F1AP, "no ue_context for RNTI %x, acknowledging release\n", rnti); } - /* TODO send this once the connection has really been released */ + // TODO send this once the connection has really been released f1ap_ue_context_release_cplt_t cplt; cplt.rnti = ctxt.rnti; DU_send_UE_CONTEXT_RELEASE_COMPLETE(instance, &cplt); return 0; - } + }*/ } int DU_send_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, f1ap_ue_context_release_cplt_t *cplt) { diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index d4e1ff8941..a18b267ec6 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1515,6 +1515,18 @@ rrc_gNB_process_RRCReconfigurationComplete( free(DRB_Release_configList2); ue_context_pP->ue_context.DRB_Release_configList2[xid] = NULL; } + //Temporarily trigger artificially UE context release for the CU case just to be able to test it with OAI UE. To be removed later + if(0){ + if(NODE_IS_CU(RC.nrrrc[ctxt_pP->instance]->node_type)){ + MessageDef *message_p; + message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, F1AP_UE_CONTEXT_RELEASE_CMD); + f1ap_ue_context_release_cmd_t *rel_cmd=&F1AP_UE_CONTEXT_RELEASE_CMD (message_p); + rel_cmd->rnti = ctxt_pP->rnti; + rel_cmd->cause = F1AP_CAUSE_RADIO_NETWORK; + rel_cmd->cause_value = 10; // 10 = F1AP_CauseRadioNetwork_normal_release + itti_send_msg_to_task(TASK_CU_F1, ctxt_pP->module_id, message_p); + } + } } //----------------------------------------------------------------------------- @@ -3925,15 +3937,27 @@ void nr_rrc_subframe_process(protocol_ctxt_t *const ctxt_pP, const int CC_id) { // Remove here the MAC and RRC context when RRC is not connected or gNB is not connected to CN5G if(ue_context_p->ue_context.StatusRrc < NR_RRC_CONNECTED || ue_context_p->ue_context.gNB_ue_ngap_id == 0) { - mac_remove_nr_ue(ctxt_pP->module_id, ctxt_pP->rnti); - rrc_rlc_remove_ue(ctxt_pP); - pdcp_remove_UE(ctxt_pP); + if(!NODE_IS_CU(RC.nrrrc[ctxt_pP->instance]->node_type)){ + mac_remove_nr_ue(ctxt_pP->module_id, ctxt_pP->rnti); + rrc_rlc_remove_ue(ctxt_pP); + pdcp_remove_UE(ctxt_pP); - /* remove RRC UE Context */ - ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[ctxt_pP->module_id], ctxt_pP->rnti); - if (ue_context_p) { - rrc_gNB_remove_ue_context(ctxt_pP, RC.nrrrc[ctxt_pP->module_id], ue_context_p); - LOG_I(NR_RRC, "remove UE %x \n", ctxt_pP->rnti); + /* remove RRC UE Context */ + ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[ctxt_pP->module_id], ctxt_pP->rnti); + if (ue_context_p) { + rrc_gNB_remove_ue_context(ctxt_pP, RC.nrrrc[ctxt_pP->module_id], ue_context_p); + LOG_I(NR_RRC, "remove UE %x \n", ctxt_pP->rnti); + } + } + // In case of CU trigger UE context release command towards the DU + else{ + MessageDef *message_p; + message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, F1AP_UE_CONTEXT_RELEASE_CMD); + f1ap_ue_context_release_cmd_t *rel_cmd=&F1AP_UE_CONTEXT_RELEASE_CMD (message_p); + rel_cmd->rnti = ctxt_pP->rnti; + rel_cmd->cause = F1AP_CAUSE_RADIO_NETWORK; + rel_cmd->cause_value = 10; // 10 = F1AP_CauseRadioNetwork_normal_release + itti_send_msg_to_task(TASK_CU_F1, ctxt_pP->module_id, message_p); } } From 11cdf1610ec79f31ae9578b1fd60433202eda383 Mon Sep 17 00:00:00 2001 From: matzakos Date: Wed, 20 Oct 2021 19:00:51 +0200 Subject: [PATCH 013/267] Update F1AP UE context release command handling function for NR -Include ITTI message to RRC to do the actual processing at RRC layer, as done for the other F1AP messages. Leave LTE processing as it was for now. --- openair2/F1AP/f1ap_du_ue_context_management.c | 185 +++++++++++++++++- openair2/RRC/NR/rrc_gNB.c | 5 + 2 files changed, 187 insertions(+), 3 deletions(-) diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index 77f8b9d046..92e8e272da 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -674,7 +674,7 @@ int DU_send_UE_CONTEXT_RELEASE_REQUEST(instance_t instance, getCxt(false, instance)->default_sctp_stream_id); return 0; } -int DU_handle_UE_CONTEXT_RELEASE_COMMAND(instance_t instance, +/*int DU_handle_UE_CONTEXT_RELEASE_COMMAND(instance_t instance, uint32_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { @@ -700,7 +700,7 @@ int DU_handle_UE_CONTEXT_RELEASE_COMMAND(instance_t instance, rnti, ctxt.rnti); int UE_out_of_sync = 0; - /*if (RC.nrrrc && RC.nrrrc[instance]->node_type == ngran_gNB_DU) { + if (RC.nrrrc && RC.nrrrc[instance]->node_type == ngran_gNB_DU) { for (int n = 0; n < MAX_MOBILES_PER_GNB; ++n) { if (RC.nrmac[instance]->UE_info.active[n] == TRUE && rnti == RC.nrmac[instance]->UE_info.rnti[n]) { @@ -811,8 +811,187 @@ int DU_handle_UE_CONTEXT_RELEASE_COMMAND(instance_t instance, cplt.rnti = ctxt.rnti; DU_send_UE_CONTEXT_RELEASE_COMPLETE(instance, &cplt); return 0; - }*/ + } +}*/ + + +int DU_handle_UE_CONTEXT_RELEASE_COMMAND(instance_t instance, + uint32_t assoc_id, + uint32_t stream, + F1AP_F1AP_PDU_t *pdu) { + F1AP_UEContextReleaseCommand_t *container; + F1AP_UEContextReleaseCommandIEs_t *ie; + protocol_ctxt_t ctxt; + + /* ITTI message to NR-RRC for the case of gNB-DU */ + MessageDef *msg_p; // message to NR-RRC + msg_p = itti_alloc_new_message(TASK_DU_F1, 0, F1AP_UE_CONTEXT_RELEASE_CMD); + f1ap_ue_context_release_req_t *f1ap_ue_context_release_cmd = &F1AP_UE_CONTEXT_RELEASE_CMD(msg_p); + + + DevAssert(pdu); + container = &pdu->choice.initiatingMessage->value.choice.UEContextReleaseCommand; + // GNB_CU_UE_F1AP_ID + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseCommandIEs_t, ie, container, + F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); + if(RC.nrrrc && RC.nrrrc[instance]->node_type == ngran_gNB_DU){ + f1ap_ue_context_release_cmd->rnti = f1ap_get_rnti_by_cu_id(DUtype, instance, ie->value.choice.GNB_CU_UE_F1AP_ID); + } + else{ + ctxt.rnti = f1ap_get_rnti_by_cu_id(DUtype, instance, ie->value.choice.GNB_CU_UE_F1AP_ID); + ctxt.instance = instance; + ctxt.module_id = instance; + ctxt.enb_flag = 1; + } + // GNB_DU_UE_F1AP_ID + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseCommandIEs_t, ie, container, + F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); + const rnti_t rnti = f1ap_get_rnti_by_du_id(DUtype, instance, + ie->value.choice.GNB_DU_UE_F1AP_ID); + if(RC.nrrrc && RC.nrrrc[instance]->node_type == ngran_gNB_DU){ + AssertFatal(f1ap_ue_context_release_cmd->rnti == rnti, + "RNTI obtained through DU ID (%x) is different from CU ID (%x)\n", + rnti, f1ap_ue_context_release_cmd->rnti); + } + else{ + AssertFatal(ctxt.rnti == rnti, + "RNTI obtained through DU ID (%x) is different from CU ID (%x)\n", + rnti, ctxt.rnti); + } + int UE_out_of_sync = 0; + + if(RC.rrc && RC.rrc[instance]->node_type == ngran_eNB_DU){ + for (int n = 0; n < MAX_MOBILES_PER_ENB; ++n) { + if (RC.mac[instance]->UE_info.active[n] == TRUE + && rnti == UE_RNTI(instance, n)) { + UE_out_of_sync = RC.mac[instance]->UE_info.UE_sched_ctrl[n].ul_out_of_sync; + break; + } + } + } + + // We don't need the Cause + // Optional RRC Container: if present, send to UE + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseCommandIEs_t, ie, container, + F1AP_ProtocolIE_ID_id_RRCContainer, false); + + if (ie && !UE_out_of_sync && RC.rrc && RC.rrc[instance]->node_type == ngran_eNB_DU) { + // RRC message and UE is reachable, send message + const sdu_size_t sdu_len = ie->value.choice.RRCContainer.size; + mem_block_t *pdu_p = NULL; + pdu_p = get_free_mem_block(sdu_len, __func__); + memcpy(&pdu_p->data[0], ie->value.choice.RRCContainer.buf, sdu_len); + rlc_op_status_t rlc_status = rlc_data_req(&ctxt + , 1 + , MBMS_FLAG_NO + , 1 // SRB 1 correct? + , 0 + , 0 + , sdu_len + , pdu_p + ,NULL + ,NULL + ); + + switch (rlc_status) { + case RLC_OP_STATUS_OK: + break; + + case RLC_OP_STATUS_BAD_PARAMETER: + LOG_W(F1AP, "Data sending request over RLC failed with 'Bad Parameter' reason!\n"); + break; + + case RLC_OP_STATUS_INTERNAL_ERROR: + LOG_W(F1AP, "Data sending request over RLC failed with 'Internal Error' reason!\n"); + break; + + case RLC_OP_STATUS_OUT_OF_RESSOURCES: + LOG_W(F1AP, "Data sending request over RLC failed with 'Out of Resources' reason!\n"); + break; + + default: + LOG_W(F1AP, "RLC returned an unknown status code after F1AP placed " + "the order to send some data (Status Code:%d)\n", rlc_status); + break; + } + } + else if(ie && RC.nrrrc && RC.nrrrc[instance]->node_type == ngran_gNB_DU) { + f1ap_ue_context_release_cmd->rrc_container = malloc(ie->value.choice.RRCContainer.size); + memcpy(f1ap_ue_context_release_cmd->rrc_container, + ie->value.choice.RRCContainer.buf, ie->value.choice.RRCContainer.size); + } + + if (RC.nrrrc && RC.nrrrc[instance]->node_type == ngran_gNB_DU) { + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseCommandIEs_t, ie, container, + F1AP_ProtocolIE_ID_id_Cause, true); + switch (ie->value.choice.Cause.present){ + case F1AP_Cause_PR_radioNetwork: + LOG_W (F1AP, "UE context release command cause is due to radioNetwork with specific code: %ld\n",ie->value.choice.Cause.choice.radioNetwork); + f1ap_ue_context_release_cmd->cause = F1AP_CAUSE_RADIO_NETWORK; + break; + case F1AP_Cause_PR_transport: + LOG_W (F1AP, "UE context release command cause is due to transport with specific code: %ld\n",ie->value.choice.Cause.choice.transport); + f1ap_ue_context_release_cmd->cause = F1AP_CAUSE_TRANSPORT; + break; + case F1AP_Cause_PR_protocol: + LOG_W (F1AP, "UE context release command cause is due to protocol with specific code: %ld\n",ie->value.choice.Cause.choice.protocol); + f1ap_ue_context_release_cmd->cause = F1AP_CAUSE_PROTOCOL; + break; + case F1AP_Cause_PR_misc: + LOG_W (F1AP, "UE context release command cause is misc with specific code: %ld \n",ie->value.choice.Cause.choice.misc); + f1ap_ue_context_release_cmd->cause = F1AP_CAUSE_MISC; + break; + default: + LOG_W(F1AP, "Unknown cause for UE context release command\n"); + break; + + } + itti_send_msg_to_task(TASK_RRC_GNB, instance, msg_p); + return 0; + } else { + struct rrc_eNB_ue_context_s *ue_context_p; + ue_context_p = rrc_eNB_get_ue_context(RC.rrc[ctxt.instance], ctxt.rnti); + + if (ue_context_p && !UE_out_of_sync) { + // UE exists and is in sync so we start a timer before releasing the + // connection + pthread_mutex_lock(&rrc_release_freelist); + + for (uint16_t release_num = 0; release_num < NUMBER_OF_UE_MAX; release_num++) { + if (rrc_release_info.RRC_release_ctrl[release_num].flag == 0) { + if (ue_context_p->ue_context.ue_release_timer_s1 > 0) + rrc_release_info.RRC_release_ctrl[release_num].flag = 1; + else + rrc_release_info.RRC_release_ctrl[release_num].flag = 2; + + rrc_release_info.RRC_release_ctrl[release_num].rnti = ctxt.rnti; + LOG_D(F1AP, "add rrc_release_info RNTI %x\n", ctxt.rnti); + // TODO: how to provide the correct MUI? + rrc_release_info.RRC_release_ctrl[release_num].rrc_eNB_mui = 0; + rrc_release_info.num_UEs++; + LOG_D(RRC,"Generate DLSCH Release send: index %d rnti %x mui %d flag %d \n",release_num, + ctxt.rnti, 0, rrc_release_info.RRC_release_ctrl[release_num].flag); + break; + } + } + + pthread_mutex_unlock(&rrc_release_freelist); + ue_context_p->ue_context.ue_release_timer_s1 = 0; + } else if (ue_context_p && UE_out_of_sync) { + // UE exists and is out of sync, drop the connection + mac_eNB_rrc_ul_failure(instance, 0, 0, 0, rnti); + } else { + LOG_E(F1AP, "no ue_context for RNTI %x, acknowledging release\n", rnti); + } + + // TODO send this once the connection has really been released + f1ap_ue_context_release_cplt_t cplt; + cplt.rnti = ctxt.rnti; + DU_send_UE_CONTEXT_RELEASE_COMPLETE(instance, &cplt); + return 0; + } } + int DU_send_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, f1ap_ue_context_release_cplt_t *cplt) { F1AP_F1AP_PDU_t pdu= {0}; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index a18b267ec6..25f058c1d2 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -4212,6 +4212,11 @@ void *rrc_gnb_task(void *args_p) { rrc_DU_process_ue_context_modification_request(msg_p, msg_name_p, instance); break; + case F1AP_UE_CONTEXT_RELEASE_CMD: + LOG_W(NR_RRC, "Received F1AP_UE_CONTEXT_RELEASE_CMD for processing at the RRC layer of the DU. Processing function " + "implementation is pending\n"); + break; + /* Messages from X2AP */ case X2AP_ENDC_SGNB_ADDITION_REQ: LOG_I(NR_RRC, "Received ENDC sgNB addition request from X2AP \n"); From 96efe9c03b5f2b146bfabdb709bddd58eaf738cf Mon Sep 17 00:00:00 2001 From: matzakos Date: Tue, 26 Oct 2021 12:56:32 +0200 Subject: [PATCH 014/267] Enable rrc mac config from init NR SI for the DU case --- openair2/RRC/NR/rrc_gNB.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 25f058c1d2..58a0f4b0c9 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -257,7 +257,7 @@ static void init_NR_SI(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration LOG_I(NR_RRC,"Done init_NR_SI\n"); - if (NODE_IS_MONOLITHIC(rrc->node_type)){ + if (NODE_IS_MONOLITHIC(rrc->node_type) || NODE_IS_DU(rrc->node_type)){ rrc_mac_config_req_gNB(rrc->module_id, rrc->carrier.ssb_SubcarrierOffset, rrc->carrier.pdsch_AntennaPorts, From e7f8b56b65186d5f7f09a13e8a44740153037ae2 Mon Sep 17 00:00:00 2001 From: matzakos Date: Tue, 26 Oct 2021 12:57:47 +0200 Subject: [PATCH 015/267] Include NR_SIB1_t type in F1 setup req container instead of the whole NR_BCCH_DL_SCH_Message_t message -Wireshark is not complaining after that -Issue at decoding F1 Setup req at the CU due to the new encoding -Keep the previous encoding as the default for now until the CU issue is fixed -Fix PUCCH allocation for ACK/NAK issue appearing when DU runs without OAI CU --- openair2/GNB_APP/gnb_config.c | 38 ++++++++++++++++++- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 2 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 2 +- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index bcce5a367a..a2e418245a 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1735,9 +1735,43 @@ int RCconfig_NR_DU_F1(MessageDef *msg_p, uint32_t i) { f1Setup->measurement_timing_information[k] = "0"; f1Setup->ranac[k] = 0; f1Setup->mib[k] = rrc->carrier.MIB; - f1Setup->sib1[k] = rrc->carrier.SIB1; f1Setup->mib_length[k] = rrc->carrier.sizeof_MIB; - f1Setup->sib1_length[k] = rrc->carrier.sizeof_SIB1; + if(1){ + f1Setup->sib1[k] = rrc->carrier.SIB1; + f1Setup->sib1_length[k] = rrc->carrier.sizeof_SIB1; + } + else{ + NR_BCCH_DL_SCH_Message_t *bcch_message = NULL; + + asn_dec_rval_t dec_rval = uper_decode_complete( NULL, + &asn_DEF_NR_BCCH_DL_SCH_Message, + (void **)&bcch_message, + (const void *)rrc->carrier.SIB1, + rrc->carrier.sizeof_SIB1); + + if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { + LOG_E(RRC,"SIB1 decode error\n"); + // free the memory + SEQUENCE_free( &asn_DEF_NR_BCCH_DL_SCH_Message, bcch_message, 1 ); + exit(1); + } + + NR_SIB1_t *bcch_SIB1 = bcch_message->message.choice.c1->choice.systemInformationBlockType1; + f1Setup->sib1[k] = calloc(1,rrc->carrier.sizeof_SIB1); + asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_SIB1, + NULL, + (void *)bcch_SIB1, + f1Setup->sib1[k], + NR_MAX_SIB_LENGTH/8); + AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, enc_rval.encoded); + + //if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { + LOG_I(NR_RRC, "SIB1 container to be integrated in F1 Setup request:\n"); + xer_fprint(stdout, &asn_DEF_NR_SIB1,(void *)bcch_message->message.choice.c1->choice.systemInformationBlockType1 ); + //} + f1Setup->sib1_length[k] = (enc_rval.encoded+7)/8; + } break; } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 606da48575..dc4d187842 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1463,7 +1463,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra int r_pucch = ((CCEIndex<<1)/N_cce)+(delta_PRI<<1); int alloc = nr_acknack_scheduling(module_idP, UE_id, frameP, slotP, r_pucch); - AssertFatal(alloc>=0,"Couldn't find a pucch allocation for ack nack (msg4)\n"); + AssertFatal(alloc>=0,"%d.%d Couldn't find a pucch allocation for ack nack (msg4), r_pucch %d (CCEindex%d,N_cce%d\n",frameP,slotP,r_pucch,CCEIndex,N_cce); NR_sched_pucch_t *pucch = &sched_ctrl->sched_pucch[alloc]; harq->feedback_slot = pucch->ul_slot; harq->feedback_frame = pucch->frame; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 0f828b8e81..6fcc3fe5c1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -1355,7 +1355,7 @@ int nr_acknack_scheduling(int mod_id, * for initialCyclicShift 0 (we assume it always has that one), so other * initialCyclicShifts can overlap with ICS 0!*/ if (pucch_Config==NULL) - return -1; + return 0; const NR_PUCCH_Resource_t *resource = pucch_Config->resourceToAddModList->list.array[pucch->resource_indicator]; DevAssert(resource->format.present == NR_PUCCH_Resource__format_PR_format0); if (resource->format.choice.format0->initialCyclicShift == 0) { From b103ada5421f4ca46ac9d52e554a9694b95dd933 Mon Sep 17 00:00:00 2001 From: matzakos Date: Tue, 26 Oct 2021 18:30:51 +0200 Subject: [PATCH 016/267] Fix decoding of SIB1 RRC container at the processing function of F1 setup request at the CU after modifications done at the encoded SIB1 message type included in the RRC container of F1 setup request at the DU -Some cleanup required --- openair2/GNB_APP/gnb_config.c | 2 +- openair2/RRC/NR/nr_rrc_defs.h | 3 ++- openair2/RRC/NR/rrc_gNB.c | 16 +++++++++++----- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index a2e418245a..29f3c15355 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1736,7 +1736,7 @@ int RCconfig_NR_DU_F1(MessageDef *msg_p, uint32_t i) { f1Setup->ranac[k] = 0; f1Setup->mib[k] = rrc->carrier.MIB; f1Setup->mib_length[k] = rrc->carrier.sizeof_MIB; - if(1){ + if(0){ f1Setup->sib1[k] = rrc->carrier.SIB1; f1Setup->sib1_length[k] = rrc->carrier.sizeof_SIB1; } diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 4418a37632..19120e8854 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -440,7 +440,8 @@ typedef struct { NR_BCCH_BCH_Message_t mib; NR_BCCH_BCH_Message_t *mib_DU; - NR_BCCH_DL_SCH_Message_t *siblock1_DU; + NR_SIB1_t *siblock1_DU; + //NR_BCCH_DL_SCH_Message_t *siblock1_DU; NR_SIB1_t *sib1; NR_SIB2_t *sib2; NR_SIB3_t *sib3; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 58a0f4b0c9..c618468cd9 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2895,11 +2895,11 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *f1_setup_req) { memset(mib->message.choice.mib,0,sizeof(struct NR_MIB)); memcpy(mib->message.choice.mib, mib_DU->message.choice.mib, sizeof(struct NR_MIB)); - rrc->carrier.SIB1 = malloc(f1_setup_req->sib1_length[i]); + /*rrc->carrier.SIB1 = malloc(f1_setup_req->sib1_length[i]); rrc->carrier.sizeof_SIB1 = f1_setup_req->sib1_length[i]; - memcpy((void *)rrc->carrier.SIB1,f1_setup_req->sib1[i],f1_setup_req->sib1_length[i]); + memcpy((void *)rrc->carrier.SIB1,f1_setup_req->sib1[i],f1_setup_req->sib1_length[i]);*/ dec_rval = uper_decode_complete(NULL, - &asn_DEF_NR_BCCH_DL_SCH_Message, + &asn_DEF_NR_SIB1, //&asn_DEF_NR_BCCH_DL_SCH_Message, (void **)&rrc->carrier.siblock1_DU, f1_setup_req->sib1[i], f1_setup_req->sib1_length[i]); @@ -2909,12 +2909,18 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *f1_setup_req) { dec_rval.consumed ); // Parse message and extract SystemInformationBlockType1 field - NR_BCCH_DL_SCH_Message_t *bcch_message = rrc->carrier.siblock1_DU; + rrc->carrier.sib1 = rrc->carrier.siblock1_DU; + if ( LOG_DEBUGFLAG(DEBUG_ASN1)){ + LOG_I(NR_RRC, "Printing received SIB1 container inside F1 setup request message:\n"); + xer_fprint(stdout, &asn_DEF_NR_SIB1,(void *)rrc->carrier.sib1); + } + + /*NR_BCCH_DL_SCH_Message_t *bcch_message = rrc->carrier.siblock1_DU; AssertFatal(bcch_message->message.present == NR_BCCH_DL_SCH_MessageType_PR_c1, "bcch_message->message.present != NR_BCCH_DL_SCH_MessageType_PR_c1\n"); AssertFatal(bcch_message->message.choice.c1->present == NR_BCCH_DL_SCH_MessageType__c1_PR_systemInformationBlockType1, "bcch_message->message.choice.c1->present != NR_BCCH_DL_SCH_MessageType__c1_PR_systemInformationBlockType1\n"); - rrc->carrier.sib1 = bcch_message->message.choice.c1->choice.systemInformationBlockType1; + rrc->carrier.sib1 = bcch_message->message.choice.c1->choice.systemInformationBlockType1;*/ rrc->carrier.physCellId = f1_setup_req->cell[i].nr_pci; F1AP_GNB_CU_CONFIGURATION_UPDATE (msg_p2).gNB_CU_name = rrc->node_name; From e2b4f80ac23b391f7d5eaca468c95165f39261e2 Mon Sep 17 00:00:00 2001 From: matzakos Date: Fri, 5 Nov 2021 10:38:46 +0100 Subject: [PATCH 017/267] Add sNSSAI configuration in F1 Setup request message to the CU -Required for interoperability with Accelleran CU and OAI CN -Currently hardcoded values, to be modified so that they are parsed from the DU config file -After this modification Accelleran CU sends gNBCU configuration update --- openair2/F1AP/f1ap_du_interface_management.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/openair2/F1AP/f1ap_du_interface_management.c b/openair2/F1AP/f1ap_du_interface_management.c index 12b0559003..e6631e1edb 100644 --- a/openair2/F1AP/f1ap_du_interface_management.c +++ b/openair2/F1AP/f1ap_du_interface_management.c @@ -175,6 +175,24 @@ int DU_send_F1_SETUP_REQUEST(instance_t instance) { MCC_MNC_TO_PLMNID(cell->mcc, cell->mnc, cell->mnc_digit_length, &servedPLMN_item->pLMN_Identity); // // /* - CHOICE NR-MODE-Info */ F1AP_NR_Mode_Info_t *nR_Mode_Info= &served_cell_information->nR_Mode_Info; + //if(0){ + //F1AP_ProtocolExtensionContainer_154P260_t *p_154P260=calloc(1, sizeof(* p_154P260)); + F1AP_ProtocolExtensionContainer_154P34_t *p_154P34=calloc(1,sizeof(* p_154P34)); + servedPLMN_item->iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)p_154P34; + asn1cSequenceAdd(p_154P34->list, F1AP_ServedPLMNs_ItemExtIEs_t , served_plmns_itemExtIEs); + served_plmns_itemExtIEs->criticality = F1AP_Criticality_ignore; + served_plmns_itemExtIEs->id = F1AP_ProtocolIE_ID_id_TAISliceSupportList; + served_plmns_itemExtIEs->extensionValue.present = F1AP_ServedPLMNs_ItemExtIEs__extensionValue_PR_SliceSupportList; + F1AP_SliceSupportList_t *slice_support_list = &served_plmns_itemExtIEs->extensionValue.choice.SliceSupportList; + + asn1cSequenceAdd(slice_support_list->list, F1AP_SliceSupportItem_t, SliceSupport_item); + INT8_TO_OCTET_STRING(1,&SliceSupport_item->sNSSAI.sST); + //OCTET_STRING_fromBuf(&SliceSupport_item->sNSSAI.sST, "1", 1); + asn1cCalloc(SliceSupport_item->sNSSAI.sD, tmp); + INT24_TO_OCTET_STRING(1,tmp); + //OCTET_STRING_fromBuf(tmp, "1",1); + //} + if (f1ap_req(false, instance)->fdd_flag) { // FDD nR_Mode_Info->present = F1AP_NR_Mode_Info_PR_fDD; From 6a1ac1444766c2af61f1a3e8bb89a9e763e16ce8 Mon Sep 17 00:00:00 2001 From: matzakos Date: Wed, 10 Nov 2021 18:31:08 +0100 Subject: [PATCH 018/267] Include mandatory transaction ID field in F1 initial UL RRC message transfer --- openair2/F1AP/f1ap_du_rrc_message_transfer.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openair2/F1AP/f1ap_du_rrc_message_transfer.c b/openair2/F1AP/f1ap_du_rrc_message_transfer.c index ac281af81d..59445d792d 100644 --- a/openair2/F1AP/f1ap_du_rrc_message_transfer.c +++ b/openair2/F1AP/f1ap_du_rrc_message_transfer.c @@ -812,6 +812,13 @@ int DU_send_INITIAL_UL_RRC_MESSAGE_TRANSFER(instance_t instanceP, sdu2P, sdu2_lenP); } + /* mandatory */ + /* c6. Transaction ID (integer value) */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_InitialULRRCMessageTransferIEs_t, ie6); + ie6->id = F1AP_ProtocolIE_ID_id_TransactionID; + ie6->criticality = F1AP_Criticality_ignore; + ie6->value.present = F1AP_F1SetupRequestIEs__value_PR_TransactionID; + ie6->value.choice.TransactionID = F1AP_get_next_transaction_identifier(f1ap_req(false, instanceP)->gNB_DU_id, f1ap_req(false, instanceP)->gNB_DU_id); /* encode */ if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { From f1455f15a3e184139ac3bbb92f43e65ac8f5e390 Mon Sep 17 00:00:00 2001 From: matzakos Date: Wed, 10 Nov 2021 18:33:48 +0100 Subject: [PATCH 019/267] Check whether RRC Setup is available before sending CBRA Msg4 -Required for the CU/DU split case if the RRC Setup arrives later than the first opportunity to transmit Msg4 -Next extension is to decouple RRCSetup from Msg4 --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 5 +++++ openair2/RRC/NR/L2_nr_interface.c | 8 ++++++++ openair2/RRC/NR/nr_rrc_proto.h | 6 ++++++ 3 files changed, 19 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index dc4d187842..26ef47f152 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1388,6 +1388,11 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra if (ra->Msg4_frame == frameP && ra->Msg4_slot == slotP ) { + if (nr_mac_rrc_check_RRCSetup(module_idP, ra->rnti) <= 0){ + ra->Msg4_frame++; + return; + } + uint8_t time_domain_assignment = 0; uint8_t mcsIndex = 0; diff --git a/openair2/RRC/NR/L2_nr_interface.c b/openair2/RRC/NR/L2_nr_interface.c index 445aa832cb..dd9a5bb188 100644 --- a/openair2/RRC/NR/L2_nr_interface.c +++ b/openair2/RRC/NR/L2_nr_interface.c @@ -304,6 +304,14 @@ int8_t mac_rrc_nr_data_req(const module_id_t Mod_idP, } +int8_t nr_mac_rrc_check_RRCSetup(const module_id_t Mod_idP, + const rnti_t rnti) { + struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[Mod_idP], rnti); + char payload_size = ue_context_p->ue_context.Srb0.Tx_buffer.payload_size; + return payload_size; + +} + int8_t nr_mac_rrc_data_ind(const module_id_t module_idP, const int CC_id, const frame_t frameP, diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 2ac8d14a23..771845d5d0 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -170,6 +170,12 @@ nr_rrc_data_req( const pdcp_transmission_mode_t modeP ); +int8_t nr_mac_rrc_check_RRCSetup( + const module_id_t Mod_idP, + const rnti_t rnti + +); + int nr_rrc_mac_remove_ue(module_id_t mod_idP, rnti_t rntiP); From cd16d7ce0386173594a43b8102a95d9eca10b120 Mon Sep 17 00:00:00 2001 From: matzakos Date: Wed, 10 Nov 2021 18:35:05 +0100 Subject: [PATCH 020/267] Make the call to send DCCH SDU to RLC from RRC instead of F1AP --- openair2/F1AP/f1ap_du_ue_context_management.c | 10 +--------- openair2/RRC/NR/rrc_gNB.c | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index 92e8e272da..1a4fbe38a5 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -230,17 +230,9 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, f1ap_ue_context_setup_req->rrc_container = malloc(ieRRC->value.choice.RRCContainer.size); memcpy(f1ap_ue_context_setup_req->rrc_container, ieRRC->value.choice.RRCContainer.buf, ieRRC->value.choice.RRCContainer.size); + f1ap_ue_context_setup_req->rrc_container_length = ieRRC->value.choice.RRCContainer.size; // AssertFatal(0, "check configuration, send to appropriate handler\n"); protocol_ctxt_t ctxt; - // decode RRC Container and act on the message type - //FIXME - //rnti_t rnti = f1ap_get_rnti_by_du_id(DUtype, instance, du_ue_f1ap_id); - ctxt.instance = instance; - ctxt.instance = instance; - ctxt.enb_flag = 1; - mem_block_t *pdcp_pdu_p = get_free_mem_block(ieRRC->value.choice.RRCContainer.size, __func__); - memcpy(&pdcp_pdu_p->data[0], ieRRC->value.choice.RRCContainer.buf, ieRRC->value.choice.RRCContainer.size); - du_rlc_data_req(&ctxt, 1, 0x00, 1, 1, 0, ieRRC->value.choice.RRCContainer.size, pdcp_pdu_p); } else { LOG_E(F1AP, " RRCContainer in UEContextSetupRequestIEs size id 0\n"); } diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index c618468cd9..c3f415ee64 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -3393,8 +3393,20 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha req->srbs_to_be_setup_length>0 ? 1:0, req->drbs_to_be_setup_length>0 ? 1:0); } - + apply_macrlc_config(rrc, ue_context_p, &ctxt); + + if(req->rrc_container_length > 0){ + mem_block_t *pdcp_pdu_p = get_free_mem_block(req->rrc_container_length, __func__); + memcpy(&pdcp_pdu_p->data[0], req->rrc_container, req->rrc_container_length); + du_rlc_data_req(&ctxt, 1, 0x00, 1, 1, 0, req->rrc_container_length, pdcp_pdu_p); + LOG_I(F1AP, "Printing RRC Container of UE context setup request: \n"); + for (int j=0; jrrc_container_length; j++){ + printf("%02x ", pdcp_pdu_p->data[j]); + } + printf("\n"); + } + /* Fill the UE context setup response ITTI message to send to F1AP */ resp->gNB_CU_ue_id = req->gNB_CU_ue_id; resp->rnti = ctxt.rnti; @@ -4526,5 +4538,6 @@ void nr_rrc_trigger(protocol_ctxt_t *ctxt, int CC_id, int frame, int subframe) message_p = itti_alloc_new_message(TASK_RRC_GNB, 0, RRC_SUBFRAME_PROCESS); RRC_SUBFRAME_PROCESS(message_p).ctxt = *ctxt; RRC_SUBFRAME_PROCESS(message_p).CC_id = CC_id; + LOG_D(NR_RRC, "Time in RRC: %u/ %u \n", frame, subframe); itti_send_msg_to_task(TASK_RRC_GNB, ctxt->module_id, message_p); } From 188a99ca518a17113abc588fc6ca098e3d26237b Mon Sep 17 00:00:00 2001 From: matzakos Date: Wed, 10 Nov 2021 18:35:52 +0100 Subject: [PATCH 021/267] Temporary dirty fix to not block SRB1 traffic once SRB2 is added -This function will change completely after update with develop --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 2cbe232fe0..9e9e105ba0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -395,8 +395,14 @@ void nr_store_dlsch_buffer(module_id_t module_id, loop_dcch_dtch = DL_SCH_LCID_DTCH; else if ((sched_ctrl->lcid_mask&(1<<1)) > 0 && loop_dcch_dtch == DL_SCH_LCID_DTCH) loop_dcch_dtch = DL_SCH_LCID_DCCH; - else if ((sched_ctrl->lcid_mask&(1<<2)) > 0 && loop_dcch_dtch == DL_SCH_LCID_DCCH) - loop_dcch_dtch = DL_SCH_LCID_DCCH1; + /*else if ((sched_ctrl->lcid_mask&(1<<2)) > 0 && loop_dcch_dtch == DL_SCH_LCID_DCCH) + loop_dcch_dtch = DL_SCH_LCID_DCCH1;*/ + else if ((sched_ctrl->lcid_mask&(1<<2)) > 0){ //&& loop_dcch_dtch == DL_SCH_LCID_DCCH + if (loop_dcch_dtch == DL_SCH_LCID_DCCH) + loop_dcch_dtch = DL_SCH_LCID_DCCH1; + else if(loop_dcch_dtch == DL_SCH_LCID_DCCH1) + loop_dcch_dtch = DL_SCH_LCID_DCCH; + } const int lcid = loop_dcch_dtch; // const int lcid = DL_SCH_LCID_DTCH; @@ -788,6 +794,10 @@ void nr_schedule_ue_spec(module_id_t module_id, return; /* PREPROCESSOR */ + //Following commented section condition should be removed before update with develop. + /*if(slot!= 1 && slot!=11){ + return; + }*/ gNB_mac->pre_processor_dl(module_id, frame, slot); const int CC_id = 0; From 40263348f96ead12dac9626bb30639f1b47d4be7 Mon Sep 17 00:00:00 2001 From: matzakos Date: Fri, 12 Nov 2021 17:01:27 +0100 Subject: [PATCH 022/267] Merge with NR_F1C_F1U_extensions and resolve conflicts --- ci-scripts/Jenkinsfile-GitLab-Container | 17 + ci-scripts/Jenkinsfile-push-registry | 86 ++ ci-scripts/Jenkinsfile-tmp-multi-enb-nsa | 15 + ci-scripts/Jenkinsfile-trig-nsa | 44 +- ci-scripts/ci_ueinfra.yaml | 15 +- ci-scripts/cls_containerize.py | 17 +- ci-scripts/cls_module_ue.py | 31 +- ci-scripts/cls_oaicitest.py | 289 +++++-- ci-scripts/conf_files/channelmod_rfsimu.conf | 2 +- .../enb.band38.lte_2x2.100PRB.usrpn310.conf | 281 ++++++ .../enb.band38.nsa_2x2.100PRB.usrpn310.conf | 9 +- .../gNB_SA_n78_106PRB.2x2_usrpn310.conf | 338 ++++++++ .../gNB_SA_n78_133PRB.2x2_usrpn310.conf | 334 ++++++++ .../gnb.band261.tm1.32PRB.usrpn300.conf | 20 +- .../gnb.band66.tm1.106PRB.usrpn300.conf | 17 + .../gnb.band78.nsa_2x2.106PRB.usrpn310.conf | 25 +- ...gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf | 340 ++++++++ .../gnb.band78.sa.fr1.106PRB.usrpn310.conf | 45 +- .../gnb.band78.tm1.106PRB.usrpn300.conf | 18 +- .../gnb.band78.tm1.fr1.106PRB.usrpb210.conf | 17 + .../gnb.band78.tm1.fr1.106PRB.usrpn310.conf | 17 + ci-scripts/datalog_rt_stats.yaml | 6 +- ci-scripts/epc.py | 116 ++- ci-scripts/main.py | 1 + ci-scripts/ran.py | 55 +- ci-scripts/sshconnection.py | 12 + ci-scripts/stats_monitor.py | 102 +++ ci-scripts/stats_monitor.py.old | 94 ++ ci-scripts/stats_monitor_conf.yaml | 11 + ci-scripts/stats_monitor_dev.py | 101 +++ ci-scripts/xml_files/fr1_enb_build.xml | 50 ++ ci-scripts/xml_files/fr1_gnb_build.xml | 2 - ci-scripts/xml_files/fr1_lte_2x2_quectel.xml | 141 +++ ci-scripts/xml_files/fr1_multi_node_build.xml | 7 +- ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml | 30 +- .../fr1_nsa_2x2_quectel_attach_detach.xml | 145 ++++ ci-scripts/xml_files/fr1_oai_cn_deploy.xml | 2 +- ci-scripts/xml_files/fr1_sa_quectel.xml | 16 +- .../docker-compose.yml | 19 +- .../docker-compose.yml} | 139 ++- .../yaml_files/magma_nsa_20897/entrypoint.sh | 36 + .../yaml_files/magma_nsa_20897/mme.conf | 136 +++ .../magma_nsa_20897/mme_fd.sprint.conf | 169 ++++ .../magma_nsa_20897/redis_extern.conf | 33 + cmake_targets/CMakeLists.txt | 86 +- cmake_targets/build_oai | 2 +- cmake_targets/tools/build_helper | 53 +- common/utils/DOC/loader/devusage/api.md | 4 + common/utils/load_module_shlib.c | 11 +- common/utils/load_module_shlib.h | 5 +- common/utils/nr/nr_common.c | 196 +++++ common/utils/nr/nr_common.h | 7 + common/utils/telnetsrv/telnetsrv.c | 139 ++- common/utils/telnetsrv/telnetsrv.h | 2 + .../telnetsrv/telnetsrv_5Gue_measurements.c | 178 ++++ .../utils/telnetsrv/telnetsrv_CMakeLists.txt | 6 +- .../utils/telnetsrv/telnetsrv_cpumeasur_def.h | 162 ++-- .../utils/telnetsrv/telnetsrv_measurements.c | 101 ++- .../utils/telnetsrv/telnetsrv_measurements.h | 8 +- doc/BUILD.md | 15 + doc/RUNMODEM.md | 5 +- doc/testing_gnb_w_cots_ue_resources/gnb.conf | 17 + docker/Dockerfile.eNB.rhel8.2 | 17 +- docker/Dockerfile.eNB.ubuntu18 | 28 +- docker/Dockerfile.gNB.rhel8.2 | 17 +- docker/Dockerfile.gNB.ubuntu18 | 24 +- docker/Dockerfile.lteRU.rhel8.2 | 16 +- docker/Dockerfile.lteRU.ubuntu18 | 27 +- docker/Dockerfile.lteUE.rhel8.2 | 17 +- docker/Dockerfile.lteUE.ubuntu18 | 29 +- docker/Dockerfile.nrUE.rhel8.2 | 16 +- docker/Dockerfile.nrUE.ubuntu18 | 26 +- docker/Dockerfile.ran.rhel8.2 | 3 + docker/Dockerfile.ran.ubuntu18 | 5 +- docker/scripts/enb_entrypoint.sh | 6 +- docker/scripts/gnb_entrypoint.sh | 6 +- docker/scripts/lte_ru_entrypoint.sh | 6 +- docker/scripts/lte_ue_entrypoint.sh | 6 +- docker/scripts/nr_ue_entrypoint.sh | 6 +- executables/nr-gnb.c | 87 +- executables/nr-ru.c | 301 ++++--- executables/nr-uesoftmodem.c | 8 +- executables/nr-uesoftmodem.h | 2 +- executables/softmodem-common.h | 8 +- nfapi/oai_integration/nfapi_pnf.c | 85 +- openair1/PHY/CODING/DOC/LDPCImplementation.md | 163 +++- openair1/PHY/CODING/TESTBENCH/ldpctest.c | 51 +- .../CODING/nrLDPC_decoder/nrLDPC_decoder.c | 6 +- .../CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c | 436 ++++++++++ .../nrLDPC_decoder_kernels_CL.cl | 302 +++++++ .../PHY/CODING/nrLDPC_decoder/nrLDPC_types.h | 1 + .../nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu | 59 +- openair1/PHY/CODING/nrLDPC_defs.h | 3 +- openair1/PHY/CODING/nrLDPC_extern.h | 7 +- openair1/PHY/CODING/nrLDPC_load.c | 26 +- .../CODING/nrPolar_tools/nr_polar_encoder.c | 25 +- openair1/PHY/CODING/nr_segmentation.c | 10 +- openair1/PHY/INIT/nr_init.c | 48 +- openair1/PHY/INIT/nr_init_ru.c | 18 +- openair1/PHY/INIT/nr_parms.c | 5 +- openair1/PHY/INIT/phy_init.h | 1 + openair1/PHY/LTE_TRANSPORT/if5_tools.c | 199 ++--- openair1/PHY/MODULATION/slot_fep_nr.c | 25 +- .../PHY/NR_ESTIMATION/nr_measurements_gNB.c | 115 ++- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 43 +- openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 2 +- openair1/PHY/NR_REFSIG/nr_gold.c | 4 +- openair1/PHY/NR_TRANSPORT/nr_dci.c | 23 +- openair1/PHY/NR_TRANSPORT/nr_dci.h | 2 - openair1/PHY/NR_TRANSPORT/nr_dci_tools.c | 107 +-- .../PHY/NR_TRANSPORT/nr_dci_tools_common.c | 62 -- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 18 +- openair1/PHY/NR_TRANSPORT/nr_dlsch.h | 8 +- openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c | 2 +- openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c | 38 +- openair1/PHY/NR_TRANSPORT/nr_prach_common.c | 1 - openair1/PHY/NR_TRANSPORT/nr_tbs_tools.c | 2 +- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 3 +- openair1/PHY/NR_TRANSPORT/nr_ulsch.c | 24 +- openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c | 29 +- .../PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 86 +- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 803 ++++++++++-------- .../PHY/NR_UE_ESTIMATION/nr_ue_measurements.c | 1 - openair1/PHY/NR_UE_TRANSPORT/dci_nr.c | 45 +- openair1/PHY/NR_UE_TRANSPORT/dci_tools_nr.c | 5 - .../PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c | 84 +- .../NR_UE_TRANSPORT/nr_dlsch_demodulation.c | 34 +- .../PHY/NR_UE_TRANSPORT/nr_initial_sync.c | 9 +- .../PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c | 1 - openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 9 +- openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c | 3 +- openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h | 1 - openair1/PHY/TOOLS/time_meas.c | 133 ++- openair1/PHY/TOOLS/time_meas.h | 86 +- openair1/PHY/defs_RU.h | 1 + openair1/PHY/defs_gNB.h | 61 +- openair1/PHY/impl_defs_top.h | 11 +- openair1/SCHED/nfapi_lte_dummy.c | 11 +- openair1/SCHED/nfapi_nr_dummy.c | 9 +- openair1/SCHED_NR/fapi_nr_l1.c | 96 +-- openair1/SCHED_NR/fapi_nr_l1.h | 8 +- openair1/SCHED_NR/nr_prach_procedures.c | 55 +- openair1/SCHED_NR/nr_ru_procedures.c | 9 +- openair1/SCHED_NR/phy_frame_config_nr.c | 16 + openair1/SCHED_NR/phy_frame_config_nr.h | 2 + openair1/SCHED_NR/phy_procedures_nr_gNB.c | 299 ++++--- openair1/SCHED_NR/sched_nr.h | 2 +- openair1/SCHED_NR_UE/defs.h | 2 - openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 142 +--- openair1/SCHED_NR_UE/pucch_uci_ue_nr.c | 293 +------ openair1/SCHED_NR_UE/pucch_uci_ue_nr.h | 27 - openair1/SIMULATION/LTE_PHY/dlsim.c | 10 +- openair1/SIMULATION/LTE_PHY/mbmssim.c | 10 +- openair1/SIMULATION/LTE_PHY/ulsim.c | 2 +- openair1/SIMULATION/NR_PHY/dlschsim.c | 6 +- openair1/SIMULATION/NR_PHY/dlsim.c | 71 +- openair1/SIMULATION/NR_PHY/pbchsim.c | 10 +- openair1/SIMULATION/NR_PHY/prachsim.c | 1 + openair1/SIMULATION/NR_PHY/pucchsim.c | 291 ++++--- openair1/SIMULATION/NR_PHY/ulsim.c | 239 ++++-- openair1/SIMULATION/TOOLS/abstraction.c | 13 +- openair1/SIMULATION/TOOLS/random_channel.c | 19 +- openair1/SIMULATION/TOOLS/sim.h | 4 +- openair2/COMMON/f1ap_messages_types.h | 2 +- openair2/COMMON/gtpv1_u_messages_def.h | 3 +- openair2/COMMON/gtpv1_u_messages_types.h | 20 +- openair2/COMMON/ngap_messages_types.h | 51 ++ openair2/COMMON/rrc_messages_types.h | 1 + openair2/ENB_APP/enb_config.c | 12 +- openair2/ENB_APP/enb_paramdef.h | 2 +- openair2/F1AP/dummy_enb.c | 13 + openair2/GNB_APP/MACRLC_nr_paramdef.h | 8 +- openair2/GNB_APP/gnb_config.c | 192 +++-- openair2/GNB_APP/gnb_paramdef.h | 26 +- .../NR_MAC_COMMON/nr_compute_tbs_common.c | 5 +- openair2/LAYER2/NR_MAC_COMMON/nr_mac.h | 8 + openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 594 +++++-------- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h | 20 +- openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h | 3 + openair2/LAYER2/NR_MAC_UE/config_ue.c | 80 +- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 25 +- openair2/LAYER2/NR_MAC_UE/mac_proto.h | 113 ++- openair2/LAYER2/NR_MAC_UE/main_ue_nr.c | 5 +- openair2/LAYER2/NR_MAC_UE/nr_l1_helpers.c | 143 +--- .../nr_l1_helpers.h} | 24 +- openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c | 157 +++- .../NR_MAC_UE/nr_ue_dci_configuration.c | 150 ++-- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 572 +++++++++---- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 797 +++++++++++++++-- openair2/LAYER2/NR_MAC_gNB/config.c | 45 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 86 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 243 +++--- .../LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 21 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 188 ++-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 61 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 353 +++++--- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 232 +++-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 213 +++-- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 28 +- openair2/LAYER2/NR_MAC_gNB/main.c | 82 ++ openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 15 +- openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c | 26 +- openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c | 1 + openair2/LAYER2/nr_pdcp/nr_pdcp_entity_srb.c | 75 -- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 65 +- openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c | 31 +- openair2/RRC/LTE/rrc_UE.c | 9 +- openair2/RRC/LTE/rrc_defs.h | 2 +- openair2/RRC/LTE/rrc_eNB.c | 8 - openair2/RRC/NR/L2_nr_interface.c | 8 +- openair2/RRC/NR/MESSAGES/asn1_msg.c | 288 ++++++- openair2/RRC/NR/MESSAGES/asn1_msg.h | 9 +- openair2/RRC/NR/nr_rrc_defs.h | 7 +- openair2/RRC/NR/rrc_gNB.c | 76 +- openair2/RRC/NR/rrc_gNB_NGAP.c | 151 ++-- openair2/RRC/NR/rrc_gNB_UE_context.c | 2 +- openair2/RRC/NR/rrc_gNB_nsa.c | 18 +- openair2/RRC/NR_UE/rrc_UE.c | 167 ++-- openair2/SDAP/nr_sdap/nr_sdap_gnb.c | 87 ++ openair2/SDAP/nr_sdap/nr_sdap_gnb.h | 61 ++ openair2/UTIL/OSA/osa_key_deriver.c | 2 + openair3/NAS/COMMON/API/NETWORK/as_message.c | 66 +- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 241 ++++-- openair3/NAS/NR_UE/nr_nas_msg_sim.h | 12 + openair3/NAS/UE/EMM/SAP/emm_as.c | 54 +- openair3/NAS/UE/nas_network.c | 26 +- openair3/NGAP/ngap_gNB_handlers.c | 7 +- openair3/ocp-gtpu/gtp_itf.cpp | 39 +- targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp | 47 +- .../CONF/gnb.band257.tm1.32PRB.usrpn300.conf | 17 + .../CONF/gnb.band257.tm1.32PRB.usrpx300.conf | 17 + .../CONF/gnb.band257.tm1.66PRB.usrpn300.conf | 17 + .../CONF/gnb.band261.tm1.32PRB.usrpn300.conf | 17 + .../CONF/gnb.band66.tm1.106PRB.usrpn300.conf | 17 + .../CONF/gnb.band66.tm1.106PRB.usrpx300.conf | 17 + .../gnb.band78.106PRB.30kHz,usrpb2x0.conf | 17 + .../CONF/gnb.band78.106PRB.slave.conf | 17 + .../CONF/gnb.band78.slave.conf | 17 + .../gnb.band78.tm1.106PRB.PTRS.usrpx300.conf | 17 + .../CONF/gnb.band78.tm1.106PRB.usrpb210.conf | 17 + .../CONF/gnb.band78.tm1.106PRB.usrpn300.conf | 17 + .../CONF/gnb.band78.tm1.106PRB.usrpx300.conf | 17 + .../CONF/gnb.band78.tm1.217PRB.usrpn300.conf | 17 + .../CONF/gnb.band78.tm1.217PRB.usrpx300.conf | 17 + .../CONF/gnb.band78.tm1.24PRB.usrpb210.conf | 17 + .../CONF/gnb.band78.tm1.24PRB.usrpn300.conf | 17 + .../CONF/gnb.band78.tm1.24PRB.usrpx300.conf | 17 + .../CONF/gnb.band78.tm1.273PRB.usrpn300.conf | 17 + .../GENERIC-LTE-EPC/CONF/testing_gnb.conf | 9 +- .../CONF/testing_gnb_24PRB.conf | 17 + .../CONF/testing_gnb_n310.conf | 17 + .../CONF/testing_gnb_nsa_n310.conf | 296 +++++++ .../PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf | 20 +- ...b.band78.tm1.106PRB.usrpn300.gtp-itti.conf | 17 + .../gnb.sa.band41.fr1.106PRB.usrpb210.conf | 26 +- .../gnb.sa.band78.fr1.106PRB.usrpb210.conf | 30 +- ...b.sa.band78.fr1.106PRB.usrpb210.sabox.conf | 17 + 257 files changed, 12071 insertions(+), 4910 deletions(-) create mode 100644 ci-scripts/Jenkinsfile-push-registry create mode 100644 ci-scripts/conf_files/enb.band38.lte_2x2.100PRB.usrpn310.conf create mode 100644 ci-scripts/conf_files/gNB_SA_n78_106PRB.2x2_usrpn310.conf create mode 100644 ci-scripts/conf_files/gNB_SA_n78_133PRB.2x2_usrpn310.conf create mode 100644 ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf create mode 100755 ci-scripts/stats_monitor.py create mode 100755 ci-scripts/stats_monitor.py.old create mode 100644 ci-scripts/stats_monitor_conf.yaml create mode 100755 ci-scripts/stats_monitor_dev.py create mode 100644 ci-scripts/xml_files/fr1_enb_build.xml create mode 100644 ci-scripts/xml_files/fr1_lte_2x2_quectel.xml create mode 100644 ci-scripts/xml_files/fr1_nsa_2x2_quectel_attach_detach.xml rename ci-scripts/yaml_files/{fr1_epc_tim => fr1_epc_20897}/docker-compose.yml (95%) rename ci-scripts/yaml_files/{fr1_epc_tim/docker-compose.yml.orig => magma_nsa_20897/docker-compose.yml} (62%) create mode 100755 ci-scripts/yaml_files/magma_nsa_20897/entrypoint.sh create mode 100644 ci-scripts/yaml_files/magma_nsa_20897/mme.conf create mode 100644 ci-scripts/yaml_files/magma_nsa_20897/mme_fd.sprint.conf create mode 100644 ci-scripts/yaml_files/magma_nsa_20897/redis_extern.conf create mode 100644 common/utils/telnetsrv/telnetsrv_5Gue_measurements.c create mode 100644 openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c create mode 100644 openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_kernels_CL.cl delete mode 100644 openair1/PHY/NR_TRANSPORT/nr_dci_tools_common.c mode change 100755 => 100644 openair2/LAYER2/NR_MAC_UE/config_ue.c mode change 100755 => 100644 openair2/LAYER2/NR_MAC_UE/mac_defs.h mode change 100755 => 100644 openair2/LAYER2/NR_MAC_UE/mac_proto.h rename openair2/LAYER2/{nr_pdcp/nr_pdcp_entity_srb.h => NR_MAC_UE/nr_l1_helpers.h} (65%) mode change 100644 => 100755 delete mode 100644 openair2/LAYER2/nr_pdcp/nr_pdcp_entity_srb.c create mode 100644 openair2/SDAP/nr_sdap/nr_sdap_gnb.c create mode 100644 openair2/SDAP/nr_sdap/nr_sdap_gnb.h create mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_nsa_n310.conf diff --git a/ci-scripts/Jenkinsfile-GitLab-Container b/ci-scripts/Jenkinsfile-GitLab-Container index f4b99e7f92..b413617580 100644 --- a/ci-scripts/Jenkinsfile-GitLab-Container +++ b/ci-scripts/Jenkinsfile-GitLab-Container @@ -220,6 +220,21 @@ pipeline { } } } + stage ("Images Push to Registries") { + when { expression {"PUSH".equals(env.gitlabActionType)} } + steps { + script { + triggerSlaveJob ('RAN-DockerHub-Push', 'Push-to-Docker-Hub') + } + post { + failure { + script { + currentBuild.result = 'FAILURE' + } + } + } + } + } } post { always { @@ -247,6 +262,7 @@ pipeline { echo "This is a MERGE event" addGitLabMRComment comment: message } + echo "Pipeline is SUCCESSFUL" } } failure { @@ -256,6 +272,7 @@ pipeline { echo "This is a MERGE event" addGitLabMRComment comment: message } + echo "Pipeline FAILED" } } } diff --git a/ci-scripts/Jenkinsfile-push-registry b/ci-scripts/Jenkinsfile-push-registry new file mode 100644 index 0000000000..91d6136e0a --- /dev/null +++ b/ci-scripts/Jenkinsfile-push-registry @@ -0,0 +1,86 @@ +#!/bin/groovy +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +// Location of the python executor node shall be in the same subnet as the others servers +def nodeExecutor = params.nodeExecutor + +// Name of the phone resource +def ciServerResource = params.serverResource + +pipeline { + agent { + label nodeExecutor + } + options { + disableConcurrentBuilds() + ansiColor('xterm') + lock (ciServerResource) + } + stages { + stage ("Verify Parameters") { + steps { + script { + echo '\u2705 \u001B[32mVerify Parameters\u001B[0m' + def allParametersPresent = true + + // It is already to late to check it + if (params.nodeExecutor != null) { + echo "Docker Push executor node : ${nodeExecutor}" + } + if (params.serverResource == null) { + allParametersPresent = false + } + } + } + } + stage ("Push to DockerHub") { + steps { + script { + WEEK_TAG = sh returnStdout: true, script: 'date +"%Y.w%U"' + WEEK_TAG = WEEK_TAG.trim() + + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.DH_Credentials}", usernameVariable: 'DH_Username', passwordVariable: 'DH_Password'] + ]) { + def listOfImages = ["oai-enb", "oai-gnb", "oai-lte-ue", "oai-nr-ue"] + sh "docker login -u ${DH_Username} -p ${DH_Password} > /dev/null 2>&1" + listOfImages.eachWithIndex { item, iindex -> + sh "docker image tag ${item}:develop ${DH_Username}/${item}:develop" + sh "docker image tag ${item}:develop ${DH_Username}/${item}:${WEEK_TAG}" + sh "docker push --quiet ${DH_Username}/${item}:${WEEK_TAG}" + sh "docker push --quiet ${DH_Username}/${item}:develop" + sh "docker rmi ${DH_Username}/${item}:${WEEK_TAG} ${DH_Username}/${item}:develop" + } + sh "docker logout > /dev/null 2>&1" + } + } + } + } + } + post { + always { + script { + echo "End of Registry Push" + } + } + } +} diff --git a/ci-scripts/Jenkinsfile-tmp-multi-enb-nsa b/ci-scripts/Jenkinsfile-tmp-multi-enb-nsa index 95aa4046d7..3243d1645d 100644 --- a/ci-scripts/Jenkinsfile-tmp-multi-enb-nsa +++ b/ci-scripts/Jenkinsfile-tmp-multi-enb-nsa @@ -265,6 +265,21 @@ pipeline { if(fileExists("enb.log.${env.BUILD_ID}.zip")) { archiveArtifacts "enb.log.${env.BUILD_ID}.zip" } + } + } + } + stage('Log Collection (CN)') { + steps { + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'] + ]) { + echo '\u2705 \u001B[32mLog Transfer (CN)\u001B[0m' + sh "sshpass -p \'${EPC_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${EPC_Username}@${params.EPC_IPAddress}:${EPC_SourceCodePath}/logs/oai-cn5g.log.zip ./oai-cn5g.log.${env.BUILD_ID}.zip || true" + } + script { + if(fileExists("oai-cn5g.log.${env.BUILD_ID}.zip")) { + archiveArtifacts "oai-cn5g.log.${env.BUILD_ID}.zip" + } if(fileExists("ci-scripts/test_results.html")) { sh "mv ci-scripts/test_results.html test_results-${JOB_NAME}.html" sh "sed -i -e 's#TEMPLATE_JOB_NAME#${JOB_NAME}#' -e 's@build #TEMPLATE_BUILD_ID@build #${BUILD_ID}@' -e 's#Build-ID: TEMPLATE_BUILD_ID#Build-ID: ${BUILD_ID}#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html" diff --git a/ci-scripts/Jenkinsfile-trig-nsa b/ci-scripts/Jenkinsfile-trig-nsa index 2dcaf1a04f..40d74f4da0 100644 --- a/ci-scripts/Jenkinsfile-trig-nsa +++ b/ci-scripts/Jenkinsfile-trig-nsa @@ -47,30 +47,38 @@ pipeline { COMMIT_ID=sh returnStdout: true, script: """curl --silent "https://gitlab.eurecom.fr/api/v4/projects/oai%2Fopenairinterface5g/merge_requests/${MR}" | jq ".sha" || true """ COMMIT_ID=COMMIT_ID.trim() echo "Testing NSA on : ${MR} ${SRC_BRANCH} ${COMMIT_ID}" - //calling NSA sub job - build job: "RAN-NSA-Mini-Module", wait : true, propagate : false, parameters: [ + //calling NSA B200 + build job: "RAN-NSA-B200-Module-LTEBOX", wait : true, propagate : false, parameters: [ string(name: 'eNB_MR', value: String.valueOf(MR)), string(name: 'eNB_Branch', value: String.valueOf(SRC_BRANCH)), string(name: 'eNB_CommitID', value: String.valueOf(COMMIT_ID)), string(name: 'eNB_TargetBranch', value: String.valueOf(TARGET_BRANCH)), booleanParam(name: 'eNB_AllowMergeRequestProcess', value: Boolean.valueOf(ALLOW_MERGE)) ] - //calling NSA long sub job -// build job: "RAN-NSA-Mini-Module-Long", wait : true, propagate : false, parameters: [ -// string(name: 'eNB_MR', value: String.valueOf(MR)), -// string(name: 'eNB_Branch', value: String.valueOf(SRC_BRANCH)), -// string(name: 'eNB_CommitID', value: String.valueOf(COMMIT_ID)), -// string(name: 'eNB_TargetBranch', value: String.valueOf(TARGET_BRANCH)), -// booleanParam(name: 'eNB_AllowMergeRequestProcess', value: Boolean.valueOf(ALLOW_MERGE)) -// ] - //calling NSA attach/detach job -// build job: "RAN-NSA-Mini-Module-Attach-Detach", wait : true, propagate : false, parameters: [ -// string(name: 'eNB_MR', value: String.valueOf(MR)), -// string(name: 'eNB_Branch', value: String.valueOf(SRC_BRANCH)), -// string(name: 'eNB_CommitID', value: String.valueOf(COMMIT_ID)), -// string(name: 'eNB_TargetBranch', value: String.valueOf(TARGET_BRANCH)), -// booleanParam(name: 'eNB_AllowMergeRequestProcess', value: Boolean.valueOf(ALLOW_MERGE)) -// ] + //calling NSA 2x2 + build job: "RAN-NSA-2x2-Module-OAIEPC", wait : true, propagate : false, parameters: [ + string(name: 'eNB_MR', value: String.valueOf(MR)), + string(name: 'eNB_Branch', value: String.valueOf(SRC_BRANCH)), + string(name: 'eNB_CommitID', value: String.valueOf(COMMIT_ID)), + string(name: 'eNB_TargetBranch', value: String.valueOf(TARGET_BRANCH)), + booleanParam(name: 'eNB_AllowMergeRequestProcess', value: Boolean.valueOf(ALLOW_MERGE)) + ] + //calling LTE 2x2 + build job: "RAN-LTE-2x2-Module-OAIEPC", wait : true, propagate : false, parameters: [ + string(name: 'eNB_MR', value: String.valueOf(MR)), + string(name: 'eNB_Branch', value: String.valueOf(SRC_BRANCH)), + string(name: 'eNB_CommitID', value: String.valueOf(COMMIT_ID)), + string(name: 'eNB_TargetBranch', value: String.valueOf(TARGET_BRANCH)), + booleanParam(name: 'eNB_AllowMergeRequestProcess', value: Boolean.valueOf(ALLOW_MERGE)) + ] + //calling SA + build job: "RAN-SA-Module-CN5G", wait : true, propagate : false, parameters: [ + string(name: 'eNB_MR', value: String.valueOf(MR)), + string(name: 'eNB_Branch', value: String.valueOf(SRC_BRANCH)), + string(name: 'eNB_CommitID', value: String.valueOf(COMMIT_ID)), + string(name: 'eNB_TargetBranch', value: String.valueOf(TARGET_BRANCH)), + booleanParam(name: 'eNB_AllowMergeRequestProcess', value: Boolean.valueOf(ALLOW_MERGE)) + ] } } diff --git a/ci-scripts/ci_ueinfra.yaml b/ci-scripts/ci_ueinfra.yaml index 619e8fba15..51acb75968 100644 --- a/ci-scripts/ci_ueinfra.yaml +++ b/ci-scripts/ci_ueinfra.yaml @@ -4,7 +4,9 @@ idefix: Kind : quectel Process : Name : quectel-CM - Cmd : /home/oaicicd/quectel-CM/quectel-CM -s oai.ipv4 -4 + Cmd : /home/oaicicd/quectel-CM/quectel-CM -4 -s + Apn : + ltebox : oai.ipv4 WakeupScript : ci_ctl_qtel.py /dev/ttyUSB2 wup DetachScript : ci_ctl_qtel.py /dev/ttyUSB2 detach LogStore : /media/usb-drive/ci_qlogs @@ -14,22 +16,29 @@ idefix: HostUsername : oaicicd HostPassword : oaicicd HostSourceCodePath : none + MTU : 1500 nrmodule2_quectel: ID: nrmodule2_quectel State : enabled Kind : quectel Process : Name : quectel-CM - Cmd : /home/nrmodule2/quectel-CM/quectel-CM -s oai.ipv4 -4 + Cmd : /home/nrmodule2/quectel-CM/quectel-CM -4 -s + Apn : + OAICN5G : oai + OAI-Rel14-Docker : oai.ipv4 WakeupScript : ci_ctl_qtel.py /dev/ttyUSB7 wup DetachScript : ci_ctl_qtel.py /dev/ttyUSB7 detach LogStore : /media/ci_qlogs - PLMN : 20899 + PLMN : 20897 UENetwork : wwan1 HostIPAddress : 192.168.18.189 HostUsername : nrmodule2 HostPassword : linux HostSourceCodePath : none + StartCommands : + - sudo -S ip link set dev wwan1 mtu 1500 + MTU : 1500 dummy: ID: '' State : '' diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index ea09cd0585..ff2b261424 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -196,6 +196,7 @@ class Containerize(): # the potential merge. Note that merge conflicts should already been checked earlier imageTag = 'develop' sharedTag = 'develop' + forceSharedImageBuild = False if (self.ranAllowMerge): imageTag = 'ci-temp' if self.ranTargetBranch == '': @@ -204,6 +205,13 @@ class Containerize(): else: logging.debug('Merging with the target branch: ' + self.ranTargetBranch) mySSH.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5) + mySSH.command('git diff HEAD..origin/develop -- docker/Dockerfile.ran' + self.dockerfileprefix + ' | grep -i INDEX', '\$', 5) + result = re.search('index', mySSH.getBefore()) + if result is not None: + forceSharedImageBuild = True + sharedTag = 'ci-temp' + else: + forceSharedImageBuild = True # if asterix, copy the entitlement and subscription manager configurations if self.host == 'Red Hat': @@ -215,13 +223,14 @@ class Containerize(): sharedimage = 'ran-build' # Let's remove any previous run artifacts if still there mySSH.command(self.cli + ' image prune --force', '\$', 30) - if (not self.ranAllowMerge): - mySSH.command(self.cli + ' image rm ' + sharedimage + ':' + sharedTag, '\$', 30) + if forceSharedImageBuild: + mySSH.command(self.cli + ' image rm ' + sharedimage + ':' + sharedTag + ' || true', '\$', 30) for image,pattern in imageNames: - mySSH.command(self.cli + ' image rm ' + image + ':' + imageTag, '\$', 30) + mySSH.command(self.cli + ' image rm ' + image + ':' + imageTag + ' || true', '\$', 30) # Build the shared image only on Push Events (not on Merge Requests) - if (not self.ranAllowMerge): + # On when the shared image docker file is being modified. + if forceSharedImageBuild: mySSH.command(self.cli + ' build ' + self.cliBuildOptions + ' --target ' + sharedimage + ' --tag ' + sharedimage + ':' + sharedTag + ' --file docker/Dockerfile.ran' + self.dockerfileprefix + ' --build-arg NEEDED_GIT_PROXY="http://proxy.eurecom.fr:8080" . > cmake_targets/log/ran-build.log 2>&1', '\$', 1600) # First verify if the shared image was properly created. status = True diff --git a/ci-scripts/cls_module_ue.py b/ci-scripts/cls_module_ue.py index 96d4e0310e..74ae9c207e 100644 --- a/ci-scripts/cls_module_ue.py +++ b/ci-scripts/cls_module_ue.py @@ -61,7 +61,7 @@ class Module_UE: #this method checks if the specified Process is running on the server hosting the module #if not it will be started - def CheckCMProcess(self): + def CheckCMProcess(self,CNType): HOST=self.HostUsername+'@'+self.HostIPAddress COMMAND="ps aux | grep " + self.Process['Name'] + " | grep -v grep " logging.debug(COMMAND) @@ -76,7 +76,7 @@ class Module_UE: logging.debug('Starting ' + self.Process['Name']) mySSH = sshconnection.SSHConnection() mySSH.open(self.HostIPAddress, self.HostUsername, self.HostPassword) - mySSH.command('echo $USER; echo ' + self.HostPassword + ' | nohup sudo -S ' + self.Process['Cmd'] + ' &','\$',5) + mySSH.command('echo $USER; echo ' + self.HostPassword + ' | nohup sudo -S ' + self.Process['Cmd'] + ' ' + self.Process['Apn'][CNType] + ' &','\$',5) mySSH.close() #checking the process time.sleep(5) @@ -131,6 +131,33 @@ class Module_UE: logging.debug('\u001B[1;37;41m Module IP Address Not Found! \u001B[0m') return -1 + def CheckModuleMTU(self): + HOST=self.HostUsername+'@'+self.HostIPAddress + response= [] + tentative = 3 + while (len(response)==0) and (tentative>0): + COMMAND="ip a show dev " + self.UENetwork + " | grep mtu" + logging.debug(COMMAND) + ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE) + response = ssh.stdout.readlines() + tentative-=1 + time.sleep(10) + if (tentative==0) and (len(response)==0): + logging.debug('\u001B[1;37;41m Module NIC MTU Not Found! Time expired \u001B[0m') + return -1 + else: #check response + result = re.search('mtu (?P[0-9]+)', response[0].decode("utf-8") ) + if result is not None: + if (result.group('mtu') is not None) and (str(result.group('mtu'))==str(self.MTU)) : + logging.debug('\u001B[1mUE Module NIC MTU is ' + str(self.MTU) + ' as expected\u001B[0m') + return 0 + else: + logging.debug('\u001B[1;37;41m Incorrect Module NIC MTU ' + str(result.group('mtu')) + '! Expected : ' + str(self.MTU) + '\u001B[0m') + return -1 + else: + logging.debug('\u001B[1;37;41m Module NIC MTU Not Found! \u001B[0m') + return -1 + def EnableTrace(self): if self.ue_trace=="yes": mySSH = sshconnection.SSHConnection() diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index f1ab8c106f..92a4e8637e 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -388,22 +388,45 @@ class OaiCiTest(): #RH Module_UE = cls_module_ue.Module_UE(InfraUE.ci_ue_infra[self.ue_id]) Module_UE.ue_trace=ue_trace - is_module=Module_UE.CheckCMProcess() + is_module=Module_UE.CheckCMProcess(EPC.Type) if is_module: Module_UE.EnableTrace() time.sleep(5) - Module_UE.Command("wup") - logging.debug("Waiting for IP address to be assigned") - time.sleep(20) - logging.debug("Retrieve IP address") - status=Module_UE.GetModuleIPAddress() - if status==0: + + # Looping attach / detach / wait to be successful at least once + cnt = 0 + status = -1 + while cnt < 4: + Module_UE.Command("wup") + logging.debug("Waiting for IP address to be assigned") + time.sleep(20) + logging.debug("Retrieve IP address") + status=Module_UE.GetModuleIPAddress() + if status==0: + cnt = 10 + else: + cnt += 1 + Module_UE.Command("detach") + time.sleep(20) + + if cnt == 10 and status == 0: HTML.CreateHtmlTestRow(Module_UE.UEIPAddress, 'OK', CONST.ALL_PROCESSES_OK) logging.debug('UE IP addresss : '+ Module_UE.UEIPAddress) + #execute additional commands from yaml file after UE attach + SSH = sshconnection.SSHConnection() + SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) + if hasattr(Module_UE,'StartCommands'): + for startcommand in Module_UE.StartCommands: + cmd = 'echo ' + Module_UE.HostPassword + ' | ' + startcommand + SSH.command(cmd,'\$',5) + SSH.close() + #check that the MTU is as expected / requested + Module_UE.CheckModuleMTU() else: #status==-1 failed to retrieve IP address HTML.CreateHtmlTestRow('N/A', 'KO', CONST.UE_IP_ADDRESS_ISSUE) self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE) return + def InitializeOAIUE(self,HTML,RAN,EPC,COTS_UE,InfraUE): @@ -1033,14 +1056,34 @@ class OaiCiTest(): #Attention, as opposed to InitializeUE, the connect manager process is not checked as it is supposed to be active already #only 1- module wakeup, 2- check IP address Module_UE = cls_module_ue.Module_UE(InfraUE.ci_ue_infra[self.ue_id]) - Module_UE.Command("wup") - logging.debug("Waiting for IP address to be assigned") - time.sleep(20) - logging.debug("Retrieve IP address") - status=Module_UE.GetModuleIPAddress() - if status==0: + status = -1 + cnt = 0 + while cnt < 4: + Module_UE.Command("wup") + logging.debug("Waiting for IP address to be assigned") + time.sleep(20) + logging.debug("Retrieve IP address") + status=Module_UE.GetModuleIPAddress() + if status==0: + cnt = 10 + else: + cnt += 1 + Module_UE.Command("detach") + time.sleep(20) + + if cnt == 10 and status == 0: HTML.CreateHtmlTestRow(Module_UE.UEIPAddress, 'OK', CONST.ALL_PROCESSES_OK) logging.debug('UE IP addresss : '+ Module_UE.UEIPAddress) + #execute additional commands from yaml file after UE attach + SSH = sshconnection.SSHConnection() + SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) + if hasattr(Module_UE,'StartCommands'): + for startcommand in Module_UE.StartCommands: + cmd = 'echo ' + Module_UE.HostPassword + ' | ' + startcommand + SSH.command(cmd,'\$',5) + SSH.close() + #check that the MTU is as expected / requested + Module_UE.CheckModuleMTU() else: #status==-1 failed to retrieve IP address HTML.CreateHtmlTestRow('N/A', 'KO', CONST.UE_IP_ADDRESS_ISSUE) self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC,InfraUE) @@ -1539,6 +1582,8 @@ class OaiCiTest(): #target address is different depending on EPC type if re.match('OAI-Rel14-Docker', EPC.Type, re.IGNORECASE): Target = EPC.MmeIPAddress + elif re.match('OAICN5G', EPC.Type, re.IGNORECASE): + Target = '8.8.8.8' else: Target = EPC.IPAddress #ping from module NIC rather than IP address to make sure round trip is over the air @@ -1986,7 +2031,7 @@ class OaiCiTest(): if type==0: result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(?P[0-9]+)/ +(?P[0-9]+)', str(line)) else: - result = re.search('^\[ \d\].+ +(?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(?P[0-9]+)\/(?P[0-9]+)', str(line)) + result = re.search('^\[\s+\d\].+ (?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(?P[0-9]+)\/\s*(?P[0-9]+)', str(line)) if result is not None: bitrate = result.group('bitrate') @@ -2230,85 +2275,157 @@ class OaiCiTest(): def Iperf_Module(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue,EPC, Module_UE): - SSH = sshconnection.SSHConnection() - #RH temporary quick n dirty for test - SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) - cmd = 'echo ' + EPC.Password + ' | sudo -S ip link set dev tun5 mtu 1358' - SSH.command(cmd,'\$',5) - SSH.close() - - - #kill iperf processes before (in case there are still some remaining) - SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) - cmd = 'killall --signal=SIGKILL iperf' - SSH.command(cmd,'\$',5) - SSH.close() - SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) - cmd = 'killall --signal=SIGKILL iperf' - SSH.command(cmd,'\$',5) - SSH.close() - - - iperf_time = self.Iperf_ComputeTime() - if self.iperf_direction=="DL": - logging.debug("Iperf for Module in DL mode detected") - #server side UE - SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) - cmd = 'rm iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' - SSH.command(cmd,'\$',5) - cmd = 'echo $USER; nohup /opt/iperf-2.0.10/iperf -s -B ' + UE_IPAddress + ' -u 2>&1 > iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' - SSH.command(cmd,'\$',5) - SSH.close() - #client side EPC + if (re.match('OAI-Rel14-Docker', EPC.Type, re.IGNORECASE)) or (re.match('OAICN5G', EPC.Type, re.IGNORECASE)): + #retrieve trf-gen container IP address + SSH = sshconnection.SSHConnection() SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) - cmd = 'rm iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log' - SSH.command(cmd,'\$',5) - cmd = 'iperf -c ' + UE_IPAddress + ' ' + self.iperf_args + ' 2>&1 > iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log' - SSH.command(cmd,'\$',int(iperf_time)*5.0) + SSH.command('docker inspect --format="TRF_IP_ADDR = {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" prod-trf-gen', '\$', 5) + result = re.search('TRF_IP_ADDR = (?P[0-9\.]+)', SSH.getBefore()) + if result is not None: + trf_gen_IP = result.group('trf_ip_addr') SSH.close() - #copy the 2 resulting files locally - SSH.copyin(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword, 'iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log', '.') - SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, 'iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log', '.') - #send for analysis - filename='iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' - self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, self.iperf_args,filename,1) - - elif self.iperf_direction=="UL":#does not work at the moment - logging.debug("Iperf for Module in UL mode detected") - #server side EPC - SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) - cmd = 'rm iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' - SSH.command(cmd,'\$',5) - cmd = 'echo $USER; nohup iperf -s -u 2>&1 > iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' - SSH.command(cmd,'\$',5) - SSH.close() - - #client side UE + #kill iperf processes on UE side before (in case there are still some remaining) SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) - cmd = 'rm iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log' + cmd = 'killall --signal=SIGKILL iperf' SSH.command(cmd,'\$',5) - SSH.command('/opt/iperf-2.0.10/iperf -c 192.172.0.1 ' + self.iperf_args + ' 2>&1 > iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log', '\$', int(iperf_time)*5.0) SSH.close() - #copy the 2 resulting files locally - SSH.copyin(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword, 'iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log', '.') - SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, 'iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log', '.') - #send for analysis - filename='iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' - self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, self.iperf_args,filename,1) - else : - logging.debug("Incorrect or missing IPERF direction in XML") + iperf_time = self.Iperf_ComputeTime() + if self.iperf_direction=="DL": + logging.debug("Iperf for Module in DL mode detected") + #server side UE + server_filename='iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' + SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) + cmd = 'rm ' + server_filename + SSH.command(cmd,'\$',5) + cmd = 'echo $USER; nohup iperf -s -B ' + UE_IPAddress + ' -u 2>&1 > ' + server_filename + ' &' + SSH.command(cmd,'\$',5) + SSH.close() + #client side EPC + SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) + client_filename = 'iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log' + SSH.command('docker exec -it prod-trf-gen /bin/bash -c "killall --signal SIGKILL iperf"', '\$', 5) + iperf_cmd = 'bin/iperf -c ' + UE_IPAddress + ' ' + self.iperf_args + ' 2>&1 > ' + client_filename + cmd = 'docker exec -it prod-trf-gen /bin/bash -c \"' + iperf_cmd + '\"' + SSH.command(cmd,'\$',int(iperf_time)*5.0) + SSH.command('docker cp prod-trf-gen:/iperf-2.0.13/'+ client_filename + ' ' + EPC.SourceCodePath, '\$', 5) + SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, EPC.SourceCodePath + '/' + client_filename, '.') + SSH.close() - #kill iperf processes after to be clean - SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) - cmd = 'killall --signal=SIGKILL iperf' - SSH.command(cmd,'\$',5) - SSH.close() - SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) - cmd = 'killall --signal=SIGKILL iperf' - SSH.command(cmd,'\$',5) - SSH.close() - return + #copy the 2 resulting files locally + SSH.copyin(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword, server_filename, '.') + SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, client_filename, '.') + #send for analysis + self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, self.iperf_args,server_filename,1) + + elif self.iperf_direction=="UL": + logging.debug("Iperf for Module in UL mode detected") + #server side EPC + SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) + server_filename = 'iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' + SSH.command('docker exec -it prod-trf-gen /bin/bash -c "killall --signal SIGKILL iperf"', '\$', 5) + iperf_cmd = 'echo $USER; nohup bin/iperf -s -u 2>&1 > ' + server_filename + cmd = 'docker exec -it prod-trf-gen /bin/bash -c \"' + iperf_cmd + '\"' + SSH.command(cmd,'\$',5) + SSH.close() + + #client side UE + SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) + client_filename = 'iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log' + cmd = 'rm '+ client_filename + SSH.command(cmd,'\$',5) + SSH.command('iperf -B ' + UE_IPAddress + ' -c ' + trf_gen_IP + ' ' + self.iperf_args + ' 2>&1 > ' + client_filename, '\$', int(iperf_time)*5.0) + SSH.close() + + #once client is done, retrieve the server file from container to EPC Host + SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) + SSH.command('docker cp prod-trf-gen:/iperf-2.0.13/' + server_filename + ' ' + EPC.SourceCodePath, '\$', 5) + SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, EPC.SourceCodePath + '/' + server_filename, '.') + SSH.close() + + #copy the 2 resulting files locally + SSH.copyin(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword, client_filename, '.') + SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, server_filename, '.') + #send for analysis + self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, self.iperf_args,server_filename,1) + else : + logging.debug("Incorrect or missing IPERF direction in XML") + + else: #default is ltebox + + SSH = sshconnection.SSHConnection() + + #kill iperf processes before (in case there are still some remaining) + SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) + cmd = 'killall --signal=SIGKILL iperf' + SSH.command(cmd,'\$',5) + SSH.close() + SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) + cmd = 'killall --signal=SIGKILL iperf' + SSH.command(cmd,'\$',5) + SSH.close() + + + iperf_time = self.Iperf_ComputeTime() + if self.iperf_direction=="DL": + logging.debug("Iperf for Module in DL mode detected") + #server side UE + SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) + cmd = 'rm iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' + SSH.command(cmd,'\$',5) + cmd = 'echo $USER; nohup /opt/iperf-2.0.10/iperf -s -B ' + UE_IPAddress + ' -u 2>&1 > iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log &' + SSH.command(cmd,'\$',5) + SSH.close() + #client side EPC + SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) + cmd = 'rm iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log' + SSH.command(cmd,'\$',5) + cmd = 'iperf -c ' + UE_IPAddress + ' ' + self.iperf_args + ' 2>&1 > iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log' + SSH.command(cmd,'\$',int(iperf_time)*5.0) + SSH.close() + #copy the 2 resulting files locally + SSH.copyin(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword, 'iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log', '.') + SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, 'iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log', '.') + #send for analysis + filename='iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' + self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, self.iperf_args,filename,1) + + elif self.iperf_direction=="UL": + logging.debug("Iperf for Module in UL mode detected") + #server side EPC + SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) + cmd = 'rm iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' + SSH.command(cmd,'\$',5) + cmd = 'echo $USER; nohup iperf -s -u 2>&1 > iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log &' + SSH.command(cmd,'\$',5) + SSH.close() + + #client side UE + SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) + cmd = 'rm iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log' + SSH.command(cmd,'\$',5) + SSH.command('/opt/iperf-2.0.10/iperf -c 192.172.0.1 ' + self.iperf_args + ' 2>&1 > iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log', '\$', int(iperf_time)*5.0) + SSH.close() + + #copy the 2 resulting files locally + SSH.copyin(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword, 'iperf_client_' + self.testCase_id + '_' + self.ue_id + '.log', '.') + SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, 'iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log', '.') + #send for analysis + filename='iperf_server_' + self.testCase_id + '_' + self.ue_id + '.log' + self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, self.iperf_args,filename,1) + else : + logging.debug("Incorrect or missing IPERF direction in XML") + + #kill iperf processes after to be clean + SSH.open(Module_UE.HostIPAddress, Module_UE.HostUsername, Module_UE.HostPassword) + cmd = 'killall --signal=SIGKILL iperf' + SSH.command(cmd,'\$',5) + SSH.close() + SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password) + cmd = 'killall --signal=SIGKILL iperf' + SSH.command(cmd,'\$',5) + SSH.close() + return def Iperf_common(self, lock, UE_IPAddress, device_id, idx, ue_num, statusQueue,EPC): try: diff --git a/ci-scripts/conf_files/channelmod_rfsimu.conf b/ci-scripts/conf_files/channelmod_rfsimu.conf index 9a6ded24f1..cd4490d9ba 100644 --- a/ci-scripts/conf_files/channelmod_rfsimu.conf +++ b/ci-scripts/conf_files/channelmod_rfsimu.conf @@ -15,7 +15,7 @@ channelmod = { ds_tdl = 0; }, { - model_name = "rfsimu_channel_ue1" + model_name = "rfsimu_channel_ue0" type = "AWGN"; ploss_dB = 0; noise_power_dB = 0; diff --git a/ci-scripts/conf_files/enb.band38.lte_2x2.100PRB.usrpn310.conf b/ci-scripts/conf_files/enb.band38.lte_2x2.100PRB.usrpn310.conf new file mode 100644 index 0000000000..d2e91fb872 --- /dev/null +++ b/ci-scripts/conf_files/enb.band38.lte_2x2.100PRB.usrpn310.conf @@ -0,0 +1,281 @@ +Active_eNBs = ( "eNB-Eurecom-B38"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + ////////// Identification parameters: + eNB_ID = 0xe02; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB-Eurecom-B38"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ( { mcc = 208; mnc = 97; mnc_length = 2; } ); + + tr_s_preference = "local_mac" + + ////////// Physical parameters: + + component_carriers = ( + { + node_function = "3GPP_eNODEB"; + node_timing = "synch_to_ext_device"; + node_synch_ref = 0; + frame_type = "TDD"; + tdd_config = 1; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 38; + downlink_frequency = 2605000000L; + nr_scg_ssb_freq = 624608; + uplink_frequency_offset = 0; + Nid_cell = 0; + N_RB_DL = 100; + Nid_cell_mbsfn = 0; + nb_antenna_ports = 1; + nb_antennas_tx = 2; + nb_antennas_rx = 2; + tx_gain = 90; + rx_gain = 125; + pbch_repetition = "FALSE"; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 0; + pucch_nCS_AN = 0; + pucch_n1_AN = 0; + pdsch_referenceSignalPower = -29; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 1; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -96; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -104; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 4; + rach_preambleInitialReceivedTargetPower = -108; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + ue_TransmissionMode = 1; + + //Parameters for SIB18 + rxPool_sc_CP_Len = "normal"; + rxPool_sc_Period = "sf40"; + rxPool_data_CP_Len = "normal"; + rxPool_ResourceConfig_prb_Num = 20; + rxPool_ResourceConfig_prb_Start = 5; + rxPool_ResourceConfig_prb_End = 44; + rxPool_ResourceConfig_offsetIndicator_present = "prSmall"; + rxPool_ResourceConfig_offsetIndicator_choice = 0; + rxPool_ResourceConfig_subframeBitmap_present = "prBs40"; + rxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "00000000000000000000"; + rxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5; + rxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0; +/* rxPool_dataHoppingConfig_hoppingParameter = 0; + rxPool_dataHoppingConfig_numSubbands = "ns1"; + rxPool_dataHoppingConfig_rbOffset = 0; + rxPool_commTxResourceUC-ReqAllowed = "TRUE"; +*/ + // Parameters for SIB19 + discRxPool_cp_Len = "normal" + discRxPool_discPeriod = "rf32" + discRxPool_numRetx = 1; + discRxPool_numRepetition = 2; + discRxPool_ResourceConfig_prb_Num = 5; + discRxPool_ResourceConfig_prb_Start = 3; + discRxPool_ResourceConfig_prb_End = 21; + discRxPool_ResourceConfig_offsetIndicator_present = "prSmall"; + discRxPool_ResourceConfig_offsetIndicator_choice = 0; + discRxPool_ResourceConfig_subframeBitmap_present = "prBs40"; + discRxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "f0ffffffff"; + discRxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5; + discRxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0; + + } + ); + + + srb1_parameters : + { + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + timer_poll_retransmit = 80; + + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] + timer_reordering = 35; + + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] + timer_status_prohibit = 0; + + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] + poll_pdu = 4; + + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] + poll_byte = 99999; + + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] + max_retx_threshold = 4; + } + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "CI_MME_IP_ADDR"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + enable_measurement_reports = "no"; + + ///X2 + enable_x2 = "yes"; + t_reloc_prep = 1000; /* unit: millisecond */ + tx2_reloc_overall = 2000; /* unit: millisecond */ + t_dc_prep = 1000; /* unit: millisecond */ + t_dc_overall = 2000; /* unit: millisecond */ + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "eno1"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "CI_ENB_IP_ADDR"; + ENB_INTERFACE_NAME_FOR_S1U = "eno1"; + ENB_IPV4_ADDRESS_FOR_S1U = "CI_ENB_IP_ADDR"; + ENB_PORT_FOR_S1U = 2152; # Spec 2152 + ENB_IPV4_ADDRESS_FOR_X2C = "CI_ENB_IP_ADDR"; + ENB_PORT_FOR_X2C = 36422; # Spec 36422 + }; + } +); + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + phy_test_mode = 0; + scheduler_mode = "fairRR"; + bler_target_upper = 20.0; + bler_target_lower = 10.0; + max_ul_rb_index = 27; + puSch10xSnr = 200; + puCch10xSnr = 150; + } +); + +L1s = ( + { + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 200; + pucch1_dtx_threshold = 5 + pucch1ab_dtx_threshold =0; + } +); + +RUs = ( + { + local_rf = "yes" + nb_tx = 2 + nb_rx = 2 + att_tx = 0 + att_rx = 0; + bands = [38]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 75; + eNB_instances = [0]; + sdr_addrs = "mgmt_addr=192.168.18.241,addr=192.168.20.2,second_addr=192.168.10.2"; + + } +); + +THREAD_STRUCT = ( + { + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_SINGLE_THREAD"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; + } +); + +NETWORK_CONTROLLER : +{ + FLEXRAN_ENABLED = "no"; + FLEXRAN_INTERFACE_NAME = "lo"; + FLEXRAN_IPV4_ADDRESS = "127.0.0.1"; + FLEXRAN_PORT = 2210; + FLEXRAN_CACHE = "/mnt/oai_agent_cache"; + FLEXRAN_AWAIT_RECONF = "no"; +}; + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; + diff --git a/ci-scripts/conf_files/enb.band38.nsa_2x2.100PRB.usrpn310.conf b/ci-scripts/conf_files/enb.band38.nsa_2x2.100PRB.usrpn310.conf index db0802fdd7..6c8d5ba6f0 100644 --- a/ci-scripts/conf_files/enb.band38.nsa_2x2.100PRB.usrpn310.conf +++ b/ci-scripts/conf_files/enb.band38.nsa_2x2.100PRB.usrpn310.conf @@ -6,7 +6,7 @@ eNBs = ( { ////////// Identification parameters: - eNB_ID = 0xe00; + eNB_ID = 0xe04; cell_type = "CELL_MACRO_ENB"; @@ -14,7 +14,7 @@ eNBs = // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = 1; - plmn_list = ( { mcc = 208; mnc = 99; mnc_length = 2; } ); + plmn_list = ( { mcc = 208; mnc = 97; mnc_length = 2; } ); tr_s_preference = "local_mac" @@ -31,6 +31,7 @@ eNBs = prefix_type = "NORMAL"; eutra_band = 38; downlink_frequency = 2605000000L; + nr_scg_ssb_freq = 624608; uplink_frequency_offset = 0; Nid_cell = 0; N_RB_DL = 100; @@ -209,8 +210,8 @@ MACRLCs = ( scheduler_mode = "fairRR"; bler_target_upper = 20.0; bler_target_lower = 10.0; - max_ul_rb_index = 24; - puSch10xSnr = 100; + max_ul_rb_index = 27; + puSch10xSnr = 200; puCch10xSnr = 150; } ); diff --git a/ci-scripts/conf_files/gNB_SA_n78_106PRB.2x2_usrpn310.conf b/ci-scripts/conf_files/gNB_SA_n78_106PRB.2x2_usrpn310.conf new file mode 100644 index 0000000000..9bf3136690 --- /dev/null +++ b/ci-scripts/conf_files/gNB_SA_n78_106PRB.2x2_usrpn310.conf @@ -0,0 +1,338 @@ +Active_gNBs = ( "gNB-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_CU_ID = 0xe00; + +# cell_type = "CELL_MACRO_GNB"; + + gNB_name = "gNB-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + + plmn_list = ({ + mcc = 208; + mnc = 99; + mnc_length = 2; + snssaiList = ( + { + sst = 1; + sd = 0x010203; // 0 false, else true + }, + { + sst = 1; + sd = 0x112233; // 0 false, else true + } + ); + }); + + nr_cellid = 12345678L + +# tr_s_preference = "local_mac" + + ////////// Physical parameters: + + ssb_SubcarrierOffset = 0; + pdsch_AntennaPorts = 1; + pusch_AntennaPorts = 2; + + pdcch_ConfigSIB1 = ( + { + controlResourceSetZero = 11; + searchSpaceZero = 0; + } + ); + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3301.68 MHz + 22*12*30e-3 MHz = 3309.6 + #absoluteFrequencySSB = 620640; + # this is 3300.60 MHz + 53*12*30e-3 MHz = 3319.68 + absoluteFrequencySSB = 621312; + # this is 3503.28 MHz + 22*12*30e-3 MHz = 3511.2 + #absoluteFrequencySSB = 634080; + # this is 3600.48 MHz + #absoluteFrequencySSB = 640032; + #dl_frequencyBand = 78; + # this is 3301.68 MHz + #dl_absoluteFrequencyPointA = 620112; + # this is 3300.60 MHz + dl_absoluteFrequencyPointA = 620040; + # this is 3502.56 MHz + #dl_absoluteFrequencyPointA = 633552; + # this is 3600.48 MHz + #dl_absoluteFrequencyPointA = 640032; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 106; + #initialDownlinkBWP + #genericParameters + # this is RBstart=0,L=106 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 28875; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 11; + initialDLBWPsearchSpaceZero = 0; + #pdsch-ConfigCommon + #pdschTimeDomainAllocationList (up to 16 entries) + initialDLBWPk0_0 = 0; + #initialULBWPmappingType + #0=typeA,1=typeB + initialDLBWPmappingType_0 = 0; + #this is SS=1,L=13 + initialDLBWPstartSymbolAndLength_0 = 40; + + initialDLBWPk0_1 = 0; + initialDLBWPmappingType_1 = 0; + #this is SS=1,L=5 + initialDLBWPstartSymbolAndLength_1 = 57; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 106; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 28875; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 12; + preambleReceivedTargetPower = -104; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 4; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + + # pusch-ConfigCommon (up to 16 elements) + initialULBWPk2_0 = 2; + initialULBWPmappingType_0 = 1 + # this is SS=2 L=13 + initialULBWPstartSymbolAndLength_0 = 41; + + initialULBWPk2_1 = 2; + initialULBWPmappingType_1 = 1; + # this is SS=0 L=4 + initialULBWPstartSymbolAndLength_1 = 52; + + initialULBWPk2_2 = 7; + initialULBWPmappingType_2 = 1; + # this is SS=10 L=4 + initialULBWPstartSymbolAndLength_2 = 52; + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; +# ssb_PositionsInBurs_BitmapPR +# 1=short, 2=medium, 3=long + ssb_PositionsInBurst_PR = 2; + ssb_PositionsInBurst_Bitmap = 1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = -25; + } + + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + ////////// AMF parameters: + amf_ip_address = ( { ipv4 = "192.168.69.131"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + + GNB_INTERFACE_NAME_FOR_NG_AMF = "em1"; + GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.18.194/24"; + GNB_INTERFACE_NAME_FOR_NGU = "em1"; + GNB_IPV4_ADDRESS_FOR_NGU = "192.168.18.194/24"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + } +); + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 200; + pucch_TargetSNRx10 = 150; + } +); + +L1s = ( + { + num_cc = 1; + tr_n_preference = "local_mac"; + pusch_proc_threads = 2; + prach_dtx_threshold = 120; + pucch0_dtx_threshold = 150; + } +); + +RUs = ( + { + local_rf = "yes" + nb_tx = 2 + nb_rx = 2 + att_tx = 0 + att_rx = 0; + bands = [78]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 75; + eNB_instances = [0]; + ##beamforming 1x2 matrix: 1 layer x 2 antennas + bf_weights = [0x00007fff, 0x0000]; + ##beamforming 1x4 matrix: 1 layer x 4 antennas + #bf_weights = [0x00007fff, 0x0000,0x0000, 0x0000]; + ## beamforming 2x2 matrix: + # bf_weights = [0x00007fff, 0x00000000, 0x00000000, 0x00007fff]; + ## beamforming 4x4 matrix: + #bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff]; + + sdr_addrs = "mgmt_addr=192.168.18.240,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" + } +); + +THREAD_STRUCT = ( + { + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_SINGLE_THREAD"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; + } +); + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + f1ap_log_level ="debug"; + f1ap_log_verbosity ="medium"; + }; diff --git a/ci-scripts/conf_files/gNB_SA_n78_133PRB.2x2_usrpn310.conf b/ci-scripts/conf_files/gNB_SA_n78_133PRB.2x2_usrpn310.conf new file mode 100644 index 0000000000..dfbbdf659d --- /dev/null +++ b/ci-scripts/conf_files/gNB_SA_n78_133PRB.2x2_usrpn310.conf @@ -0,0 +1,334 @@ +Active_gNBs = ( "gNB-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; +Num_Threads_PUSCH = 8; + +gNBs = +( + { + ////////// Identification parameters: + gNB_CU_ID = 0xe00; + +# cell_type = "CELL_MACRO_GNB"; + + gNB_name = "gNB-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + + plmn_list = ({ + mcc = 208; + mnc = 99; + mnc_length = 2; + snssaiList = ( + { + sst = 1; + sd = 0x010203; // 0 false, else true + }, + { + sst = 1; + sd = 0x112233; // 0 false, else true + } + ); + }); + + nr_cellid = 12345678L + +# tr_s_preference = "local_mac" + + ////////// Physical parameters: + + ssb_SubcarrierOffset = 0; + pdsch_AntennaPorts = 1; + pusch_AntennaPorts = 2; + + pdcch_ConfigSIB1 = ( + { + controlResourceSetZero = 10; + searchSpaceZero = 0; + } + ); + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3301.68 MHz + 22*12*30e-3 MHz = 3309.6 + absoluteFrequencySSB = 620640; + # this is 3502.56 MHz + #absoluteFrequencySSB = 633504; + # this is 3600.48 MHz + #absoluteFrequencySSB = 640032; + #dl_frequencyBand = 78; + # this is 3301.68 MHz + dl_absoluteFrequencyPointA = 620112; + # this is 3502.56 MHz + #dl_absoluteFrequencyPointA = 633504; + # this is 3600.48 MHz + #dl_absoluteFrequencyPointA = 640032; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 133; + #initialDownlinkBWP + #genericParameters + # this is RBstart=0,L=133 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 36300; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 10; + initialDLBWPsearchSpaceZero = 0; + #pdsch-ConfigCommon + #pdschTimeDomainAllocationList (up to 16 entries) + initialDLBWPk0_0 = 0; + #initialULBWPmappingType + #0=typeA,1=typeB + initialDLBWPmappingType_0 = 0; + #this is SS=1,L=13 + initialDLBWPstartSymbolAndLength_0 = 40; + + initialDLBWPk0_1 = 0; + initialDLBWPmappingType_1 = 0; + #this is SS=1,L=5 + initialDLBWPstartSymbolAndLength_1 = 57; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 133; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 36300; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 12; + preambleReceivedTargetPower = -108; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 4; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + + # pusch-ConfigCommon (up to 16 elements) + initialULBWPk2_0 = 6; + initialULBWPmappingType_0 = 1 + # this is SS=2 L=13 + initialULBWPstartSymbolAndLength_0 = 41; + + initialULBWPk2_1 = 6; + initialULBWPmappingType_1 = 1; + # this is SS=0 L=4 + initialULBWPstartSymbolAndLength_1 = 52; + + initialULBWPk2_2 = 7; + initialULBWPmappingType_2 = 1; + # this is SS=10 L=4 + initialULBWPstartSymbolAndLength_2 = 52; + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; +# ssb_PositionsInBurs_BitmapPR +# 1=short, 2=medium, 3=long + ssb_PositionsInBurst_PR = 2; + ssb_PositionsInBurst_Bitmap = 1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = -25; + } + + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + ////////// AMF parameters: + amf_ip_address = ( { ipv4 = "192.168.69.131"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + + GNB_INTERFACE_NAME_FOR_NG_AMF = "em1"; + GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.18.194/24"; + GNB_INTERFACE_NAME_FOR_NGU = "em1"; + GNB_IPV4_ADDRESS_FOR_NGU = "192.168.18.194/24"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + } +); + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 200; + pucch_TargetSNRx10 = 150; + } +); + +L1s = ( + { + num_cc = 1; + tr_n_preference = "local_mac"; + pusch_proc_threads = 2; + prach_dtx_threshold = 120; + } +); + +RUs = ( + { + local_rf = "yes" + nb_tx = 2 + nb_rx = 2 + att_tx = 0 + att_rx = 0; + bands = [78]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 75; + eNB_instances = [0]; + ##beamforming 1x2 matrix: 1 layer x 2 antennas + bf_weights = [0x00007fff, 0x0000]; + ##beamforming 1x4 matrix: 1 layer x 4 antennas + #bf_weights = [0x00007fff, 0x0000,0x0000, 0x0000]; + ## beamforming 2x2 matrix: + # bf_weights = [0x00007fff, 0x00000000, 0x00000000, 0x00007fff]; + ## beamforming 4x4 matrix: + #bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff]; + + sdr_addrs = "mgmt_addr=192.168.18.240,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" + } +); + +THREAD_STRUCT = ( + { + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_RU_L1_TRX_SPLIT"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; + } +); + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + f1ap_log_level ="debug"; + f1ap_log_verbosity ="medium"; + }; diff --git a/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf b/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf index 8d403cf4ce..1c62882406 100644 --- a/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf +++ b/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf @@ -228,9 +228,8 @@ MACRLCs = ( num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "local_RRC"; - ulsch_max_slots_inactivity = 1; pusch_TargetSNRx10 = 200; - pucch_TargetSNRx10 = 200; + pucch_TargetSNRx10 = 200; } ); @@ -270,6 +269,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/ci-scripts/conf_files/gnb.band66.tm1.106PRB.usrpn300.conf b/ci-scripts/conf_files/gnb.band66.tm1.106PRB.usrpn300.conf index 05c71c082e..850cf9a60c 100644 --- a/ci-scripts/conf_files/gnb.band66.tm1.106PRB.usrpn300.conf +++ b/ci-scripts/conf_files/gnb.band66.tm1.106PRB.usrpn300.conf @@ -259,6 +259,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf index 24dbdbd74b..a4452b202d 100644 --- a/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf @@ -13,7 +13,7 @@ gNBs = // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = 1; - plmn_list = ({mcc = 208; mnc = 99; mnc_length = 2;}); + plmn_list = ({mcc = 208; mnc = 97; mnc_length = 2;}); tr_s_preference = "local_mac" @@ -24,6 +24,7 @@ gNBs = pusch_AntennaPorts = 2; pusch_TargetSNRx10 = 200; pucch_TargetSNRx10 = 200; + ul_prbblacklist = "51,52,53,54" servingCellConfigCommon = ( { @@ -33,11 +34,11 @@ gNBs = # downlinkConfigCommon #frequencyInfoDL - # this is 3600 MHz + 84 PRBs@30kHz SCS (same as initial BWP) - absoluteFrequencySSB = 641272; //641032; #641968; 641968=start of ssb at 3600MHz + 82 RBs 641032=center of SSB at center of cell + # this is 3350.04 MHz + 53 PRBs@30kHz SCS (same as initial BWP) + absoluteFrequencySSB = 624608; dl_frequencyBand = 78; - # this is 3600 MHz - dl_absoluteFrequencyPointA = 640000; + # this is 3350.04 MHz + dl_absoluteFrequencyPointA = 623336; #scs-SpecificCarrierList dl_offstToCarrier = 0; # subcarrierSpacing @@ -46,7 +47,7 @@ gNBs = dl_carrierBandwidth = 106; #initialDownlinkBWP #genericParameters - # this is RBstart=84,L=13 (275*(L-1))+RBstart + # this is RBstart=43,L=24 (275*(L-1))+RBstart initialDLBWPlocationAndBandwidth = 6368; # subcarrierSpacing # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 @@ -233,7 +234,7 @@ L1s = ( num_cc = 1; tr_n_preference = "local_mac"; pusch_proc_threads = 8; - prach_dtx_threshold = 100; + prach_dtx_threshold = 120; } ); @@ -250,6 +251,7 @@ RUs = ( eNB_instances = [0]; bf_weights = [0x00007fff, 0x00007fff]; #clock_src = "external"; + sf_extension = 0 sdr_addrs = "mgmt_addr=192.168.18.240,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" } ); @@ -268,12 +270,17 @@ security = { # preferred ciphering algorithms # the first one of the list that an UE supports in chosen # valid values: nea0, nea1, nea2, nea3 - ciphering_algorithms = ( "nea0", "nea2" ); + ciphering_algorithms = ( "nea0" ); # preferred integrity algorithms # the first one of the list that an UE supports in chosen # valid values: nia0, nia1, nia2, nia3 - integrity_algorithms = ( "nia0" ); + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; }; log_config : diff --git a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf new file mode 100644 index 0000000000..c889ba2b89 --- /dev/null +++ b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf @@ -0,0 +1,340 @@ +Active_gNBs = ( "gNB-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_CU_ID = 0xe00; + +# cell_type = "CELL_MACRO_GNB"; + + gNB_name = "gNB-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + + plmn_list = ({ + mcc = 208; + mnc = 97; + mnc_length = 2; + snssaiList = ( + { + sst = 1; + sd = 0x010203; // 0 false, else true + }, + { + sst = 1; + sd = 0x112233; // 0 false, else true + } + ); + }); + + nr_cellid = 12345678L + +# tr_s_preference = "local_mac" + + ////////// Physical parameters: + + ssb_SubcarrierOffset = 0; + pdsch_AntennaPorts = 1; + pusch_AntennaPorts = 2; + ul_prbblacklist = "51,52,53,54" + + pdcch_ConfigSIB1 = ( + { + controlResourceSetZero = 11; + searchSpaceZero = 0; + } + ); + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3301.68 MHz + 22*12*30e-3 MHz = 3309.6 + #absoluteFrequencySSB = 620640; + # this is 3300.60 MHz + 53*12*30e-3 MHz = 3319.68 + absoluteFrequencySSB = 621312; + # this is 3503.28 MHz + 22*12*30e-3 MHz = 3511.2 + #absoluteFrequencySSB = 634080; + # this is 3600.48 MHz + #absoluteFrequencySSB = 640032; + #dl_frequencyBand = 78; + # this is 3301.68 MHz + #dl_absoluteFrequencyPointA = 620112; + # this is 3300.60 MHz + dl_absoluteFrequencyPointA = 620040; + # this is 3502.56 MHz + #dl_absoluteFrequencyPointA = 633552; + # this is 3600.48 MHz + #dl_absoluteFrequencyPointA = 640032; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 106; + #initialDownlinkBWP + #genericParameters + # this is RBstart=0,L=106 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 28875; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 11; + initialDLBWPsearchSpaceZero = 0; + #pdsch-ConfigCommon + #pdschTimeDomainAllocationList (up to 16 entries) + initialDLBWPk0_0 = 0; + #initialULBWPmappingType + #0=typeA,1=typeB + initialDLBWPmappingType_0 = 0; + #this is SS=1,L=13 + initialDLBWPstartSymbolAndLength_0 = 40; + + initialDLBWPk0_1 = 0; + initialDLBWPmappingType_1 = 0; + #this is SS=1,L=5 + initialDLBWPstartSymbolAndLength_1 = 57; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 106; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 28875; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 12; + preambleReceivedTargetPower = -104; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 4; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + + # pusch-ConfigCommon (up to 16 elements) + initialULBWPk2_0 = 6; + initialULBWPmappingType_0 = 1 + # this is SS=2 L=13 + initialULBWPstartSymbolAndLength_0 = 41; + + initialULBWPk2_1 = 6; + initialULBWPmappingType_1 = 1; + # this is SS=0 L=4 + initialULBWPstartSymbolAndLength_1 = 52; + + initialULBWPk2_2 = 7; + initialULBWPmappingType_2 = 1; + # this is SS=10 L=4 + initialULBWPstartSymbolAndLength_2 = 52; + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; +# ssb_PositionsInBurs_BitmapPR +# 1=short, 2=medium, 3=long + ssb_PositionsInBurst_PR = 2; + ssb_PositionsInBurst_Bitmap = 1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = -25; + } + + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + ////////// AMF parameters: + amf_ip_address = ( { ipv4 = "CI_MME_IP_ADDR"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + + GNB_INTERFACE_NAME_FOR_NG_AMF = "em1"; + GNB_IPV4_ADDRESS_FOR_NG_AMF = "CI_GNB_IP_ADDR"; + GNB_INTERFACE_NAME_FOR_NGU = "em1"; + GNB_IPV4_ADDRESS_FOR_NGU = "CI_GNB_IP_ADDR"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + } +); + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; +# pusch_TargetSNRx10 = 200; +# pucch_TargetSNRx10 = 150; + ulsch_max_slots_inactivity=20; + } +); + +L1s = ( + { + num_cc = 1; + tr_n_preference = "local_mac"; + pusch_proc_threads = 2; + prach_dtx_threshold = 120; +# pucch0_dtx_threshold = 150; + } +); + +RUs = ( + { + local_rf = "yes" + nb_tx = 2 + nb_rx = 2 + att_tx = 0 + att_rx = 0; + bands = [78]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 75; + eNB_instances = [0]; + ##beamforming 1x2 matrix: 1 layer x 2 antennas + bf_weights = [0x00007fff, 0x0000]; + ##beamforming 1x4 matrix: 1 layer x 4 antennas + #bf_weights = [0x00007fff, 0x0000,0x0000, 0x0000]; + ## beamforming 2x2 matrix: + # bf_weights = [0x00007fff, 0x00000000, 0x00000000, 0x00007fff]; + ## beamforming 4x4 matrix: + #bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff]; + sf_extension = 0 + sdr_addrs = "mgmt_addr=192.168.18.240,addr=192.168.10.2,second_addr=192.168.20.2,clock_source=internal,time_source=internal" + } +); + +THREAD_STRUCT = ( + { + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_SINGLE_THREAD"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; + } +); + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + f1ap_log_level ="debug"; + f1ap_log_verbosity ="medium"; + }; diff --git a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.usrpn310.conf index db190f177d..a5d35d450e 100644 --- a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.usrpn310.conf @@ -1,4 +1,4 @@ -Active_gNBs = ( "gNB-Eurecom-DU"); +Active_gNBs = ( "gNB-OAI"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; @@ -7,7 +7,7 @@ gNBs = { ////////// Identification parameters: gNB_ID = 0xe00; - gNB_name = "gNB-Eurecom-DU"; + gNB_name = "gNB-OAI"; // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = 1; @@ -35,6 +35,7 @@ gNBs = ssb_SubcarrierOffset = 0; pdsch_AntennaPorts = 1; pusch_AntennaPorts = 1; + ul_prbblacklist = "51,52,53,54" pdcch_ConfigSIB1 = ( { @@ -203,7 +204,7 @@ gNBs = }; - ////////// MME parameters: + ////////// AMF parameters: amf_ip_address = ( { ipv4 = "CI_MME_IP_ADDR"; ipv6 = "192:168:30::17"; active = "yes"; @@ -218,7 +219,7 @@ gNBs = GNB_IPV4_ADDRESS_FOR_NG_AMF = "CI_GNB_IP_ADDR"; GNB_INTERFACE_NAME_FOR_NGU = "eth0"; GNB_IPV4_ADDRESS_FOR_NGU = "CI_GNB_IP_ADDR"; - GNB_PORT_FOR_S1U = 2152; # Spec 2152 + GNB_PORT_FOR_NGU = 2152; # Spec 2152 }; } @@ -229,18 +230,19 @@ MACRLCs = ( num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "local_RRC"; - ulsch_max_slots_inactivity = 100; pusch_TargetSNRx10 = 200; - pucch_TargetSNRx10 = 200; + pucch_TargetSNRx10 = 150; } ); L1s = ( - { - num_cc = 1; - tr_n_preference = "local_mac"; - pusch_proc_threads = 8; - } + { + num_cc = 1; + tr_n_preference = "local_mac"; + pusch_proc_threads = 8; + prach_dtx_threshold = 120; + pucch0_dtx_threshold = 150; + } ); RUs = ( @@ -250,9 +252,9 @@ RUs = ( nb_rx = 1 att_tx = 0 att_rx = 0; - bands = [7]; + bands = [78]; max_pdschReferenceSignalPower = -27; - max_rxgain = 81; + max_rxgain = 75; eNB_instances = [0]; #beamforming 1x4 matrix: bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000]; @@ -279,6 +281,23 @@ rfsimulator : IQfile = "/tmp/rfsimulator.iqs"; }; +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf b/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf index 8d32e8b792..4f0f7c6b2e 100644 --- a/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf +++ b/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf @@ -211,7 +211,6 @@ MACRLCs = ( num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "local_RRC"; - ulsch_max_slots_inactivity = 1; } ); @@ -257,6 +256,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf index df2fd874ca..7bda7f7eb5 100644 --- a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf +++ b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf @@ -262,6 +262,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpn310.conf index b981b27f53..e6bbbf2d41 100644 --- a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpn310.conf @@ -272,6 +272,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/ci-scripts/datalog_rt_stats.yaml b/ci-scripts/datalog_rt_stats.yaml index 548caa0bdd..507ea5d182 100644 --- a/ci-scripts/datalog_rt_stats.yaml +++ b/ci-scripts/datalog_rt_stats.yaml @@ -12,7 +12,8 @@ Ref : feptx_prec : 8.0 feptx_ofdm : 50.0 feptx_total : 75.0 - L1 Tx processing : 300.0 + L1 Tx processing thread 0 : 300.0 + L1 Tx processing thread 1 : 300.0 DLSCH encoding : 230.0 L1 Rx processing : 175.0 PUSCH inner-receiver : 100.0 @@ -24,7 +25,8 @@ Threshold : feptx_prec : 1.25 feptx_ofdm : 1.25 feptx_total : 1.25 - L1 Tx processing : 1.25 + L1 Tx processing thread 0 : 1.25 + L1 Tx processing thread 1 : 1.25 DLSCH encoding : 1.25 L1 Rx processing : 1.25 PUSCH inner-receiver : 1.25 diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py index 1c202438d2..8376e07fd5 100644 --- a/ci-scripts/epc.py +++ b/ci-scripts/epc.py @@ -66,6 +66,7 @@ class EPCManagement(): self.containerPrefix = 'prod' self.mmeConfFile = 'mme.conf' self.yamlPath = '' + self.isMagmaUsed = False #----------------------------------------------------------- @@ -164,7 +165,15 @@ class EPCManagement(): if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE): mySSH = SSH.SSHConnection() mySSH.open(self.IPAddress, self.UserName, self.Password) - mySSH.command('docker inspect --format="MME_IP_ADDR = {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" ' + self.containerPrefix + '-oai-mme', '\$', 5) + self.isMagmaUsed = False + mySSH.command('docker ps -a', '\$', 5) + result = re.search('magma', mySSH.getBefore()) + if result is not None: + self.isMagmaUsed = True + if self.isMagmaUsed: + mySSH.command('docker inspect --format="MME_IP_ADDR = {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" ' + self.containerPrefix + '-magma-mme', '\$', 5) + else: + mySSH.command('docker inspect --format="MME_IP_ADDR = {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" ' + self.containerPrefix + '-oai-mme', '\$', 5) result = re.search('MME_IP_ADDR = (?P[0-9\.]+)', mySSH.getBefore()) if result is not None: self.MmeIPAddress = result.group('mme_ip_addr') @@ -220,7 +229,7 @@ class EPCManagement(): mySSH = SSH.SSHConnection() mySSH.open(self.IPAddress, self.UserName, self.Password) if re.match('ltebox', self.Type, re.IGNORECASE): - logging.debug('Using the sabox simulated HSS') + logging.debug('Using the SABOX simulated HSS') mySSH.command('if [ -d ' + self.SourceCodePath + '/scripts ]; then echo ' + self.Password + ' | sudo -S rm -Rf ' + self.SourceCodePath + '/scripts ; fi', '\$', 5) mySSH.command('mkdir -p ' + self.SourceCodePath + '/scripts', '\$', 5) mySSH.command('cd /opt/hss_sim0609', '\$', 5) @@ -229,6 +238,12 @@ class EPCManagement(): logging.debug('Using the sabox') mySSH.command('cd /opt/ltebox/tools', '\$', 5) mySSH.command('echo ' + self.Password + ' | sudo -S ./start_sabox', '\$', 5) + elif re.match('OAICN5G', self.Type, re.IGNORECASE): + logging.debug('Starting OAI CN5G') + mySSH.command('if [ -d ' + self.SourceCodePath + '/scripts ]; then echo ' + self.Password + ' | sudo -S rm -Rf ' + self.SourceCodePath + '/scripts ; fi', '\$', 5) + mySSH.command('mkdir -p ' + self.SourceCodePath + '/scripts', '\$', 5) + mySSH.command('cd /opt/oai-cn5g-fed/docker-compose', '\$', 5) + mySSH.command('./core-network.sh start nrf spgwu', '\$', 60) else: logging.error('This option should not occur!') mySSH.close() @@ -242,6 +257,16 @@ class EPCManagement(): return if re.match('ltebox', self.Type, re.IGNORECASE): self.MmeIPAddress = self.IPAddress + elif re.match('OAICN5G', self.Type, re.IGNORECASE): + mySSH = SSH.SSHConnection() + mySSH.open(self.IPAddress, self.UserName, self.Password) + response=mySSH.command3('docker container ls -f name=oai-amf', 10) + if len(response)>1: + response=mySSH.command3('docker inspect --format=\'{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}\' oai-amf', 10) + tmp = str(response[0],'utf-8') + self.MmeIPAddress = tmp.rstrip() + logging.debug('AMF IP Address ' + self.MmeIPAddress) + mySSH.close() def CheckHSSProcess(self, status_queue): try: @@ -273,7 +298,15 @@ class EPCManagement(): mySSH = SSH.SSHConnection() mySSH.open(self.IPAddress, self.UserName, self.Password) if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE): - mySSH.command('docker top ' + self.containerPrefix + '-oai-mme', '\$', 5) + self.isMagmaUsed = False + mySSH.command('docker ps -a', '\$', 5) + result = re.search('magma', mySSH.getBefore()) + if result is not None: + self.isMagmaUsed = True + if self.isMagmaUsed: + mySSH.command('docker top ' + self.containerPrefix + '-magma-mme', '\$', 5) + else: + mySSH.command('docker top ' + self.containerPrefix + '-oai-mme', '\$', 5) else: mySSH.command('stdbuf -o0 ps -aux | grep --color=never mme | grep -v grep', '\$', 5) if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE): @@ -433,6 +466,7 @@ class EPCManagement(): mySSH = SSH.SSHConnection() mySSH.open(self.IPAddress, self.UserName, self.Password) if re.match('ltebox', self.Type, re.IGNORECASE): + logging.debug('Terminating SA BOX') mySSH.command('cd /opt/ltebox/tools', '\$', 5) mySSH.command('echo ' + self.Password + ' | sudo -S ./stop_sabox', '\$', 5) time.sleep(1) @@ -440,6 +474,12 @@ class EPCManagement(): mySSH.command('cd scripts', '\$', 5) time.sleep(1) mySSH.command('echo ' + self.Password + ' | sudo -S screen -S simulated_5g_hss -X quit', '\$', 5) + elif re.match('OAICN5G', self.Type, re.IGNORECASE): + self.LogCollectOAICN5G() + logging.debug('Terminating OAI CN5G') + mySSH.command('cd /opt/oai-cn5g-fed/docker-compose', '\$', 5) + mySSH.command('docker-compose down', '\$', 5) + mySSH.command('./core-network.sh stop nrf spgwu', '\$', 60) else: logging.error('This should not happen!') mySSH.close() @@ -466,6 +506,12 @@ class EPCManagement(): HTML.CreateHtmlTabFooter(False) sys.exit('docker-compose not installed on ' + self.IPAddress) + # Checking if it is a MAGMA deployment + self.isMagmaUsed = False + if os.path.isfile('./' + self.yamlPath + '/redis_extern.conf'): + self.isMagmaUsed = True + logging.debug('MAGMA MME is used!') + mySSH.command('if [ -d ' + self.SourceCodePath + '/scripts ]; then echo ' + self.Password + ' | sudo -S rm -Rf ' + self.SourceCodePath + '/scripts ; fi', '\$', 5) mySSH.command('if [ -d ' + self.SourceCodePath + '/logs ]; then echo ' + self.Password + ' | sudo -S rm -Rf ' + self.SourceCodePath + '/logs ; fi', '\$', 5) mySSH.command('mkdir -p ' + self.SourceCodePath + '/scripts ' + self.SourceCodePath + '/logs', '\$', 5) @@ -477,10 +523,15 @@ class EPCManagement(): # - docker-compose config | grep container_name mySSH.command('cd ' + self.SourceCodePath + '/scripts', '\$', 5) mySSH.copyout(self.IPAddress, self.UserName, self.Password, './' + self.yamlPath + '/docker-compose.yml', self.SourceCodePath + '/scripts') + if self.isMagmaUsed: + mySSH.copyout(self.IPAddress, self.UserName, self.Password, './' + self.yamlPath + '/entrypoint.sh', self.SourceCodePath + '/scripts') + mySSH.copyout(self.IPAddress, self.UserName, self.Password, './' + self.yamlPath + '/mme.conf', self.SourceCodePath + '/scripts') + mySSH.copyout(self.IPAddress, self.UserName, self.Password, './' + self.yamlPath + '/mme_fd.sprint.conf', self.SourceCodePath + '/scripts') + mySSH.copyout(self.IPAddress, self.UserName, self.Password, './' + self.yamlPath + '/redis_extern.conf', self.SourceCodePath + '/scripts') + mySSH.command('chmod a+x ' + self.SourceCodePath + '/scripts/entrypoint.sh', '\$', 5) mySSH.command('wget --quiet --tries=3 --retry-connrefused https://raw.githubusercontent.com/OPENAIRINTERFACE/openair-hss/develop/src/hss_rel14/db/oai_db.cql', '\$', 30) mySSH.command('docker-compose down', '\$', 60) mySSH.command('docker-compose up -d db_init', '\$', 60) - # databases take time... time.sleep(10) cnt = 0 @@ -502,8 +553,12 @@ class EPCManagement(): # deploying EPC cNFs mySSH.command('docker-compose up -d oai_spgwu', '\$', 60) - listOfContainers = 'prod-cassandra prod-oai-hss prod-oai-mme prod-oai-spgwc prod-oai-spgwu-tiny' - expectedHealthyContainers = 5 + if self.isMagmaUsed: + listOfContainers = 'prod-cassandra prod-oai-hss prod-magma-mme prod-oai-spgwc prod-oai-spgwu-tiny prod-redis' + expectedHealthyContainers = 6 + else: + listOfContainers = 'prod-cassandra prod-oai-hss prod-oai-mme prod-oai-spgwc prod-oai-spgwu-tiny' + expectedHealthyContainers = 5 # Checking for additional services mySSH.command('docker-compose config', '\$', 5) @@ -534,7 +589,10 @@ class EPCManagement(): logging.debug(' -- ' + str(startingNb) + ' still starting container(s)') if healthyNb == expectedHealthyContainers: mySSH.command('docker exec -d prod-oai-hss /bin/bash -c "nohup tshark -i any -f \'port 9042 or port 3868\' -w /tmp/hss_check_run.pcap 2>&1 > /dev/null"', '\$', 5) - mySSH.command('docker exec -d prod-oai-mme /bin/bash -c "nohup tshark -i any -f \'port 3868 or port 2123 or port 36412\' -w /tmp/mme_check_run.pcap 2>&1 > /dev/null"', '\$', 10) + if self.isMagmaUsed: + mySSH.command('docker exec -d prod-magma-mme /bin/bash -c "nohup tshark -i any -f \'port 3868 or port 2123 or port 36412\' -w /tmp/mme_check_run.pcap 2>&1 > /dev/null"', '\$', 10) + else: + mySSH.command('docker exec -d prod-oai-mme /bin/bash -c "nohup tshark -i any -f \'port 3868 or port 2123 or port 36412\' -w /tmp/mme_check_run.pcap 2>&1 > /dev/null"', '\$', 10) mySSH.command('docker exec -d prod-oai-spgwc /bin/bash -c "nohup tshark -i any -f \'port 2123 or port 8805\' -w /tmp/spgwc_check_run.pcap 2>&1 > /dev/null"', '\$', 10) # on SPGW-U, not capturing on SGI to avoid huge file mySSH.command('docker exec -d prod-oai-spgwu-tiny /bin/bash -c "nohup tshark -i any -f \'port 8805\' -w /tmp/spgwu_check_run.pcap 2>&1 > /dev/null"', '\$', 10) @@ -552,24 +610,45 @@ class EPCManagement(): mySSH = SSH.SSHConnection() mySSH.open(self.IPAddress, self.UserName, self.Password) + # Checking if it is a MAGMA deployment. + mySSH.command('cd ' + self.SourceCodePath + '/scripts', '\$', 5) + mySSH.command('docker-compose ps -a', '\$', 5) + self.isMagmaUsed = False + result = re.search('magma', mySSH.getBefore()) + if result is not None: + self.isMagmaUsed = True + logging.debug('MAGMA MME is used!') # Recovering logs and pcap files mySSH.command('cd ' + self.SourceCodePath + '/logs', '\$', 5) mySSH.command('docker exec -it prod-oai-hss /bin/bash -c "killall --signal SIGINT oai_hss tshark"', '\$', 5) - mySSH.command('docker exec -it prod-oai-mme /bin/bash -c "killall --signal SIGINT tshark"', '\$', 5) + if self.isMagmaUsed: + mySSH.command('docker exec -it prod-magma-mme /bin/bash -c "killall --signal SIGINT tshark"', '\$', 5) + else: + mySSH.command('docker exec -it prod-oai-mme /bin/bash -c "killall --signal SIGINT tshark"', '\$', 5) mySSH.command('docker exec -it prod-oai-spgwc /bin/bash -c "killall --signal SIGINT oai_spgwc tshark"', '\$', 5) mySSH.command('docker exec -it prod-oai-spgwu-tiny /bin/bash -c "killall --signal SIGINT tshark"', '\$', 5) mySSH.command('docker logs prod-oai-hss > hss_' + self.testCase_id + '.log', '\$', 5) - mySSH.command('docker logs prod-oai-mme > mme_' + self.testCase_id + '.log', '\$', 5) + if self.isMagmaUsed: + mySSH.command('docker cp --follow-link prod-magma-mme:/var/log/mme.log mme_' + self.testCase_id + '.log', '\$', 15) + else: + mySSH.command('docker logs prod-oai-mme > mme_' + self.testCase_id + '.log', '\$', 5) mySSH.command('docker logs prod-oai-spgwc > spgwc_' + self.testCase_id + '.log', '\$', 5) mySSH.command('docker logs prod-oai-spgwu-tiny > spgwu_' + self.testCase_id + '.log', '\$', 5) mySSH.command('docker cp prod-oai-hss:/tmp/hss_check_run.pcap hss_' + self.testCase_id + '.pcap', '\$', 60) - mySSH.command('docker cp prod-oai-mme:/tmp/mme_check_run.pcap mme_' + self.testCase_id + '.pcap', '\$', 60) + if self.isMagmaUsed: + mySSH.command('docker cp prod-magma-mme:/tmp/mme_check_run.pcap mme_' + self.testCase_id + '.pcap', '\$', 60) + else: + mySSH.command('docker cp prod-oai-mme:/tmp/mme_check_run.pcap mme_' + self.testCase_id + '.pcap', '\$', 60) mySSH.command('docker cp prod-oai-spgwc:/tmp/spgwc_check_run.pcap spgwc_' + self.testCase_id + '.pcap', '\$', 60) mySSH.command('docker cp prod-oai-spgwu-tiny:/tmp/spgwu_check_run.pcap spgwu_' + self.testCase_id + '.pcap', '\$', 60) # Remove all mySSH.command('cd ' + self.SourceCodePath + '/scripts', '\$', 5) - listOfContainers = 'prod-cassandra prod-oai-hss prod-oai-mme prod-oai-spgwc prod-oai-spgwu-tiny' - nbContainers = 5 + if self.isMagmaUsed: + listOfContainers = 'prod-cassandra prod-oai-hss prod-magma-mme prod-oai-spgwc prod-oai-spgwu-tiny prod-redis' + nbContainers = 6 + else: + listOfContainers = 'prod-cassandra prod-oai-hss prod-oai-mme prod-oai-spgwc prod-oai-spgwu-tiny' + nbContainers = 5 # Checking for additional services mySSH.command('docker-compose config', '\$', 5) configResponse = mySSH.getBefore() @@ -679,3 +758,16 @@ class EPCManagement(): logging.error('This option should not occur!') mySSH.close() + def LogCollectOAICN5G(self): + mySSH = SSH.SSHConnection() + mySSH.open(self.IPAddress, self.UserName, self.Password) + logging.debug('OAI CN5G Collecting Log files to workspace') + mySSH.command('echo ' + self.Password + ' | sudo rm -rf ' + self.SourceCodePath + '/logs', '\$', 5) + mySSH.command('mkdir ' + self.SourceCodePath + '/logs','\$', 5) + containers_list=['oai-smf','oai-spgwu','oai-amf','oai-nrf'] + for c in containers_list: + mySSH.command('docker logs ' + c + ' > ' + self.SourceCodePath + '/logs/' + c + '.log', '\$', 5) + mySSH.command('cd ' + self.SourceCodePath + '/logs', '\$', 5) + mySSH.command('zip oai-cn5g.log.zip *.log', '\$', 60) + mySSH.close() + diff --git a/ci-scripts/main.py b/ci-scripts/main.py index d66c0c6305..9923d515a4 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -154,6 +154,7 @@ def GetParametersFromXML(action): elif action == 'Initialize_eNB': RAN.eNB_Trace=test.findtext('eNB_Trace') + RAN.eNB_Stats=test.findtext('eNB_Stats') RAN.Initialize_eNB_args=test.findtext('Initialize_eNB_args') eNB_instance=test.findtext('eNB_instance') USRPIPAddress=test.findtext('USRP_IPAddress') diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index 5e3d8e388f..9acb1de34e 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -39,7 +39,6 @@ import time from multiprocessing import Process, Lock, SimpleQueue import yaml - #----------------------------------------------------------- # OAI Testing modules #----------------------------------------------------------- @@ -94,6 +93,7 @@ class RANManagement(): self.runtime_stats= '' self.datalog_rt_stats={} self.eNB_Trace = '' #if 'yes', Tshark will be launched at initialization + self.eNB_Stats = '' #if 'yes', Statistics Monitor will be launched at initialization self.USRPIPAddress = '' @@ -341,6 +341,8 @@ class RANManagement(): self.testCase_id = HTML.testCase_id mySSH = SSH.SSHConnection() + cwd = os.getcwd() + mySSH.copyout(lIpAddr,lUserName,lPassWord, cwd + "/active_net_interfaces.awk", "/tmp") #reboot USRP if requested in xml if self.USRPIPAddress!='': @@ -461,10 +463,36 @@ class RANManagement(): mySSH.command('if [ -e rbconfig.raw ]; then echo ' + lPassWord + ' | sudo -S rm rbconfig.raw; fi', '\$', 5) mySSH.command('if [ -e reconfig.raw ]; then echo ' + lPassWord + ' | sudo -S rm reconfig.raw; fi', '\$', 5) # NOTE: WE SHALL do a check if the executable is present (in case build went wrong) - mySSH.command('echo "ulimit -c unlimited && ./ran_build/build/' + self.air_interface[self.eNB_instance] + ' -O ' + lSourcePath + '/' + ci_full_config_file + extra_options + '" > ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + + #hack UHD_RFNOC_DIR variable for gNB / N310 on RHEL8 server: + #if the USRP address is in the xml then we are using an eth USRP (N3xx) + if (self.air_interface[self.eNB_instance] == 'lte-softmodem') or (self.air_interface[self.eNB_instance] == 'ocp-enb'): + gNB = False + else: + gNB = True + if ((self.USRPIPAddress!='') and (gNB==True)): + mySSH.command('echo ' + lPassWord + ' | echo "ulimit -c unlimited && sudo UHD_RFNOC_DIR=/usr/local/share/uhd/rfnoc ./ran_build/build/' + self.air_interface[self.eNB_instance] + ' -O ' + lSourcePath + '/' + ci_full_config_file + extra_options + '" > ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + #otherwise the regular command is ok + else: + mySSH.command('echo "ulimit -c unlimited && ./ran_build/build/' + self.air_interface[self.eNB_instance] + ' -O ' + lSourcePath + '/' + ci_full_config_file + extra_options + '" > ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + mySSH.command('chmod 775 ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) mySSH.command('echo ' + lPassWord + ' | sudo -S rm -Rf enb_' + self.testCase_id + '.log', '\$', 5) mySSH.command('echo $USER; nohup sudo -E ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh > ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '.log 2>&1 &', lUserName, 10) + + + #stats monitoring during runtime + time.sleep(20) + monitor_file='../ci-scripts/stats_monitor.py' + conf_file='../ci-scripts/stats_monitor_conf.yaml' + if self.eNB_Stats=='yes': + if (self.air_interface[self.eNB_instance] == 'lte-softmodem') or (self.air_interface[self.eNB_instance] == 'ocp-enb'): + mySSH.command('echo $USER; nohup python3 ' + monitor_file + ' ' + conf_file + ' enb 2>&1 > enb_stats_monitor_execution.log &', '\$', 5) + else: + mySSH.command('echo $USER; nohup python3 ' + monitor_file + ' ' + conf_file + ' gnb 2>&1 > gnb_stats_monitor_execution.log &', '\$', 5) + + + self.eNBLogFiles[int(self.eNB_instance)] = 'enb_' + self.testCase_id + '.log' if extra_options != '': self.eNBOptions[int(self.eNB_instance)] = extra_options @@ -539,6 +567,8 @@ class RANManagement(): self.eNBstatuses[int(self.eNB_instance)] = int(self.eNB_serverId[self.eNB_instance]) mySSH.close() + + HTML.CreateHtmlTestRow(self.air_interface[self.eNB_instance] + ' -O ' + config_file + extra_options, 'OK', CONST.ALL_PROCESSES_OK) logging.debug('\u001B[1m Initialize eNB/gNB/ocp-eNB Completed\u001B[0m') @@ -657,6 +687,11 @@ class RANManagement(): fileToAnalyze = self.eNBLogFiles[int(self.eNB_instance)] self.eNBLogFiles[int(self.eNB_instance)] = '' if analyzeFile: + #*stats.log files + pickle + png + mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/*stats.log', '.') + mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/*.pickle', '.') + mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/*.png', '.') + # copyin_res = mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + fileToAnalyze, '.') if (copyin_res == -1): logging.debug('\u001B[1;37;41m Could not copy ' + nodeB_prefix + 'NB logfile to analyze it! \u001B[0m') @@ -665,12 +700,20 @@ class RANManagement(): self.eNBmbmsEnables[int(self.eNB_instance)] = False return if self.eNB_serverId[self.eNB_instance] != '0': + #*stats.log files + pickle + png + + #debug / tentative + mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './nrL1_stats.log', self.eNBSourceCodePath + '/cmake_targets/') + mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './nrMAC_stats.log', self.eNBSourceCodePath + '/cmake_targets/') + mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './gnb_stats_monitor.pickle', self.eNBSourceCodePath + '/cmake_targets/') + mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './gnb_stats_monitor.png', self.eNBSourceCodePath + '/cmake_targets/') + # mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './' + fileToAnalyze, self.eNBSourceCodePath + '/cmake_targets/') logging.debug('\u001B[1m Analyzing ' + nodeB_prefix + 'NB logfile \u001B[0m ' + fileToAnalyze) logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze, HTML) if (logStatus < 0): HTML.CreateHtmlTestRow('N/A', 'KO', logStatus) - self.preamtureExit = True + self.prematureExit = True self.eNBmbmsEnables[int(self.eNB_instance)] = False return else: @@ -691,8 +734,8 @@ class RANManagement(): mySSH.command('echo ' + self.eNBPassword + ' | sudo -S mv /tmp/enb_*.pcap .','\$',20) mySSH.command('echo ' + self.eNBPassword + ' | sudo -S mv /tmp/gnb_*.pcap .','\$',20) mySSH.command('echo ' + self.eNBPassword + ' | sudo -S rm -f enb.log.zip', '\$', 5) - mySSH.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip enb*.log core* enb_*record.raw enb_*.pcap gnb_*.pcap enb_*txt physim_*.log *stats.log', '\$', 60) - mySSH.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap gnb_*.pcap enb_*txt physim_*.log *stats.log', '\$', 5) + mySSH.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip enb*.log core* enb_*record.raw enb_*.pcap gnb_*.pcap enb_*txt physim_*.log *stats.log *monitor.pickle *monitor.png', '\$', 60) + mySSH.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap gnb_*.pcap enb_*txt physim_*.log *stats.log *.pickle *.png', '\$', 5) mySSH.close() def AnalyzeLogFile_eNB(self, eNBlogFile, HTML): @@ -1032,7 +1075,7 @@ class RANManagement(): for k in datalog_rt_stats['Data']: if float(datalog_rt_stats['Data'][k][2])> datalog_rt_stats['Threshold'][k]: #condition for fail : avg/ref is greater than the fixed threshold #setting prematureExit is ok although not the best option - self.prematureExit=True + self.prematureExit=False #temp for debug : do not stop the test if RT stats are excedeed else: statMsg = 'No real time stats found in the log file\n' logging.debug('No real time stats found in the log file') diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py index b4087c9695..b85c40a0be 100644 --- a/ci-scripts/sshconnection.py +++ b/ci-scripts/sshconnection.py @@ -163,6 +163,18 @@ class SSHConnection(): lSsh = subprocess.Popen(["ssh", "%s" % myHost, commandline],shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE) self.cmd2Results = str(lSsh.stdout.readlines()) + def command3(self, commandline, timeout, silent=False): + if not silent: + logging.debug(commandline) + self.cmd2Results = '' + myHost = self.username + '@' + self.ipaddress + # CAUTION: THIS METHOD IMPLIES THAT THERE ARE VALID SSH KEYS + # BETWEEN THE PYTHON EXECUTOR NODE AND THE REMOTE HOST + # OTHERWISE IT WON'T WORK + lSsh = subprocess.Popen(["ssh", "%s" % myHost, commandline],shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE) + return lSsh.stdout.readlines() + + def close(self): self.ssh.timeout = 5 self.ssh.sendline('exit') diff --git a/ci-scripts/stats_monitor.py b/ci-scripts/stats_monitor.py new file mode 100755 index 0000000000..877194de59 --- /dev/null +++ b/ci-scripts/stats_monitor.py @@ -0,0 +1,102 @@ +""" +To create graphs and pickle from runtime statistics in L1,MAC,RRC,PDCP files +""" + +import subprocess +import time +import shlex +import re +import sys +import pickle +import matplotlib.pyplot as plt +import numpy as np +import yaml + + +class StatMonitor(): + def __init__(self,cfg_file): + with open(cfg_file,'r') as file: + self.d = yaml.load(file) + for node in self.d: + for metric in self.d[node]: + self.d[node][metric]=[] + + + def process_gnb (self,node_type,output): + for line in output: + tmp=line.decode("utf-8") + result=re.match(r'^.*\bdlsch_rounds\b ([0-9]+)\/([0-9]+).*\bdlsch_errors\b ([0-9]+)',tmp) + if result is not None: + self.d[node_type]['dlsch_err'].append(int(result.group(3))) + percentage=float(result.group(2))/float(result.group(1)) + self.d[node_type]['dlsch_err_perc_round_1'].append(percentage) + result=re.match(r'^.*\bulsch_rounds\b ([0-9]+)\/([0-9]+).*\bulsch_errors\b ([0-9]+)',tmp) + if result is not None: + self.d[node_type]['ulsch_err'].append(int(result.group(3))) + percentage=float(result.group(2))/float(result.group(1)) + self.d[node_type]['ulsch_err_perc_round_1'].append(percentage) + + + def process_enb (self,node_type,output): + for line in output: + tmp=line.decode("utf-8") + result=re.match(r'^.*\bPHR\b ([0-9]+).+\bbler\b ([0-9]+\.[0-9]+).+\bmcsoff\b ([0-9]+).+\bmcs\b ([0-9]+)',tmp) + if result is not None: + self.d[node_type]['PHR'].append(int(result.group(1))) + self.d[node_type]['bler'].append(float(result.group(2))) + self.d[node_type]['mcsoff'].append(int(result.group(3))) + self.d[node_type]['mcs'].append(int(result.group(4))) + + + def collect(self,node_type): + if node_type=='enb': + cmd='cat L1_stats.log MAC_stats.log PDCP_stats.log RRC_stats.log' + else: #'gnb' + cmd='cat nrL1_stats.log nrMAC_stats.log nrPDCP_stats.log nrRRC_stats.log' + process=subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE) + output = process.stdout.readlines() + if node_type=='enb': + self.process_enb(node_type,output) + else: #'gnb' + self.process_gnb(node_type,output) + + + def graph(self,node_type): + col = 1 + figure, axis = plt.subplots(len(self.d[node_type]), col ,figsize=(10, 10)) + i=0 + for metric in self.d[node_type]: + major_ticks = np.arange(0, len(self.d[node_type][metric])+1, 1) + axis[i].set_xticks(major_ticks) + axis[i].set_xticklabels([]) + axis[i].plot(self.d[node_type][metric],marker='o') + axis[i].set_xlabel('time') + axis[i].set_ylabel(metric) + axis[i].set_title(metric) + i+=1 + + plt.tight_layout() + # Combine all the operations and display + plt.savefig(node_type+'_stats_monitor.png') + plt.show() + + +if __name__ == "__main__": + + cfg_filename = sys.argv[1] #yaml file as metrics config + node = sys.argv[2]#enb or gnb + mon=StatMonitor(cfg_filename) + + #collecting stats when modem process is stopped + CMD='ps aux | grep mode | grep -v grep' + process=subprocess.Popen(CMD, shell=True, stdout=subprocess.PIPE) + output = process.stdout.readlines() + while len(output)!=0 : + mon.collect(node) + process=subprocess.Popen(CMD, shell=True, stdout=subprocess.PIPE) + output = process.stdout.readlines() + time.sleep(1) + print('Process stopped') + with open(node+'_stats_monitor.pickle', 'wb') as handle: + pickle.dump(mon.d, handle, protocol=pickle.HIGHEST_PROTOCOL) + mon.graph(node) diff --git a/ci-scripts/stats_monitor.py.old b/ci-scripts/stats_monitor.py.old new file mode 100755 index 0000000000..ae9b39bfa6 --- /dev/null +++ b/ci-scripts/stats_monitor.py.old @@ -0,0 +1,94 @@ +import subprocess +import time +import shlex +import re +import sys +import matplotlib.pyplot as plt +import pickle +import numpy as np +import os + +def collect(d, node_type): + if node_type=='enb': + cmd='cat L1_stats.log MAC_stats.log PDCP_stats.log RRC_stats.log' + else: #'gnb' + cmd='cat nrL1_stats.log nrMAC_stats.log nrPDCP_stats.log nrRRC_stats.log' + process=subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE) + output = process.stdout.readlines() + for l in output: + tmp=l.decode("utf-8") + result=re.match(rf'^.*\bPHR\b ([0-9]+).+\bbler\b ([0-9]+\.[0-9]+).+\bmcsoff\b ([0-9]+).+\bmcs\b ([0-9]+)',tmp) + if result is not None: + d['PHR'].append(int(result.group(1))) + d['bler'].append(float(result.group(2))) + d['mcsoff'].append(int(result.group(3))) + d['mcs'].append(int(result.group(4))) + + +def graph(d, node_type): + + + figure, axis = plt.subplots(4, 1,figsize=(10, 10)) + + major_ticks = np.arange(0, len(d['PHR'])+1, 1) + axis[0].set_xticks(major_ticks) + axis[0].set_xticklabels([]) + axis[0].plot(d['PHR'],marker='o') + axis[0].set_xlabel('time') + axis[0].set_ylabel('PHR') + axis[0].set_title("PHR") + + major_ticks = np.arange(0, len(d['bler'])+1, 1) + axis[1].set_xticks(major_ticks) + axis[1].set_xticklabels([]) + axis[1].plot(d['bler'],marker='o') + axis[1].set_xlabel('time') + axis[1].set_ylabel('bler') + axis[1].set_title("bler") + + major_ticks = np.arange(0, len(d['mcsoff'])+1, 1) + axis[2].set_xticks(major_ticks) + axis[2].set_xticklabels([]) + axis[2].plot(d['mcsoff'],marker='o') + axis[2].set_xlabel('time') + axis[2].set_ylabel('mcsoff') + axis[2].set_title("mcsoff") + + major_ticks = np.arange(0, len(d['mcs'])+1, 1) + axis[3].set_xticks(major_ticks) + axis[3].set_xticklabels([]) + axis[3].plot(d['mcs'],marker='o') + axis[3].set_xlabel('time') + axis[3].set_ylabel('mcs') + axis[3].set_title("mcs") + + plt.tight_layout() + # Combine all the operations and display + plt.savefig(node_type+'_stats_monitor.png') + plt.show() + +if __name__ == "__main__": + + node_type = sys.argv[1]#enb or gnb + + d={} + d['PHR']=[] + d['bler']=[] + d['mcsoff']=[] + d['mcs']=[] + + + cmd='ps aux | grep modem | grep -v grep' + process=subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) + output = process.stdout.readlines() + while len(output)!=0 : + collect(d, node_type) + process=subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) + output = process.stdout.readlines() + time.sleep(1) + print('process stopped') + with open(node_type+'_stats_monitor.pickle', 'wb') as handle: + pickle.dump(d, handle, protocol=pickle.HIGHEST_PROTOCOL) + graph(d, node_type) + + diff --git a/ci-scripts/stats_monitor_conf.yaml b/ci-scripts/stats_monitor_conf.yaml new file mode 100644 index 0000000000..6c0a2b0225 --- /dev/null +++ b/ci-scripts/stats_monitor_conf.yaml @@ -0,0 +1,11 @@ +enb : + PHR: + bler: + mcsoff: + mcs: + +gnb : + dlsch_err: + dlsch_err_perc_round_1: + ulsch_err: + ulsch_err_perc_round_1: \ No newline at end of file diff --git a/ci-scripts/stats_monitor_dev.py b/ci-scripts/stats_monitor_dev.py new file mode 100755 index 0000000000..83de20f5d2 --- /dev/null +++ b/ci-scripts/stats_monitor_dev.py @@ -0,0 +1,101 @@ +""" +To create graphs and pickle from runtime statistics in L1,MAC,RRC,PDCP files +""" + +import subprocess +import time +import shlex +import re +import sys +import pickle +import matplotlib.pyplot as plt +import numpy as np +import yaml + + +class StatMonitor(): + def __init__(self,): + with open('stats_monitor_conf.yaml','r') as file: + self.d = yaml.load(file) + for node in self.d: + for metric in self.d[node]: + self.d[node][metric]=[] + + + def process_gnb (self,node_type,output): + for line in output: + tmp=line.decode("utf-8") + result=re.match(r'^.*\bdlsch_rounds\b ([0-9]+)\/([0-9]+).*\bdlsch_errors\b ([0-9]+)',tmp) + if result is not None: + self.d[node_type]['dlsch_err'].append(int(result.group(3))) + percentage=float(result.group(2))/float(result.group(1)) + self.d[node_type]['dlsch_err_perc_round_1'].append(percentage) + result=re.match(r'^.*\bulsch_rounds\b ([0-9]+)\/([0-9]+).*\bulsch_errors\b ([0-9]+)',tmp) + if result is not None: + self.d[node_type]['ulsch_err'].append(int(result.group(3))) + percentage=float(result.group(2))/float(result.group(1)) + self.d[node_type]['ulsch_err_perc_round_1'].append(percentage) + + + def process_enb (self,node_type,output): + for line in output: + tmp=line.decode("utf-8") + result=re.match(r'^.*\bPHR\b ([0-9]+).+\bbler\b ([0-9]+\.[0-9]+).+\bmcsoff\b ([0-9]+).+\bmcs\b ([0-9]+)',tmp) + if result is not None: + self.d[node_type]['PHR'].append(int(result.group(1))) + self.d[node_type]['bler'].append(float(result.group(2))) + self.d[node_type]['mcsoff'].append(int(result.group(3))) + self.d[node_type]['mcs'].append(int(result.group(4))) + + + def collect(self,node_type): + if node_type=='enb': + cmd='cat L1_stats.log MAC_stats.log PDCP_stats.log RRC_stats.log' + else: #'gnb' + cmd='cat nrL1_stats.log nrMAC_stats.log nrPDCP_stats.log nrRRC_stats.log' + process=subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE) + output = process.stdout.readlines() + if node_type=='enb': + self.process_enb(node_type,output) + else: #'gnb' + self.process_gnb(node_type,output) + + + def graph(self,node_type): + col = 1 + figure, axis = plt.subplots(len(self.d[node_type]), col ,figsize=(10, 10)) + i=0 + for metric in self.d[node_type]: + major_ticks = np.arange(0, len(self.d[node_type][metric])+1, 1) + axis[i].set_xticks(major_ticks) + axis[i].set_xticklabels([]) + axis[i].plot(self.d[node_type][metric],marker='o') + axis[i].set_xlabel('time') + axis[i].set_ylabel(metric) + axis[i].set_title(metric) + i+=1 + + plt.tight_layout() + # Combine all the operations and display + plt.savefig(node_type+'_stats_monitor.png') + plt.show() + + +if __name__ == "__main__": + + node = sys.argv[1]#enb or gnb + mon=StatMonitor() + + #collecting stats when modem process is stopped + CMD='ps aux | grep mode | grep -v grep' + process=subprocess.Popen(CMD, shell=True, stdout=subprocess.PIPE) + output = process.stdout.readlines() + while len(output)!=0 : + mon.collect(node) + process=subprocess.Popen(CMD, shell=True, stdout=subprocess.PIPE) + output = process.stdout.readlines() + time.sleep(1) + print('Process stopped') + with open(node+'_stats_monitor.pickle', 'wb') as handle: + pickle.dump(mon.d, handle, protocol=pickle.HIGHEST_PROTOCOL) + mon.graph(node) diff --git a/ci-scripts/xml_files/fr1_enb_build.xml b/ci-scripts/xml_files/fr1_enb_build.xml new file mode 100644 index 0000000000..084f58a591 --- /dev/null +++ b/ci-scripts/xml_files/fr1_enb_build.xml @@ -0,0 +1,50 @@ + + + build-tab + Build + wrench + + 000001 + 000002 + + + + + Build_eNB + Build eNB + -w USRP -c --eNB --ninja + 0 + 0 + True + True + + + + WaitEndBuild_eNB + Wait for end of Build eNB + 0 + 0 + + + diff --git a/ci-scripts/xml_files/fr1_gnb_build.xml b/ci-scripts/xml_files/fr1_gnb_build.xml index d0c91f407d..43cff75620 100644 --- a/ci-scripts/xml_files/fr1_gnb_build.xml +++ b/ci-scripts/xml_files/fr1_gnb_build.xml @@ -26,7 +26,6 @@ wrench 000001 - 000002 @@ -36,7 +35,6 @@ -w USRP -c --gNB --ninja 0 0 - True True diff --git a/ci-scripts/xml_files/fr1_lte_2x2_quectel.xml b/ci-scripts/xml_files/fr1_lte_2x2_quectel.xml new file mode 100644 index 0000000000..03d474aef0 --- /dev/null +++ b/ci-scripts/xml_files/fr1_lte_2x2_quectel.xml @@ -0,0 +1,141 @@ + + + TEST-LTE-TM2 + LTE 2x2 Ping DL UL with QUECTEL + tasks + 1 + + 030000 + 000002 + 010000 + 000001 + 050000 + 050001 + 000002 + 070000 + 070001 + 000001 + 010002 + 080000 + + + + + Initialize_UE + Initialize Quectel + nrmodule2_quectel + yes + + + + + Terminate_UE + Terminate Quectel + nrmodule2_quectel + + + + + Initialize_eNB + Initialize eNB + -O ci-scripts/conf_files/enb.band38.lte_2x2.100PRB.usrpn310.conf --usrp-tx-thread-config 1 --thread-pool 0,2,4,6 + 0 + 0 + lte + yes + yes + 192.168.18.241 + + + + + IdleSleep + Sleep + 5 + + + + IdleSleep + Sleep + 20 + + + + + Ping + Ping: 20 pings + nrmodule2_quectel + -c 20 + 5 + + + Ping + Ping: 100 pings, size 1024 + nrmodule2_quectel + -c 100 -s 1024 -i 0,2 + 5 + + + + + Iperf + iperf (DL/26Mbps/UDP)(60 sec)(single-ue profile) + -u -b 26M -t 60 + DL + nrmodule2_quectel + 5 + single-ue + + + + Iperf + iperf (UL/7Mbps/UDP)(60 sec)(single-ue profile) + -u -b 7M -t 60 + UL + nrmodule2_quectel + 5 + single-ue + + + + + + + Terminate_eNB + Terminate eNB + 0 + 0 + lte + + + + Terminate_eNB + Terminate gNB + 1 + 1 + nr + + + + diff --git a/ci-scripts/xml_files/fr1_multi_node_build.xml b/ci-scripts/xml_files/fr1_multi_node_build.xml index 57c4685341..60bc734e65 100644 --- a/ci-scripts/xml_files/fr1_multi_node_build.xml +++ b/ci-scripts/xml_files/fr1_multi_node_build.xml @@ -26,7 +26,7 @@ wrench 000001 000002 - 000003 000004 + 000004 000005 000003 @@ -64,5 +64,10 @@ 1 + + IdleSleep + Sleep + 120 + diff --git a/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml b/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml index a8e385b854..16dfd1e377 100644 --- a/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml +++ b/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml @@ -21,10 +21,10 @@ --> - TEST-NSA-FR1-TM1 - NSA Ping DL UL with QUECTEL + TEST-NSA-FR1-TM2-Tab1 + NSA 2x2 Ping DL UL with QUECTEL tasks - 1 + 5 030000 040000 @@ -32,6 +32,10 @@ 010000 000001 050000 + 050001 + 000002 + 070000 + 070001 000001 010002 080001 @@ -57,11 +61,12 @@ Initialize_eNB Initialize eNB - -O ci-scripts/conf_files/enb.band38.nsa_2x2.100PRB.usrpn310.conf + -O ci-scripts/conf_files/enb.band38.nsa_2x2.100PRB.usrpn310.conf --usrp-tx-thread-config 1 --thread-pool 0,2,4,6 0 0 lte yes + yes 192.168.18.241 @@ -69,17 +74,18 @@ Initialize_eNB Initialize gNB - -O ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf -q + -O ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf -q --usrp-tx-thread-config 1 --thread-pool 0,2,4,6 1 1 nr + yes 192.168.18.240 IdleSleep Sleep - 5 + 60 @@ -94,15 +100,15 @@ Ping: 20pings in 20sec nrmodule2_quectel -c 20 - 50 + 5 Ping Ping: 100pings in 20sec nrmodule2_quectel - -c 100 -i 0.2 - 50 + -c 100 -i 0,2 + 5 @@ -111,17 +117,17 @@ -u -b 20M -t 60 DL nrmodule2_quectel - 50 + 5 single-ue Iperf - iperf (UL/3Mbps/UDP)(60 sec)(single-ue profile) + iperf (UL/1Mbps/UDP)(20 sec)(single-ue profile) -u -b 3M -t 60 UL nrmodule2_quectel - 50 + 5 single-ue diff --git a/ci-scripts/xml_files/fr1_nsa_2x2_quectel_attach_detach.xml b/ci-scripts/xml_files/fr1_nsa_2x2_quectel_attach_detach.xml new file mode 100644 index 0000000000..ebb5c880d5 --- /dev/null +++ b/ci-scripts/xml_files/fr1_nsa_2x2_quectel_attach_detach.xml @@ -0,0 +1,145 @@ + + + TEST-NSA-FR1-TM2-Tab2 + NSA 2x2 Attach-Detach with QUECTEL + tasks + 5 + + 031000 + 041000 + 000002 + 010000 + 000001 + 050000 + 000002 + 010004 + 000002 + 010003 + 000001 + 050000 + 000002 + 010004 + 000002 + 010003 + 000001 + 050000 + 000002 + 010002 + 080001 + 080000 + + + + + Initialize_UE + Initialize Quectel + nrmodule2_quectel + yes + + + + + Terminate_UE + Terminate Quectel + nrmodule2_quectel + + + + Attach_UE + Attach Quectel + nrmodule2_quectel + + + + Detach_UE + Detach Quectel + nrmodule2_quectel + + + + + Initialize_eNB + Initialize eNB + -O ci-scripts/conf_files/enb.band38.nsa_2x2.100PRB.usrpn310.conf --usrp-tx-thread-config 1 --thread-pool 0,2,4,6 + 0 + 0 + lte + yes + yes + 192.168.18.241 + + + + + Initialize_eNB + Initialize gNB + -O ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf -q --usrp-tx-thread-config 1 --thread-pool 0,2,4,6 + 1 + 1 + nr + yes + 192.168.18.240 + + + + IdleSleep + Sleep + 60 + + + + IdleSleep + Sleep + 20 + + + + + Ping + Ping: 20pings in 20sec + nrmodule2_quectel + -c 20 + 5 + + + + + + Terminate_eNB + Terminate eNB + 0 + 0 + lte + + + + Terminate_eNB + Terminate gNB + 1 + 1 + nr + + + + diff --git a/ci-scripts/xml_files/fr1_oai_cn_deploy.xml b/ci-scripts/xml_files/fr1_oai_cn_deploy.xml index 919def7aa3..26dbebc329 100644 --- a/ci-scripts/xml_files/fr1_oai_cn_deploy.xml +++ b/ci-scripts/xml_files/fr1_oai_cn_deploy.xml @@ -33,7 +33,7 @@ Deploy_EPC Deploy all EPC containers - yaml_files/fr1_epc_tim + yaml_files/magma_nsa_20897 diff --git a/ci-scripts/xml_files/fr1_sa_quectel.xml b/ci-scripts/xml_files/fr1_sa_quectel.xml index 4c8fba0611..b401465f80 100644 --- a/ci-scripts/xml_files/fr1_sa_quectel.xml +++ b/ci-scripts/xml_files/fr1_sa_quectel.xml @@ -31,6 +31,9 @@ 010000 000001 050000 + 050001 + 070000 + 070001 000001 010002 080000 @@ -55,11 +58,12 @@ Initialize_eNB Initialize gNB - -O ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.usrpn310.conf --sa -q + -O ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf --sa -q --usrp-tx-thread-config 1 --thread-pool 0,2,4,6 0 0 nr yes + yes 192.168.18.240 @@ -81,15 +85,15 @@ Ping: 20pings in 20sec nrmodule2_quectel -c 20 - 50 + 5 Ping Ping: 100pings in 20sec nrmodule2_quectel - -c 100 -i 0.2 - 50 + -c 100 -i 0,2 + 5 @@ -98,7 +102,7 @@ -u -b 20M -t 60 DL nrmodule2_quectel - 50 + 5 single-ue @@ -108,7 +112,7 @@ -u -b 3M -t 60 UL nrmodule2_quectel - 50 + 5 single-ue diff --git a/ci-scripts/yaml_files/fr1_epc_tim/docker-compose.yml b/ci-scripts/yaml_files/fr1_epc_20897/docker-compose.yml similarity index 95% rename from ci-scripts/yaml_files/fr1_epc_tim/docker-compose.yml rename to ci-scripts/yaml_files/fr1_epc_20897/docker-compose.yml index 73a6b3a1ff..0005ce8844 100644 --- a/ci-scripts/yaml_files/fr1_epc_tim/docker-compose.yml +++ b/ci-scripts/yaml_files/fr1_epc_20897/docker-compose.yml @@ -51,7 +51,7 @@ services: LTE_K: FEC86BA6EB707ED08905757B1BB44B8F APN1: oai.ipv4 APN2: oai2.ipv4 - FIRST_IMSI: 208990100001127 + FIRST_IMSI: 208970100001127 NB_USERS: 5 healthcheck: test: /bin/bash -c "pgrep oai_hss" @@ -78,7 +78,7 @@ services: HSS_FQDN: hss.openairinterface.org HSS_REALM: openairinterface.org MCC: '208' - MNC: '99' + MNC: '97' MME_GID: 32768 MME_CODE: 3 TAC_0: 1 @@ -97,15 +97,15 @@ services: PEER_MME_IPV4_ADDRESS_FOR_S10_0: 0.0.0.0 PEER_MME_IPV4_ADDRESS_FOR_S10_1: 0.0.0.0 MCC_SGW_0: '208' - MNC3_SGW_0: '099' + MNC3_SGW_0: '097' TAC_LB_SGW_0: '01' TAC_HB_SGW_0: '00' MCC_MME_0: '208' - MNC3_MME_0: '099' + MNC3_MME_0: '097' TAC_LB_MME_0: '02' TAC_HB_MME_0: '00' MCC_MME_1: '208' - MNC3_MME_1: '099' + MNC3_MME_1: '097' TAC_LB_MME_1: '03' TAC_HB_MME_1: '00' TAC_LB_SGW_TEST_0: '03' @@ -138,11 +138,12 @@ services: UE_IP_ADDRESS_POOL_1: '12.1.1.2 - 12.1.1.254' UE_IP_ADDRESS_POOL_2: '12.0.0.2 - 12.0.0.254' MCC: '208' - MNC: '99' - MNC03: '099' + MNC: '97' + MNC03: '097' TAC: 1 GW_ID: 1 REALM: openairinterface.org + UE_MTU_IPV4: 1500 healthcheck: test: /bin/bash -c "pgrep oai_spgwc" interval: 10s @@ -168,8 +169,8 @@ services: NETWORK_UE_IP: '12.1.1.0/24' NETWORK_UE_NAT_OPTION: 'yes' MCC: '208' - MNC: '99' - MNC03: '099' + MNC: '97' + MNC03: '097' TAC: 1 GW_ID: 1 REALM: openairinterface.org diff --git a/ci-scripts/yaml_files/fr1_epc_tim/docker-compose.yml.orig b/ci-scripts/yaml_files/magma_nsa_20897/docker-compose.yml similarity index 62% rename from ci-scripts/yaml_files/fr1_epc_tim/docker-compose.yml.orig rename to ci-scripts/yaml_files/magma_nsa_20897/docker-compose.yml index 28ae154838..df14e900e7 100644 --- a/ci-scripts/yaml_files/fr1_epc_tim/docker-compose.yml.orig +++ b/ci-scripts/yaml_files/magma_nsa_20897/docker-compose.yml @@ -40,17 +40,18 @@ services: private_net: ipv4_address: 192.168.68.3 public_net: - ipv4_address: 192.168.61.2 + ipv4_address: 192.168.61.194 environment: + TZ: Europe/Paris REALM: openairinterface.org HSS_FQDN: hss.openairinterface.org PREFIX: /openair-hss/etc cassandra_Server_IP: 192.168.68.2 OP_KEY: 1006020f0a478bf6b699f15c062e42b3 - LTE_K: fec86ba6eb707ed08905757b1bb44b8f + LTE_K: FEC86BA6EB707ED08905757B1BB44B8F APN1: oai.ipv4 - APN2: internet - FIRST_IMSI: 222010100001120 + APN2: oai2.ipv4 + FIRST_IMSI: 208970100001127 NB_USERS: 10 healthcheck: test: /bin/bash -c "pgrep oai_hss" @@ -58,57 +59,45 @@ services: timeout: 5s retries: 5 - oai_mme: - image: oai-mme:production - container_name: prod-oai-mme + redis: + image: redis:6.0.5 + container_name: prod-redis privileged: true - depends_on: [oai_hss] networks: public_net: - ipv4_address: 192.168.61.3 + ipv4_address: 192.168.61.198 + volumes: + - ./redis_extern.conf:/usr/local/etc/redis/redis.conf + entrypoint: /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf" + healthcheck: + test: /bin/bash -c "redis-cli -h 192.168.61.198 -p 6380 ping" + interval: 10s + timeout: 5s + retries: 5 + + magma_mme: + image: magma-mme:production + container_name: prod-magma-mme + hostname: mme + privileged: true + depends_on: [oai_hss, redis] + networks: + public_net: + ipv4_address: 192.168.61.195 environment: + TZ: Europe/Paris REALM: openairinterface.org PREFIX: /openair-mme/etc - INSTANCE: 1 - PID_DIRECTORY: /var/run - HSS_IP_ADDR: 192.168.61.2 HSS_HOSTNAME: hss HSS_FQDN: hss.openairinterface.org HSS_REALM: openairinterface.org - MCC: '222' - MNC: '01' - MME_GID: 32768 - MME_CODE: 3 - TAC_0: 1 - TAC_1: 2 - TAC_2: 3 MME_FQDN: mme.openairinterface.org - MME_S6A_IP_ADDR: 192.168.61.3 - MME_INTERFACE_NAME_FOR_S1_MME: eth0 - MME_IPV4_ADDRESS_FOR_S1_MME: 192.168.61.3 - MME_INTERFACE_NAME_FOR_S11: eth0 - MME_IPV4_ADDRESS_FOR_S11: 192.168.61.3 - MME_INTERFACE_NAME_FOR_S10: lo - MME_IPV4_ADDRESS_FOR_S10: 127.0.0.10 - OUTPUT: CONSOLE - SGW_IPV4_ADDRESS_FOR_S11_0: 192.168.61.4 - PEER_MME_IPV4_ADDRESS_FOR_S10_0: 0.0.0.0 - PEER_MME_IPV4_ADDRESS_FOR_S10_1: 0.0.0.0 - MCC_SGW_0: '222' - MNC3_SGW_0: '001' - TAC_LB_SGW_0: '01' - TAC_HB_SGW_0: '00' - MCC_MME_0: '222' - MNC3_MME_0: '001' - TAC_LB_MME_0: '02' - TAC_HB_MME_0: '00' - MCC_MME_1: '222' - MNC3_MME_1: '001' - TAC_LB_MME_1: '03' - TAC_HB_MME_1: '00' - TAC_LB_SGW_TEST_0: '03' - TAC_HB_SGW_TEST_0: '00' - SGW_IPV4_ADDRESS_FOR_S11_TEST_0: 0.0.0.0 + FEATURES: mme_oai + volumes: + - ./mme_fd.sprint.conf:/magma-mme/etc/mme_fd.conf.tmplt + - ./mme.conf:/magma-mme/etc/mme.conf + - ./entrypoint.sh:/magma-mme/bin/entrypoint.sh + entrypoint: /bin/bash -c "/magma-mme/bin/entrypoint.sh" healthcheck: test: /bin/bash -c "pgrep oai_mme" interval: 10s @@ -118,22 +107,30 @@ services: oai_spgwc: image: oai-spgwc:production privileged: true - depends_on: [oai_mme] + depends_on: [magma_mme] container_name: prod-oai-spgwc networks: public_net: - ipv4_address: 192.168.61.4 + ipv4_address: 192.168.61.196 environment: - PID_DIRECTORY: /var/run + TZ: Europe/Paris SGW_INTERFACE_NAME_FOR_S11: eth0 - SGW_IP_FOR_S5_S8_CP: 127.0.0.11/8 - PGW_IP_FOR_S5_S8_CP: 127.0.0.12/8 PGW_INTERFACE_NAME_FOR_SX: eth0 - DEFAULT_APN: oai.ipv4 DEFAULT_DNS_IPV4_ADDRESS: 192.168.18.129 DEFAULT_DNS_SEC_IPV4_ADDRESS: 8.8.4.4 - UE_IP_ADDRESS_POOL: '12.1.1.2 - 12.1.1.254' - PUSH_PROTOCOL_OPTION: 'yes' + PUSH_PROTOCOL_OPTION: 'true' + APN_NI_1: oai.ipv4 + APN_NI_2: oai2.ipv4 + DEFAULT_APN_NI_1: oai.ipv4 + UE_IP_ADDRESS_POOL_1: '12.1.1.2 - 12.1.1.254' + UE_IP_ADDRESS_POOL_2: '12.0.0.2 - 12.0.0.254' + MCC: '208' + MNC: '97' + MNC03: '097' + TAC: 1 + GW_ID: 1 + REALM: openairinterface.org + UE_MTU_IPV4: 1500 healthcheck: test: /bin/bash -c "pgrep oai_spgwc" interval: 10s @@ -147,45 +144,39 @@ services: depends_on: [oai_spgwc] networks: public_net: - ipv4_address: 192.168.61.5 + ipv4_address: 192.168.61.197 environment: + TZ: Europe/Paris PID_DIRECTORY: /var/run INSTANCE: 1 SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP: eth0 PGW_INTERFACE_NAME_FOR_SGI: eth0 SGW_INTERFACE_NAME_FOR_SX: eth0 - SPGWC0_IP_ADDRESS: 192.168.61.4 + SPGWC0_IP_ADDRESS: 192.168.61.196 NETWORK_UE_IP: '12.1.1.0/24' NETWORK_UE_NAT_OPTION: 'yes' + MCC: '208' + MNC: '97' + MNC03: '097' + TAC: 1 + GW_ID: 1 + REALM: openairinterface.org healthcheck: test: /bin/bash -c "pgrep oai_spgwu" interval: 10s timeout: 5s retries: 5 - flexran_rtc: - image: flexran-rtc:production - privileged: true - container_name: prod-flexran-rtc - networks: - public_net: - ipv4_address: 192.168.61.10 - healthcheck: - test: /bin/bash -c "pgrep rt_controller" - interval: 10s - timeout: 5s - retries: 5 - trf_gen: image: trf-gen:production privileged: true container_name: prod-trf-gen networks: public_net: - ipv4_address: 192.168.61.11 - entrypoint: /bin/bash -c "ip route add 12.1.1.0/24 via 192.168.61.5 dev eth0; sleep infinity" + ipv4_address: 192.168.61.200 + entrypoint: /bin/bash -c "ip route add 12.1.1.0/24 via 192.168.61.197 dev eth0; sleep infinity" healthcheck: - test: /bin/bash -c "ping -c 2 192.168.61.5" + test: /bin/bash -c "ip route | grep '12.1.1.0'" interval: 10s timeout: 5s retries: 5 @@ -196,8 +187,12 @@ networks: ipam: config: - subnet: 192.168.68.0/26 + driver_opts: + com.docker.network.bridge.name: "oai-priv-net" public_net: name: prod-oai-public-net ipam: config: - - subnet: 192.168.61.0/26 + - subnet: 192.168.61.192/26 + driver_opts: + com.docker.network.bridge.name: "oai-pub-net" diff --git a/ci-scripts/yaml_files/magma_nsa_20897/entrypoint.sh b/ci-scripts/yaml_files/magma_nsa_20897/entrypoint.sh new file mode 100755 index 0000000000..859ff7d98f --- /dev/null +++ b/ci-scripts/yaml_files/magma_nsa_20897/entrypoint.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +INSTANCE=1 +PREFIX='/magma-mme/etc' +MY_REALM='openairinterface.org' + +declare -A MME_CONF + +pushd $PREFIX +MME_CONF[@MME_S6A_IP_ADDR@]="192.168.61.195" +MME_CONF[@INSTANCE@]=$INSTANCE +MME_CONF[@PREFIX@]=$PREFIX +MME_CONF[@REALM@]=$MY_REALM +MME_CONF[@MME_FQDN@]="mme.${MME_CONF[@REALM@]}" +MME_CONF[@HSS_HOSTNAME@]='hss' +MME_CONF[@HSS_FQDN@]="${MME_CONF[@HSS_HOSTNAME@]}.${MME_CONF[@REALM@]}" +MME_CONF[@HSS_IP_ADDR@]="192.168.61.194" + +cp mme_fd.conf.tmplt $PREFIX/mme_fd.conf + +for K in "${!MME_CONF[@]}"; do + egrep -lRZ "$K" $PREFIX/mme_fd.conf | xargs -0 -l sed -i -e "s|$K|${MME_CONF[$K]}|g" + ret=$?;[[ ret -ne 0 ]] && echo "Tried to replace $K with ${MME_CONF[$K]}" +done + +sed -i -e "s@etc/freeDiameter@etc@" /magma-mme/etc/mme_fd.conf +sed -i -e "s@bind: 127.0.0.1@bind: 192.168.61.198@" /etc/magma/redis.yml +# Generate freeDiameter certificate +popd +cd /magma-mme/scripts +./check_mme_s6a_certificate $PREFIX mme.${MME_CONF[@REALM@]} + +cd /magma-mme +nohup /magma-mme/bin/sctpd > /var/log/sctpd.log 2>&1 & +sleep 5 +/magma-mme/bin/oai_mme -c /magma-mme/etc/mme.conf diff --git a/ci-scripts/yaml_files/magma_nsa_20897/mme.conf b/ci-scripts/yaml_files/magma_nsa_20897/mme.conf new file mode 100644 index 0000000000..e41fbe6304 --- /dev/null +++ b/ci-scripts/yaml_files/magma_nsa_20897/mme.conf @@ -0,0 +1,136 @@ +# generated by generate_mme_config_script.py +MME : +{ + REALM = "openairinterface.org" + PID_DIRECTORY = "/var/run"; + MAXENB = 8; # power of 2 + MAXUE = 16; # power of 2 + RELATIVE_CAPACITY = 10; + + EMERGENCY_ATTACH_SUPPORTED = "no"; + UNAUTHENTICATED_IMSI_SUPPORTED = "no"; + + # EPS network feature support + EPS_NETWORK_FEATURE_SUPPORT_IMS_VOICE_OVER_PS_SESSION_IN_S1 = "no"; # DO NOT CHANGE + EPS_NETWORK_FEATURE_SUPPORT_EMERGENCY_BEARER_SERVICES_IN_S1_MODE = "no"; # DO NOT CHANGE + EPS_NETWORK_FEATURE_SUPPORT_LOCATION_SERVICES_VIA_EPC = "no"; # DO NOT CHANGE + EPS_NETWORK_FEATURE_SUPPORT_EXTENDED_SERVICE_REQUEST = "no"; # DO NOT CHANGE + + # Display statistics about whole system (expressed in seconds) + MME_STATISTIC_TIMER = 10; + IP_CAPABILITY = "IPV4"; # UE PDN_TYPE + USE_STATELESS = ""; + + INTERTASK_INTERFACE : + { + # max queue size per task + ITTI_QUEUE_SIZE = 2000000; + }; + + S6A : + { + S6A_CONF = "/magma-mme/etc/mme_fd.conf"; # YOUR MME freeDiameter config file path + HSS_HOSTNAME = "hss.openairinterface.org"; + HSS_REALM = "openairinterface.org"; + }; + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 8; + SCTP_OUTSTREAMS = 8; + }; + + # ------- S1AP definitions + S1AP : + { + # outcome drop timer value (seconds) + S1AP_OUTCOME_TIMER = 10; + }; + + # ------- MME served GUMMEIs + GUMMEI_LIST = ( + { MCC="208" ; MNC="97"; MME_GID="32768" ; MME_CODE="3"; } + ); + + # ------- MME served TAIs + TAI_LIST = ( + {MCC="208" ; MNC="97"; TAC = "1"; }, + {MCC="208" ; MNC="97"; TAC = "2"; }, + {MCC="208" ; MNC="97"; TAC = "3"; } + ); + + TAC_LIST = ( + {MCC="208" ; MNC="97"; TAC = "1"; } + ); + + CSFB : + { + NON_EPS_SERVICE_CONTROL = "OFF"; + CSFB_MCC = "208"; + CSFB_MNC = "97"; + LAC = "1"; + }; + NAS : + { + ORDERED_SUPPORTED_INTEGRITY_ALGORITHM_LIST = [ "EIA2" , "EIA1" , "EIA0" ]; + ORDERED_SUPPORTED_CIPHERING_ALGORITHM_LIST = [ "EEA0" , "EEA1" , "EEA2" ]; + T3402 = 1 # in minutes (default is 12 minutes) + T3412 = 54 # in minutes (default is 54 minutes, network dependent) + T3422 = 6 # in seconds (default is 6s) + T3450 = 6 # in seconds (default is 6s) + T3460 = 6 # in seconds (default is 6s) + T3470 = 6 # in seconds (default is 6s) + T3485 = 8 # UNUSED in seconds (default is 8s) + T3486 = 8 # UNUSED in seconds (default is 8s) + T3489 = 4 # UNUSED in seconds (default is 4s) + T3495 = 8 # UNUSED in seconds (default is 8s) + }; + + SGS : + { + TS6_1 = 10 # in seconds (default is 10s) + TS8 = 4 # in seconds (default is 4s) + TS9 = 2 # in seconds (default is 4s) + TS10 = 4 # in seconds (default is 4s) + TS13 = 4 # in seconds (default is 4s) + }; + + NETWORK_INTERFACES : + { + MME_INTERFACE_NAME_FOR_S1_MME = "eth0"; + MME_IPV4_ADDRESS_FOR_S1_MME = "192.168.61.195/24"; + MME_INTERFACE_NAME_FOR_S11_MME = "eth0"; + MME_IPV4_ADDRESS_FOR_S11_MME = "192.168.61.195/24"; + MME_PORT_FOR_S11_MME = 2123; + }; + + LOGGING : + { + OUTPUT = "CONSOLE"; + THREAD_SAFE = "no"; + COLOR = "no"; + + SCTP_LOG_LEVEL = "ERROR"; + GTPV1U_LOG_LEVEL = "INFO"; + SPGW_APP_LOG_LEVEL = "INFO"; + UDP_LOG_LEVEL = "INFO"; + S1AP_LOG_LEVEL = "DEBUG"; + NAS_LOG_LEVEL = "INFO"; + MME_APP_LOG_LEVEL = "DEBUG"; + GTPV2C_LOG_LEVEL = "INFO"; + S11_LOG_LEVEL = "DEBUG"; + S6A_LOG_LEVEL = "DEBUG"; + UTIL_LOG_LEVEL = "INFO"; + MSC_LOG_LEVEL = "ERROR"; + ITTI_LOG_LEVEL = "ERROR"; + MME_SCENARIO_PLAYER_LOG_LEVEL = "ERROR"; + ASN1_VERBOSITY = "INFO"; + }; + + S-GW : + { + SGW_IPV4_ADDRESS_FOR_S11 = "192.168.61.196"; + }; +}; diff --git a/ci-scripts/yaml_files/magma_nsa_20897/mme_fd.sprint.conf b/ci-scripts/yaml_files/magma_nsa_20897/mme_fd.sprint.conf new file mode 100644 index 0000000000..6f87ed8c2b --- /dev/null +++ b/ci-scripts/yaml_files/magma_nsa_20897/mme_fd.sprint.conf @@ -0,0 +1,169 @@ +# -------- Local --------- + +# Uncomment if the framework cannot resolv it. +Identity = "@MME_FQDN@"; +Realm = "@REALM@"; + +# TLS configuration (see previous section) +TLS_Cred = "@PREFIX@/freeDiameter/mme.cert.pem", + "@PREFIX@/freeDiameter/mme.key.pem"; +TLS_CA = "@PREFIX@/freeDiameter/mme.cacert.pem"; + +# Disable use of TCP protocol (only listen and connect in SCTP) +# Default : TCP enabled +No_SCTP; + +# This option is ignored if freeDiameter is compiled with DISABLE_SCTP option. +# Prefer TCP instead of SCTP for establishing new connections. +# This setting may be overwritten per peer in peer configuration blocs. +# Default : SCTP is attempted first. +Prefer_TCP; + + +No_IPv6; + +# Overwrite the number of SCTP streams. This value should be kept low, +# especially if you are using TLS over SCTP, because it consumes a lot of +# resources in that case. See tickets 19 and 27 for some additional details on +# this. +# Limit the number of SCTP streams +SCTP_streams = 3; + + +# By default, freeDiameter acts as a Diameter Relay Agent by forwarding all +# messages it cannot handle locally. This parameter disables this behavior. +NoRelay; + +# Use RFC3588 method for TLS protection, where TLS is negociated after CER/CEA exchange is completed +# on the unsecure connection. The alternative is RFC6733 mechanism, where TLS protects also the +# CER/CEA exchange on a dedicated secure port. +# This parameter only affects outgoing connections. +# The setting can be also defined per-peer (see Peers configuration section). +# Default: use RFC6733 method with separate port for TLS. + +#TLS_old_method; + +AppServThreads = 4; + +# Specify the addresses on which to bind the listening server. This must be +# specified if the framework is unable to auto-detect these addresses, or if the +# auto-detected values are incorrect. Note that the list of addresses is sent +# in CER or CEA message, so one should pay attention to this parameter if some +# adresses should be kept hidden. +ListenOn = "@MME_S6A_IP_ADDR@"; + +Port = 3870; +SecPort = 5870; + +# -------- Extensions --------- + +# Uncomment (and create rtd.conf) to specify routing table for this peer. +#LoadExtension = "/usr/local/lib/freeDiameter/rt_default.fdx" : "rtd.conf"; + +#LoadExtension = "/usr/local/lib/freeDiameter/_sample.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/app_acct.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/app_diameap.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/app_radgw.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/app_redirect.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/app_sip.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dbg_interactive.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dbg_monitor.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dbg_msg_dumps.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dbg_msg_timings.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dbg_rt.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_3gpp2_avps.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_CreditControl.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_CxDx.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_Gx.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_NAS.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_Ro.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_Rx.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_S6mS6n.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_SGd.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_SLh.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_Sd.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_Sh.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_T4.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_T6aT6bT7.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_Tsp.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_dcca.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_dcca_3gpp.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_dcca_starent.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_draftload_avps.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_eap.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_etsi283034_avps.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_legacy_xml.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_mip6a.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_mip6i.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_nas_mipv6.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_nasreq.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_rfc4004_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_rfc4006bis_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_rfc4072_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_rfc4590_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_rfc5447_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_rfc5580_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_rfc5777_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_rfc5778_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_rfc6734_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_rfc6942_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_rfc7155_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_rfc7683_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_rfc7944_avps.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_sip.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29061_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29128_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29154_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29173_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29212_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29214_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29215_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29217_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29229_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29272_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29273_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29329_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29336_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29337_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29338_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29343_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29344_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29345_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29368_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts29468_avps.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_ts32299_avps.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/rt_busypeers.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/rt_default.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/rt_ereg.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/rt_ignore_dh.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/rt_load_balance.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/rt_randomize.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/rt_redirect.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/test_acct.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/test_app.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/test_hss.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/test_netemul.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/test_rt_any.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/test_sip.fdx"; +#LoadExtension = "/usr/local/lib/freeDiameter/dict_Rf.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_S6as6d.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_S6t.fdx"; +LoadExtension = "/usr/local/lib/freeDiameter/dict_S6c.fdx"; + + +# -------- Peers --------- + +# The framework will actively attempt to establish and maintain a connection +# with the peers listed here. +# For only accepting incoming connections, see the acl_wl.fx extension. + +# ConnectPeer +# Declare a remote peer to which this peer must maintain a connection. +# In addition, this allows specifying non-default parameters for this peer only +# (for example disable SCTP with this peer, or use RFC3588-flavour TLS). +# Note that by default, if a peer is not listed as a ConnectPeer entry, an +# incoming connection from this peer will be rejected. If you want to accept +# incoming connections from other peers, see the acl_wl.fdx? extension which +# allows exactly this. + +ConnectPeer= "@HSS_FQDN@" { ConnectTo = "@HSS_IP_ADDR@"; No_SCTP ; No_IPv6; Prefer_TCP; No_TLS; port = 3868;}; diff --git a/ci-scripts/yaml_files/magma_nsa_20897/redis_extern.conf b/ci-scripts/yaml_files/magma_nsa_20897/redis_extern.conf new file mode 100644 index 0000000000..565524080a --- /dev/null +++ b/ci-scripts/yaml_files/magma_nsa_20897/redis_extern.conf @@ -0,0 +1,33 @@ +# +# Copyright (c) 2016-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. An additional grant +# of patent rights can be found in the PATENTS file in the same directory. + +# Jinja template for Redis configuration +# See the default config file for options and explanations: +# https://github.com/antirez/redis/blob/unstable/redis.conf + +# TODO: make sensible, production-aware config decisions + +bind 192.168.61.198 +port 6380 + +daemonize no +loglevel notice + +timeout 0 +databases 1 + +dbfilename redis_dump.rdb +dir /data + +# Save the DB on disk + +save 900 1 + +save 300 10 + +save 60 1000 diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index cad45fd7ef..8ad515625d 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -309,6 +309,7 @@ endif() # # add autotools definitions that were maybe used! + add_definitions("-DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_FCNTL_H=1 -DHAVE_ARPA_INET_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_SYS_SOCKET_H=1 -DHAVE_STRERROR=1 -DHAVE_SOCKET=1 -DHAVE_MEMSET=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_STDLIB_H=1 -DHAVE_MALLOC=1 -DHAVE_LIBSCTP") set(commonOpts "-pipe -Wno-packed-bitfield-compat -fPIC -Wall -fno-strict-aliasing -rdynamic") @@ -318,11 +319,7 @@ set(CMAKE_C_FLAGS set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${C_FLAGS_PROCESSOR} ${commonOpts} -std=c++11") -# cuda compiler bug (limitation) on complex macro definition -if (CUDA_FOUND) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCUDA_FLAG") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DCUDA_FLAG") -endif() + if (SANITIZE_ADDRESS) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-common") @@ -1588,6 +1585,16 @@ set(PHY_LDPC_OPTIM8SEGMULTI_SRC ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c ) +set(PHY_LDPC_CUDA_SRC + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c +) + +set(PHY_LDPC_CL_SRC + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c +) + set(PHY_NR_CODINGIF ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_load.c; ) @@ -1595,8 +1602,18 @@ set(PHY_NR_CODINGIF add_library(ldpc_orig MODULE ${PHY_LDPC_ORIG_SRC} ) add_library(ldpc_optim MODULE ${PHY_LDPC_OPTIM_SRC} ) add_library(ldpc_optim8seg MODULE ${PHY_LDPC_OPTIM8SEG_SRC} ) +add_library(ldpc_cl MODULE ${PHY_LDPC_CL_SRC} ) +target_link_libraries(ldpc_cl OpenCL) + +if (CUDA_FOUND) + cuda_add_library(ldpc_cuda MODULE ${PHY_LDPC_CUDA_SRC} ) + set_target_properties(ldpc_cuda PROPERTIES CUDA_SEPARABLE_COMPILATION ON) +# CUDA_ADD_CUFFT_TO_TARGET(ldpc_cuda) +endif (CUDA_FOUND) + add_library(ldpc MODULE ${PHY_LDPC_OPTIM8SEGMULTI_SRC} ) + add_library(coding MODULE ${PHY_TURBOSRC} ) add_library(dfts MODULE ${OPENAIR1_DIR}/PHY/TOOLS/oai_dfts.c ) @@ -1742,7 +1759,6 @@ set(PHY_SRC_UE set(PHY_NR_SRC_COMMON ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_prach_common.c - ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dci_tools_common.c ) set(PHY_NR_SRC @@ -1981,6 +1997,10 @@ set(NR_PDCP_SRC ${OPENAIR2_DIR}/LAYER2/nr_pdcp/asn1_utils.c ) +set(NR_SDAP_SRC + ${OPENAIR2_DIR}/SDAP/nr_sdap/nr_sdap_gnb.c + ) + set(L2_SRC ${PDCP_DIR}/pdcp.c ${PDCP_DIR}/pdcp_fifo.c @@ -2024,6 +2044,7 @@ set(L2_LTE_SRC set(L2_NR_SRC ${NR_RLC_SRC} ${NR_PDCP_SRC} + ${NR_SDAP_SRC} ${NR_RRC_DIR}/rrc_gNB.c ${NR_RRC_DIR}/nr_rrc_common.c ${NR_RRC_DIR}/L2_nr_interface.c @@ -2059,6 +2080,7 @@ set(L2_RRC_SRC_UE set(NR_L2_SRC_UE ${NR_RLC_SRC} ${NR_PDCP_SRC} + ${NR_SDAP_SRC} ${NR_UE_RRC_DIR}/L2_interface_ue.c ${NR_UE_RRC_DIR}/main_ue.c ${NR_UE_RRC_DIR}/rrc_UE.c @@ -3110,7 +3132,11 @@ target_link_libraries (nr-uesoftmodem ${LIB_LMS_LIBRARIES}) target_link_libraries (nr-uesoftmodem ${T_LIB}) add_dependencies( nr-uesoftmodem ldpc_orig ldpc_optim ldpc_optim8seg ldpc ) - +if (CUDA_FOUND) + add_dependencies( nr-uesoftmodem ldpc_cuda) + add_dependencies( nr-softmodem ldpc_cuda) + add_dependencies( ocp-gnb ldpc_cuda) +endif (CUDA_FOUND) ###################################" # Addexecutables for tests #################################### @@ -3170,46 +3196,18 @@ target_link_libraries(smallblocktest m pthread ${ATLAS_LIBRARIES} dl ) -if (CUDA_FOUND) -################################################### -# For CUDA library -################################################### - CUDA_ADD_LIBRARY(LDPC_CU - ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu - ) - CUDA_ADD_CUFFT_TO_TARGET(LDPC_CU) - cuda_add_executable(ldpctest - ${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/ldpctest.c - ${T_SOURCE} - ${SHLIB_LOADER_SOURCES} - ) - target_link_libraries(ldpctest -ldl - -Wl,--start-group - LDPC_CU UTIL SIMU PHY_NR CONFIG_LIB - -Wl,--end-group - m pthread ${ATLAS_LIBRARIES} dl - ) +add_executable(ldpctest + ${PHY_NR_CODINGIF} + ${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/ldpctest.c + ${T_SOURCE} + ${SHLIB_LOADER_SOURCES} + ) -else (CUDA_FOUND) - add_executable(ldpctest - ${PHY_NR_CODINGIF} - ${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/ldpctest.c - ${T_SOURCE} - ${SHLIB_LOADER_SOURCES} - ) - -endif () - - -# add_executable(ldpctest - # ${PHY_NR_CODINGIF} - # ${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/ldpctest.c - # ${T_SOURCE} - # ${SHLIB_LOADER_SOURCES} - # ) add_dependencies( ldpctest ldpc_orig ldpc_optim ldpc_optim8seg ldpc ) - +if (CUDA_FOUND) + add_dependencies( ldpctest ldpc_cuda) +endif (CUDA_FOUND) target_link_libraries(ldpctest -Wl,--start-group UTIL SIMU_COMMON SIMU PHY_NR PHY_COMMON PHY_NR_COMMON CONFIG_LIB -Wl,--end-group m pthread ${ATLAS_LIBRARIES} dl diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index c9390d67ce..c68ca8a553 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -551,7 +551,7 @@ function main() { if [ "$HW" == "OAI_USRP" ] ; then echo_info "installing packages for USRP support" check_install_usrp_uhd_driver - if [ ! "$DISABLE_HARDWARE_DEPENDENCY" == "True" ]; then + if [ ! -v BUILD_UHD_FROM_SOURCE ] && [ ! "$DISABLE_HARDWARE_DEPENDENCY" == "True" ]; then install_usrp_uhd_driver $UHD_IMAGES_DIR fi fi diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index d3fcf615e2..c5cc9d054d 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -317,19 +317,30 @@ install_usrp_uhd_driver_from_source(){ echo_info "\nInstalling UHD driver from sources. The log file for UHD driver installation is here: $uhd_install_log " ( pushd /tmp - echo "Downloading UHD driver" + echo "Cloning UHD driver repository" rm -rf /tmp/uhd git clone https://github.com/EttusResearch/uhd.git cd uhd - git checkout tags/v4.0.0.0 + if [[ -v UHD_VERSION ]]; then + git checkout tags/v${UHD_VERSION} + else + git checkout tags/v4.0.0.0 + fi mkdir -p host/build - cd host/build - $CMAKE ../ + cd host/build || true + $CMAKE ../ -GNinja echo "Compiling UHD" - make -j`nproc` - make test - $SUDO make install + ninja + $SUDO ninja install $SUDO ldconfig -v + if [ $IS_CONTAINER -eq 0 ]; then + if [[ "$OS_DISTRO" == "ubuntu" ]]; then + $SUDO /usr/local/lib/uhd/utils/uhd_images_downloader.py + fi + if [[ "$OS_DISTRO" == "rhel" ]]; then + $SUDO /usr/local/lib64/uhd/utils/uhd_images_downloader.py + fi + fi popd rm -rf /tmp/uhd ) >& $uhd_install_log @@ -338,10 +349,26 @@ install_usrp_uhd_driver_from_source(){ check_install_usrp_uhd_driver(){ if [[ "$OS_DISTRO" == "ubuntu" ]]; then #first we remove old installation - $SUDO apt-get remove -y uhd || true - $SUDO apt-get remove libuhd-dev libuhd003 uhd-host -y || true + $SUDO apt-get remove uhd -y || true + $SUDO apt-get remove uhd-host -y || true + $SUDO apt-get remove libuhd-dev -y || true + $SUDO apt-get remove libuhd003 -y || true + $SUDO apt-get remove libuhd3.13.1 -y || true + $SUDO apt-get remove libuhd3.14.0 -y || true + $SUDO apt-get remove libuhd3.14.1 -y || true + $SUDO apt-get remove libuhd3.15.0 -y || true + local distribution=$(get_distribution_release) + if [[ "$distribution" == "ubuntu18.04" ]]; then + $SUDO apt-get remove libuhd4.0.0 -y || true + $SUDO apt-get remove libuhd4.1.0 -y || true + fi v=$(lsb_release -cs) $SUDO apt-add-repository --remove "deb http://files.ettus.com/binaries/uhd/repo/uhd/ubuntu/$v $v main" + if [[ -v BUILD_UHD_FROM_SOURCE ]]; then + $SUDO apt-get install -y libboost-all-dev libusb-1.0-0-dev doxygen python3-docutils python3-mako python3-numpy python3-requests python3-setuptools ninja-build + install_usrp_uhd_driver_from_source + return + fi # The new USRP repository # Raphael Defosseux: Adding a loop on adding PPA because in CI the gpg key retrieve may # timeout due to proxy / network latencies in Eurecom on VM @@ -361,7 +388,12 @@ check_install_usrp_uhd_driver(){ done $SUDO apt-get update $SUDO apt-get -y install python python-tk libboost-all-dev libusb-1.0-0-dev - $SUDO apt-get -y install libuhd-dev libuhd003 uhd-host + if [[ "$distribution" == "ubuntu16.04" ]]; then + $SUDO apt-get -y install libuhd-dev libuhd3.15.0 uhd-host + fi + if [[ "$distribution" == "ubuntu18.04" ]]; then + $SUDO apt-get -y install libuhd-dev libuhd4.1.0 uhd-host + fi elif [[ "$OS_BASEDISTRO" == "fedora" ]]; then if [ $IS_CONTAINER -eq 0 ] then @@ -692,6 +724,7 @@ check_install_oai_software() { build-essential \ $CMAKE \ cmake-curses-gui \ + curl \ ninja-build \ doxygen \ doxygen-gui \ diff --git a/common/utils/DOC/loader/devusage/api.md b/common/utils/DOC/loader/devusage/api.md index a6e59c5938..41a0807a24 100644 --- a/common/utils/DOC/loader/devusage/api.md +++ b/common/utils/DOC/loader/devusage/api.md @@ -10,6 +10,10 @@ int load_module_shlib(char *modname,loader_shlibfunc_t *farray, int numf) * If the farray pointer is null, looks for `< modname >_getfarray` symbol, calls the corresponding function when the symbol is found. `< modname >_getfarray` takes one argument, a pointer to a `loader_shlibfunc_t` array, and returns the number of items in this array, as defined by the `getfarrayfunc_t` type. The `loader_shlibfunc_t` array returned by the shared library must be fully filled (both `fname` and `fptr` fields). * looks for the `numf` function symbols listed in the `farray[i].fname` arguments and set the corresponding `farray[i].fptr`function pointers +```c +int load_module_version_shlib(char *modname, char *version, loader_shlibfunc_t *farray, int numf) +``` +Allows loading a specific library version, as specified by the `version` parameter. When version is not NULL the version that is possibly specified as a config module parameter is ignored. This call has been introduced for phy simulators executables which do not use the config module. It is used, for example, by the ldcp initialization (`load_nrLDPClib` function in [nrLDPC_load.c](../../../../../openair1/PHY/CODING/nrLDPC_load.c) to allow the `ldpctest` simulator to select the cuda accelerated ldcp implementation. `load_module_shlib` is just a define macro to switch to a `load_module_version_shlib` call, adding a NULL pointer for the version parameter. ```c void * get_shlibmodule_fptr(char *modname, char *fname) diff --git a/common/utils/load_module_shlib.c b/common/utils/load_module_shlib.c index a4b4742c94..2b0d339358 100644 --- a/common/utils/load_module_shlib.c +++ b/common/utils/load_module_shlib.c @@ -63,7 +63,7 @@ void loader_init(void) { } /* build the full shared lib name from the module name */ -char *loader_format_shlibpath(char *modname) +char *loader_format_shlibpath(char *modname, char *version) { char *tmpstr; @@ -97,7 +97,10 @@ int ret; shlibpath = loader_data.shlibpath ; } /* no specific shared lib version */ - if (shlibversion == NULL) { + if (version != NULL) { // version specified as a function parameter + shlibversion=version; + } + if (shlibversion == NULL) { // no specific version specified, neither as a config param or as a function param shlibversion = "" ; } /* alloc memory for full module shared lib file name */ @@ -118,7 +121,7 @@ int ret; return tmpstr; } -int load_module_shlib(char *modname,loader_shlibfunc_t *farray, int numf, void *autoinit_arg) +int load_module_version_shlib(char *modname, char *version, loader_shlibfunc_t *farray, int numf, void *autoinit_arg) { void *lib_handle = NULL; initfunc_t fpi; @@ -138,7 +141,7 @@ int load_module_shlib(char *modname,loader_shlibfunc_t *farray, int numf, void * loader_init(); } - shlib_path = loader_format_shlibpath(modname); + shlib_path = loader_format_shlibpath(modname, version); for (int i = 0; i < loader_data.numshlibs; i++) { if (strcmp(loader_data.shlibs[i].name, modname) == 0) { diff --git a/common/utils/load_module_shlib.h b/common/utils/load_module_shlib.h index 685b3d1b65..0e80a5353c 100644 --- a/common/utils/load_module_shlib.h +++ b/common/utils/load_module_shlib.h @@ -84,10 +84,11 @@ loader_data_t loader_data; /*-------------------------------------------------------------------------------------------------------------*/ #else /* LOAD_MODULE_SHLIB_MAIN */ -extern int load_module_shlib(char *modname, loader_shlibfunc_t *farray, int numf, void *initfunc_arg); + +extern int load_module_version_shlib(char *modname, char *version, loader_shlibfunc_t *farray, int numf, void *initfunc_arg); extern void * get_shlibmodule_fptr(char *modname, char *fname); extern loader_data_t loader_data; #endif /* LOAD_MODULE_SHLIB_MAIN */ - +#define load_module_shlib(M, F, N, I) load_module_version_shlib(M, NULL, F, N, I) #endif diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index 8ba4633604..0a532c346b 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -34,6 +34,8 @@ #include "assertions.h" #include "nr_common.h" +const char *duplex_mode[]={"FDD","TDD"}; + // Table 5.2-1 NR operating bands in FR1 & FR2 (3GPP TS 38.101) // Table 5.4.2.3-1 Applicable NR-ARFCN per operating band in FR1 & FR2 (3GPP TS 38.101) // Notes: @@ -231,6 +233,30 @@ uint32_t nr_get_code_rate(uint8_t Imcs, uint8_t table_idx) { } +void get_coreset_rballoc(uint8_t *FreqDomainResource,int *n_rb,int *rb_offset) { + + uint8_t count=0, start=0, start_set=0; + + uint64_t bitmap = (((uint64_t)FreqDomainResource[0])<<37)| + (((uint64_t)FreqDomainResource[1])<<29)| + (((uint64_t)FreqDomainResource[2])<<21)| + (((uint64_t)FreqDomainResource[3])<<13)| + (((uint64_t)FreqDomainResource[4])<<5)| + (((uint64_t)FreqDomainResource[5])>>3); + + for (int i=0; i<45; i++) + if ((bitmap>>(44-i))&1) { + count++; + if (!start_set) { + start = i; + start_set = 1; + } + } + *rb_offset = 6*start; + *n_rb = 6*count; +} + + int get_dmrs_port(int nl, uint16_t dmrs_ports) { if (dmrs_ports == 0) return 0; // dci 1_0 @@ -249,6 +275,176 @@ int get_dmrs_port(int nl, uint16_t dmrs_ports) { return p; } +int get_num_dmrs(uint16_t dmrs_mask ) { + + int num_dmrs=0; + + for (int i=0;i<16;i++) num_dmrs+=((dmrs_mask>>i)&1); + return(num_dmrs); +} + +lte_frame_type_t get_frame_type(uint16_t current_band, uint8_t scs_index) +{ + lte_frame_type_t current_type; + int32_t delta_duplex = get_delta_duplex(current_band, scs_index); + + if (delta_duplex == 0) + current_type = TDD; + else + current_type = FDD; + + LOG_I(NR_MAC, "NR band %d, duplex mode %s, duplex spacing = %d KHz\n", current_band, duplex_mode[current_type], delta_duplex); + + return current_type; +} + +// Computes the duplex spacing (either positive or negative) in KHz +int32_t get_delta_duplex(int nr_bandP, uint8_t scs_index) +{ + int nr_table_idx = get_nr_table_idx(nr_bandP, scs_index); + + int32_t delta_duplex = (nr_bandtable[nr_table_idx].ul_min - nr_bandtable[nr_table_idx].dl_min); + + LOG_I(NR_MAC, "NR band duplex spacing is %d KHz (nr_bandtable[%d].band = %d)\n", delta_duplex, nr_table_idx, nr_bandtable[nr_table_idx].band); + + return delta_duplex; +} + +uint16_t config_bandwidth(int mu, int nb_rb, int nr_band) +{ + + if (nr_band < 100) { //FR1 + switch(mu) { + case 0 : + if (nb_rb<=25) + return 5; + if (nb_rb<=52) + return 10; + if (nb_rb<=79) + return 15; + if (nb_rb<=106) + return 20; + if (nb_rb<=133) + return 25; + if (nb_rb<=160) + return 30; + if (nb_rb<=216) + return 40; + if (nb_rb<=270) + return 50; + AssertFatal(1==0,"Number of DL resource blocks %d undefined for mu %d and band %d\n", nb_rb, mu, nr_band); + break; + case 1 : + if (nb_rb<=11) + return 5; + if (nb_rb<=24) + return 10; + if (nb_rb<=38) + return 15; + if (nb_rb<=51) + return 20; + if (nb_rb<=65) + return 25; + if (nb_rb<=78) + return 30; + if (nb_rb<=106) + return 40; + if (nb_rb<=133) + return 50; + if (nb_rb<=162) + return 60; + if (nb_rb<=189) + return 70; + if (nb_rb<=217) + return 80; + if (nb_rb<=245) + return 90; + if (nb_rb<=273) + return 100; + AssertFatal(1==0,"Number of DL resource blocks %d undefined for mu %d and band %d\n", nb_rb, mu, nr_band); + break; + case 2 : + if (nb_rb<=11) + return 10; + if (nb_rb<=18) + return 15; + if (nb_rb<=24) + return 20; + if (nb_rb<=31) + return 25; + if (nb_rb<=38) + return 30; + if (nb_rb<=51) + return 40; + if (nb_rb<=65) + return 50; + if (nb_rb<=79) + return 60; + if (nb_rb<=93) + return 70; + if (nb_rb<=107) + return 80; + if (nb_rb<=121) + return 90; + if (nb_rb<=135) + return 100; + AssertFatal(1==0,"Number of DL resource blocks %d undefined for mu %d and band %d\n", nb_rb, mu, nr_band); + break; + default: + AssertFatal(1==0,"Numerology %d undefined for band %d in FR1\n", mu,nr_band); + } + } + else { + switch(mu) { + case 2 : + if (nb_rb<=66) + return 50; + if (nb_rb<=132) + return 100; + if (nb_rb<=264) + return 200; + AssertFatal(1==0,"Number of DL resource blocks %d undefined for mu %d and band %d\n", nb_rb, mu, nr_band); + break; + case 3 : + if (nb_rb<=32) + return 50; + if (nb_rb<=66) + return 100; + if (nb_rb<=132) + return 200; + if (nb_rb<=264) + return 400; + AssertFatal(1==0,"Number of DL resource blocks %d undefined for mu %d and band %d\n", nb_rb, mu, nr_band); + break; + default: + AssertFatal(1==0,"Numerology %d undefined for band %d in FR1\n", mu,nr_band); + } + } +} + +// Returns the corresponding row index of the NR table +int get_nr_table_idx(int nr_bandP, uint8_t scs_index) { + int i, j; + int scs_khz = 15 << scs_index; + int supplementary_bands[] = {29,75,76,80,81,82,83,84,86,89,95}; + size_t s = sizeof(supplementary_bands)/sizeof(supplementary_bands[0]); + + for(j = 0; j < s; j++){ + if (nr_bandP == supplementary_bands[j]) + AssertFatal(0 == 1, "Band %d is a supplementary band (%d). This is not supported yet.\n", nr_bandP, supplementary_bands[j]); + } + + AssertFatal(nr_bandP <= nr_bandtable[nr_bandtable_size-1].band, "NR band %d exceeds NR bands table maximum limit %d\n", nr_bandP, nr_bandtable[nr_bandtable_size-1].band); + for (i = 0; i < nr_bandtable_size && nr_bandtable[i].band != nr_bandP; i++); + + // selection of correct Deltaf raster according to SCS + if ((nr_bandtable[i].deltaf_raster != 100) && (nr_bandtable[i].deltaf_raster != scs_khz)) + i++; + + LOG_D(PHY, "NR band table index %d (Band %d, dl_min %lu, ul_min %lu)\n", i, nr_bandtable[i].band, nr_bandtable[i].dl_min,nr_bandtable[i].ul_min); + + return i; +} int get_subband_size(int NPRB,int size) { // implements table 5.2.1.4-2 from 36.214 diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index b3d2469a12..d9f2b0c03a 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -35,6 +35,7 @@ #include #include "assertions.h" +#include "PHY/defs_common.h" typedef struct nr_bandentry_s { int16_t band; @@ -50,6 +51,12 @@ typedef struct nr_bandentry_s { extern const size_t nr_bandtable_size; extern nr_bandentry_t nr_bandtable[]; +void get_coreset_rballoc(uint8_t *FreqDomainResource,int *n_rb,int *rb_offset); +int get_num_dmrs(uint16_t dmrs_mask); +uint16_t config_bandwidth(int mu, int nb_rb, int nr_band); +int get_nr_table_idx(int nr_bandP, uint8_t scs_index); +int32_t get_delta_duplex(int nr_bandP, uint8_t scs_index); +lte_frame_type_t get_frame_type(uint16_t nr_bandP, uint8_t scs_index); uint16_t get_band(uint64_t downlink_frequency, int32_t delta_duplex); int NRRIV2BW(int locationAndBandwidth,int N_RB); int NRRIV2PRBOFFSET(int locationAndBandwidth,int N_RB); diff --git a/common/utils/telnetsrv/telnetsrv.c b/common/utils/telnetsrv/telnetsrv.c index 734126721a..9e4eeca205 100644 --- a/common/utils/telnetsrv/telnetsrv.c +++ b/common/utils/telnetsrv/telnetsrv.c @@ -51,6 +51,7 @@ #include #include #include +#include #include "common/utils/load_module_shlib.h" #include "common/config/config_userapi.h" #include "common/utils/threadPool/thread-pool.h" @@ -62,34 +63,27 @@ #include "telnetsrv_proccmd.h" static char *telnet_defstatmod[] = {"softmodem","phy","loader","measur"}; static telnetsrv_params_t telnetparams; -#define TELNETSRV_LISTENADDR 0 -#define TELNETSRV_LISTENPORT 1 -#define TELNETSRV_PRIORITY 2 -#define TELNETSRV_DEBUG 3 -#define TELNETSRV_LOOPC 4 -#define TELNETSRV_LOOPD 5 -#define TELNETSRV_HISFILE 6 -#define TELNETSRV_HISSIZE 7 -#define TELNETSRV_PHYBSIZE 8 -#define TELNETSRV_STATICMOD 9 -#define TELNETSRV_SHRMOD 10 + +#define TELNETSRV_OPTNAME_STATICMOD "staticmod" +#define TELNETSRV_OPTNAME_SHRMOD "shrmod" paramdef_t telnetoptions[] = { - /*--------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ - /* configuration parameters for telnet utility */ - /* optname helpstr paramflags XXXptr defXXXval type numelt */ - /*--------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ - {"listenaddr", "\n", 0, uptr:&telnetparams.listenaddr, defstrval:"0.0.0.0", TYPE_IPV4ADDR, 0 }, - {"listenport", "\n", 0, uptr:&(telnetparams.listenport), defuintval:9090, TYPE_UINT, 0 }, - {"priority", "\n", 0, uptr:NULL, defuintval:0, TYPE_UINT, 0 }, - {"loopcount", "\n", 0, uptr:&(telnetparams.loopcount), defuintval:10, TYPE_UINT, 0 }, - {"loopdelay", "\n", 0, uptr:&(telnetparams.loopdelay), defuintval:5000, TYPE_UINT, 0 }, - {"histfile", "\n", PARAMFLAG_NOFREE, strptr:&(telnetparams.histfile), defstrval:"oaitelnet.history", TYPE_STRING, 0 }, - {"histsize", "\n", 0, iptr:&(telnetparams.histsize), defuintval:50, TYPE_INT, 0 }, - {"phypbsize", "\n",0, uptr:&(telnetparams.phyprntbuff_size),defuintval:65000, TYPE_UINT, 0 }, - {"staticmod", "\n", 0, strlistptr:NULL, defstrlistval:telnet_defstatmod,TYPE_STRINGLIST,(sizeof(telnet_defstatmod)/sizeof(char *))}, - {"shrmod", "\n", 0, strlistptr:NULL, defstrlistval:NULL,TYPE_STRINGLIST,0 } + /*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ + /* configuration parameters for telnet utility */ + /* optname helpstr paramflags XXXptr defXXXval type numelt */ + /*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ + {"listenaddr", "\n", 0, uptr:&telnetparams.listenaddr, defstrval:"0.0.0.0", TYPE_IPV4ADDR, 0 }, + {"listenport", "\n", 0, uptr:&(telnetparams.listenport), defuintval:9090, TYPE_UINT, 0 }, + {"listenstdin", "enable input from stdin\n", PARAMFLAG_BOOL, uptr:&(telnetparams.listenstdin), defuintval:0, TYPE_UINT, 0 }, + {"priority", "\n", 0, uptr:NULL, defuintval:0, TYPE_UINT, 0 }, + {"loopcount", "\n", 0, uptr:&(telnetparams.loopcount), defuintval:10, TYPE_UINT, 0 }, + {"loopdelay", "\n", 0, uptr:&(telnetparams.loopdelay), defuintval:5000, TYPE_UINT, 0 }, + {"histfile", "\n", PARAMFLAG_NOFREE, strptr:&(telnetparams.histfile), defstrval:"oaitelnet.history", TYPE_STRING, 0 }, + {"histsize", "\n", 0, iptr:&(telnetparams.histsize), defuintval:50, TYPE_INT, 0 }, + {"phypbsize", "\n",0, uptr:&(telnetparams.phyprntbuff_size),defuintval:65000, TYPE_UINT, 0 }, + {TELNETSRV_OPTNAME_STATICMOD, "\n", 0, strlistptr:NULL, defstrlistval:telnet_defstatmod,TYPE_STRINGLIST,(sizeof(telnet_defstatmod)/sizeof(char *))}, + {TELNETSRV_OPTNAME_SHRMOD, "\n", 0, strlistptr:NULL, defstrlistval:NULL,TYPE_STRINGLIST,0 } }; int get_phybsize(void) { @@ -682,6 +676,77 @@ void run_telnetsrv(void) { return; } +void run_telnetclt(void) { + int sock; + struct sockaddr_in name; + pthread_setname_np(pthread_self(), "telnetclt"); + set_sched(pthread_self(),0,telnetparams.priority); + char prompt[sizeof(TELNET_PROMPT_PREFIX)+10]; + sprintf(prompt,"%s_%s> ",TELNET_PROMPT_PREFIX,get_softmodem_function(NULL)); + name.sin_family = AF_INET; + struct in_addr addr; + inet_aton("127.0.0.1", &addr) ; + name.sin_addr.s_addr = addr.s_addr; + name.sin_port = htons((unsigned short)(telnetparams.listenport)); + while (1) { + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) + fprintf(stderr,"[TELNETSRV] Error %s on socket call\n",strerror(errno)); + + if(connect(sock, (void *) &name, sizeof(name))) + fprintf(stderr,"[TELNETSRV] Error %s on connect call\n",strerror(errno)); + + struct timeval ts; + ts.tv_sec = 1; // 1 second + ts.tv_usec = 0; + while (1) { + fd_set fds; + FD_ZERO(&fds); + FD_SET(sock, &fds); + FD_SET(STDIN_FILENO , &fds); + // wait for data + int nready = select(sock + 1, &fds, (fd_set *) 0, (fd_set *) 0, &ts); + if (nready < 0) { + perror("select. Error"); + break; + } + else if (nready == 0) { + ts.tv_sec = 1; // 1 second + ts.tv_usec = 0; + } + else if ( FD_ISSET(sock, &fds)) { + int rv; + char inbuf[TELNET_MAX_MSGLENGTH*2]; + memset(inbuf,0,sizeof(inbuf)); + rv = recv(sock , inbuf , sizeof(inbuf)-1 , 0); + if (rv > 0) { + printf("%s",inbuf); + } + else if (rv == 0) { + printf("Connection closed by the remote end\n\r"); + break; + } + else { + perror("recv error"); + break; + } + } + else if (FD_ISSET(STDIN_FILENO , &fds)) { + char *inbuf=NULL; + size_t inlen=0; + inlen = getline( &inbuf,&inlen, stdin); + if ( inlen > 0 ) { + if ( send(sock, inbuf,inlen, 0) < 0) + break; + } + free(inbuf); + } + } + close(sock); + } + return; +} /* run_telnetclt */ + void poll_telnetcmdq(void *qid, void *arg) { notifiedFIFO_elt_t *msg = pollNotifiedFIFO((notifiedFIFO_t *)qid); @@ -720,10 +785,10 @@ void exec_moduleinit(char *modname) { int add_embeddedmodules(void) { int ret=0; - - for(int i=0; i +#include +#include +#include +#include +#include +#include + + + + +#define TELNETSERVERCODE +#include "telnetsrv.h" + +#include "common/utils/LOG/log.h" +#include "common/config/config_userapi.h" +#include "telnetsrv_measurements.h" +#include "telnetsrv_ltemeasur_def.h" +#include "telnetsrv_cpumeasur_def.h" +#include "openair2/LAYER2/NR_MAC_UE/mac_defs.h" +#include "openair1/PHY/phy_extern_nr_ue.h" + +void measurcmd_display_macstats(telnet_printfunc_t prnt); +void measurcmd_display_macstats_ue(telnet_printfunc_t prnt); +void measurcmd_display_rlcstats(telnet_printfunc_t prnt); +void measurcmd_display_phycpu(telnet_printfunc_t prnt); +void measurcmd_display_maccpu(telnet_printfunc_t prnt); +void measurcmd_display_pdcpcpu(telnet_printfunc_t prnt); + + +static telnet_measurgroupdef_t nrUEmeasurgroups[] = { +// {"ue", GROUP_LTESTATS,0, measurcmd_display_macstats, {NULL}}, +// {"rlc", GROUP_LTESTATS,0, measurcmd_display_rlcstats, {NULL}}, + {"phycpu",GROUP_CPUSTATS,0, measurcmd_display_phycpu, {NULL}}, +// {"maccpu",GROUP_CPUSTATS,0, measurcmd_display_maccpu, {NULL}}, +// {"pdcpcpu",GROUP_CPUSTATS,0, measurcmd_display_pdcpcpu, {NULL}}, +}; +#define TELNET_NUM_NRUEMEASURGROUPS (sizeof(nrUEmeasurgroups)/sizeof(telnet_measurgroupdef_t)) + + +static double cpufreq; + + +#define HDR "---------------------------------" + + +int get_measurgroups(telnet_measurgroupdef_t **measurgroups) { + *measurgroups = nrUEmeasurgroups; + return TELNET_NUM_NRUEMEASURGROUPS; +} + + +void measurcmd_display_phycpu(telnet_printfunc_t prnt) { + PHY_VARS_NR_UE *UE = PHY_vars_UE_g[0][0]; + telnet_cpumeasurdef_t cpumeasur[]=CPU_PHYNRUE_MEASURE; + prnt("%s cpu (%1.1g GHz) measurements: PHY (cpustats %s) %s\n",HDR,cpufreq, + PRINT_CPUMEAS_STATE,HDR); + measurcmd_display_cpumeasures(prnt, cpumeasur, sizeof(cpumeasur)/sizeof(telnet_cpumeasurdef_t)); +} +/* +void measurcmd_display_maccpu(telnet_printfunc_t prnt) { + eNB_MAC_INST *macvars = RC.mac[eNB_id]; + telnet_cpumeasurdef_t cpumeasur[]=CPU_MACENB_MEASURE; + prnt("%s cpu (%1.1g GHz) measurements: MAC (cpustats %s) %s\n",HDR,cpufreq, + PRINT_CPUMEAS_STATE,HDR); + measurcmd_display_cpumeasures(prnt, cpumeasur, sizeof(cpumeasur)/sizeof(telnet_cpumeasurdef_t)); +} + +void measurcmd_display_pdcpcpu(telnet_printfunc_t prnt) { + pdcp_stats_t *pdcpvars = &(eNB_pdcp_stats[eNB_id]); + telnet_cpumeasurdef_t cpumeasur[]=CPU_PDCPENB_MEASURE; + prnt("%s cpu (%1.1g GHz) measurements: PDCP (cpustats %s) %s \n",HDR,cpufreq, + PRINT_CPUMEAS_STATE,HDR); + measurcmd_display_cpumeasures(prnt, cpumeasur, sizeof(cpumeasur)/sizeof(telnet_cpumeasurdef_t)); +} +//---------------------------------------------------------------------------------------------------- + + +void measurcmd_display_macstats_ue(telnet_printfunc_t prnt) { + UE_info_t *UE_info = &(RC.mac[eNB_id]->UE_info); + + for (int UE_id=UE_info->list.head; UE_id>=0; UE_id=UE_info->list.next[UE_id]) { + for (int i=0; inumactiveCCs[UE_id]; i++) { + int CC_id = UE_info->ordered_CCids[i][UE_id]; + prnt("%s UE %i Id %i CCid %i %s\n",HDR,i,UE_id,CC_id,HDR); + eNB_UE_STATS *macuestatptr = &(UE_info->eNB_UE_stats[CC_id][UE_id]); + telnet_ltemeasurdef_t statsptr[]=LTEMAC_UEMEASURE; + measurcmd_display_measures(prnt, statsptr, sizeof(statsptr)/sizeof(telnet_ltemeasurdef_t)); + } + } +} // measurcmd_display_macstats_ue + +void measurcmd_display_macstats(telnet_printfunc_t prnt) { + for (int CC_id=0 ; CC_id < MAX_NUM_CCs; CC_id++) { + eNB_STATS *macstatptr=&(RC.mac[eNB_id]->eNB_stats[CC_id]); + telnet_ltemeasurdef_t statsptr[]=LTEMAC_MEASURE; + prnt("%s eNB %i mac stats CC %i frame %u %s\n", + HDR, eNB_id, CC_id, RC.mac[eNB_id]->frame,HDR); + measurcmd_display_measures(prnt,statsptr,sizeof(statsptr)/sizeof(telnet_ltemeasurdef_t)); + } +} // measurcmd_display_macstats + + +void measurcmd_display_one_rlcstat(telnet_printfunc_t prnt, int UE_id, telnet_ltemeasurdef_t *statsptr, int num_rlcmeasure, unsigned int *rlcstats, + char *rbid_str, protocol_ctxt_t *ctxt, const srb_flag_t srb_flagP, const rb_id_t rb_idP) + +{ + int rlc_status = rlc_stat_req(ctxt,srb_flagP,rb_idP, + rlcstats, rlcstats+1, rlcstats+2, rlcstats+3, rlcstats+4, rlcstats+5, + rlcstats+6, rlcstats+7, rlcstats+8, rlcstats+9, rlcstats+10, rlcstats+11, + rlcstats+12, rlcstats+13, rlcstats+14, rlcstats+15, rlcstats+16, rlcstats+17, + rlcstats+18, rlcstats+19, rlcstats+20, rlcstats+21, rlcstats+22, rlcstats+23, + rlcstats+24, rlcstats+25, rlcstats+26, rlcstats+27); + + if (rlc_status == RLC_OP_STATUS_OK) { + prnt("%s UE %i RLC %s mode %s %s\n",HDR,UE_id, rbid_str, + (rlcstats[0]==RLC_MODE_AM)? "AM": (rlcstats[0]==RLC_MODE_UM)?"UM":"NONE",HDR); + measurcmd_display_measures(prnt, statsptr, num_rlcmeasure); + } +} // status measurcmd_rlc_stat_req + + +void measurcmd_display_rlcstats(telnet_printfunc_t prnt) { + protocol_ctxt_t ctxt; + UE_info_t *UE_info = &(RC.mac[eNB_id]->UE_info); + telnet_ltemeasurdef_t statsptr[]=LTE_RLCMEASURE; + int num_rlcmeasure = sizeof(statsptr)/sizeof(telnet_ltemeasurdef_t ); + unsigned int *rlcstats = malloc(num_rlcmeasure*sizeof(unsigned int)); + eNB_MAC_INST *eNB = RC.mac[eNB_id]; + + for(int i=0; i list.head; UE_id>=0; UE_id=UE_info->list.next[UE_id]) { +#define NB_eNB_INST 1 + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt,eNB_id, ENB_FLAG_YES,UE_info->eNB_UE_stats[0][UE_id].crnti, + eNB->frame,eNB->subframe,eNB_id); + measurcmd_display_one_rlcstat(prnt, UE_id, statsptr, num_rlcmeasure, rlcstats, "DCCH", &ctxt, SRB_FLAG_YES, DCCH); + measurcmd_display_one_rlcstat(prnt, UE_id, statsptr, num_rlcmeasure, rlcstats, "DTCH", &ctxt, SRB_FLAG_NO, DTCH-2); + } +} // measurcmd_display_macstats_ue + +*/ + + diff --git a/common/utils/telnetsrv/telnetsrv_CMakeLists.txt b/common/utils/telnetsrv/telnetsrv_CMakeLists.txt index 519a1a72ff..2713c71cc0 100644 --- a/common/utils/telnetsrv/telnetsrv_CMakeLists.txt +++ b/common/utils/telnetsrv/telnetsrv_CMakeLists.txt @@ -8,9 +8,9 @@ set(TELNETSRV_SOURCE ) add_library(telnetsrv MODULE ${TELNETSRV_SOURCE} ) -target_link_libraries(telnetsrv PRIVATE history) +target_link_libraries(telnetsrv PRIVATE history ncurses form ) -foreach(TELNETLIB enb gnb 4gUE 5gUE) +foreach(TELNETLIB enb gnb 4Gue 5Gue) set(TELNETLIB_SRCS "") foreach(TELNETLIB_ASRC measurements phycmd) set(TELNETLIB_SRC ${OPENAIR_DIR}/common/utils/telnetsrv/telnetsrv_${TELNETLIB}_${TELNETLIB_ASRC}.c) @@ -32,4 +32,4 @@ install(TARGETS telnetsrv DESTINATION bin) if (EXISTS "${OPENAIR_BUILD_DIR}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_BUILD_DIR}/ran_build/build") install(TARGETS telnetsrv DESTINATION ${OPENAIR_BUILD_DIR}/ran_build/build) -endif (EXISTS "${OPENAIR_BUILD_DIR}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_BUILD_DIR}/ran_build/build") \ No newline at end of file +endif (EXISTS "${OPENAIR_BUILD_DIR}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_BUILD_DIR}/ran_build/build") diff --git a/common/utils/telnetsrv/telnetsrv_cpumeasur_def.h b/common/utils/telnetsrv/telnetsrv_cpumeasur_def.h index 7a45b351f3..a275272e80 100644 --- a/common/utils/telnetsrv/telnetsrv_cpumeasur_def.h +++ b/common/utils/telnetsrv/telnetsrv_cpumeasur_def.h @@ -24,8 +24,8 @@ * \ strucures arrays which are then used by the display functions * \ in telnetsrv_measurements.c. * \author Francois TABURET - * \date 2019 - * \version 0.1 + * \date 2021 + * \version 0.2 * \company NOKIA BellLabs France * \email: francois.taburet@nokia-bell-labs.com * \note @@ -37,67 +37,119 @@ #define CPU_PHYENB_MEASURE \ { \ - {"phy_proc_tx", &(phyvars->phy_proc_tx),0},\ - {"phy_proc_rx", &(phyvars->phy_proc_rx),0},\ - {"rx_prach", &(phyvars->rx_prach),0},\ - {"ofdm_mod", &(phyvars->ofdm_mod_stats),0},\ - {"dlsch_common_and_dci", &(phyvars->dlsch_common_and_dci),0},\ - {"dlsch_ue_specific", &(phyvars->dlsch_ue_specific),0},\ - {"dlsch_encoding", &(phyvars->dlsch_encoding_stats),0},\ - {"dlsch_modulation", &(phyvars->dlsch_modulation_stats),0},\ - {"dlsch_scrambling", &(phyvars->dlsch_scrambling_stats),0},\ - {"dlsch_rate_matching", &(phyvars->dlsch_rate_matching_stats),0},\ - {"dlsch_turbo_encod_prep", &(phyvars->dlsch_turbo_encoding_preperation_stats),0},\ - {"dlsch_turbo_encod_segm", &(phyvars->dlsch_turbo_encoding_segmentation_stats),0},\ - {"dlsch_turbo_encod", &(phyvars->dlsch_turbo_encoding_stats),0},\ - {"dlsch_turbo_encod_waiting", &(phyvars->dlsch_turbo_encoding_waiting_stats),0},\ - {"dlsch_turbo_encod_signal", &(phyvars->dlsch_turbo_encoding_signal_stats),0},\ - {"dlsch_turbo_encod_main", &(phyvars->dlsch_turbo_encoding_main_stats),0},\ - {"dlsch_turbo_encod_wakeup0", &(phyvars->dlsch_turbo_encoding_wakeup_stats0),0},\ - {"dlsch_turbo_encod_wakeup1", &(phyvars->dlsch_turbo_encoding_wakeup_stats1),0},\ - {"dlsch_interleaving", &(phyvars->dlsch_interleaving_stats),0},\ - {"rx_dft", &(phyvars->rx_dft_stats),0},\ - {"ulsch_channel_estimation", &(phyvars->ulsch_channel_estimation_stats),0},\ - {"ulsch_freq_offset_estimation", &(phyvars->ulsch_freq_offset_estimation_stats),0},\ - {"ulsch_decoding", &(phyvars->ulsch_decoding_stats),0},\ - {"ulsch_demodulation", &(phyvars->ulsch_demodulation_stats),0},\ - {"ulsch_rate_unmatching", &(phyvars->ulsch_rate_unmatching_stats),0},\ - {"ulsch_turbo_decoding", &(phyvars->ulsch_turbo_decoding_stats),0},\ - {"ulsch_deinterleaving", &(phyvars->ulsch_deinterleaving_stats),0},\ - {"ulsch_demultiplexing", &(phyvars->ulsch_demultiplexing_stats),0},\ - {"ulsch_llr", &(phyvars->ulsch_llr_stats),0},\ - {"ulsch_tc_init", &(phyvars->ulsch_tc_init_stats),0},\ - {"ulsch_tc_alpha", &(phyvars->ulsch_tc_alpha_stats),0},\ - {"ulsch_tc_beta", &(phyvars->ulsch_tc_beta_stats),0},\ - {"ulsch_tc_gamma", &(phyvars->ulsch_tc_gamma_stats),0},\ - {"ulsch_tc_ext", &(phyvars->ulsch_tc_ext_stats),0},\ - {"ulsch_tc_intl1", &(phyvars->ulsch_tc_intl1_stats),0},\ - {"ulsch_tc_intl2", &(phyvars->ulsch_tc_intl2_stats),0},\ + {"phy_proc_tx", &(phyvars->phy_proc_tx),0,1},\ + {"phy_proc_rx", &(phyvars->phy_proc_rx),0,1},\ + {"rx_prach", &(phyvars->rx_prach),0,1},\ + {"ofdm_mod", &(phyvars->ofdm_mod_stats),0,1},\ + {"dlsch_common_and_dci", &(phyvars->dlsch_common_and_dci),0,1},\ + {"dlsch_ue_specific", &(phyvars->dlsch_ue_specific),0,1},\ + {"dlsch_encoding", &(phyvars->dlsch_encoding_stats),0,1},\ + {"dlsch_modulation", &(phyvars->dlsch_modulation_stats),0,1},\ + {"dlsch_scrambling", &(phyvars->dlsch_scrambling_stats),0,1},\ + {"dlsch_rate_matching", &(phyvars->dlsch_rate_matching_stats),0,1},\ + {"dlsch_turbo_encod_prep", &(phyvars->dlsch_turbo_encoding_preperation_stats),0,1},\ + {"dlsch_turbo_encod_segm", &(phyvars->dlsch_turbo_encoding_segmentation_stats),0,1},\ + {"dlsch_turbo_encod", &(phyvars->dlsch_turbo_encoding_stats),0,1},\ + {"dlsch_turbo_encod_waiting", &(phyvars->dlsch_turbo_encoding_waiting_stats),0,1},\ + {"dlsch_turbo_encod_signal", &(phyvars->dlsch_turbo_encoding_signal_stats),0,1},\ + {"dlsch_turbo_encod_main", &(phyvars->dlsch_turbo_encoding_main_stats),0,1},\ + {"dlsch_turbo_encod_wakeup0", &(phyvars->dlsch_turbo_encoding_wakeup_stats0),0,1},\ + {"dlsch_turbo_encod_wakeup1", &(phyvars->dlsch_turbo_encoding_wakeup_stats1),0,1},\ + {"dlsch_interleaving", &(phyvars->dlsch_interleaving_stats),0,1},\ + {"rx_dft", &(phyvars->rx_dft_stats),0,1},\ + {"ulsch_channel_estimation", &(phyvars->ulsch_channel_estimation_stats),0,1},\ + {"ulsch_freq_offset_estimation", &(phyvars->ulsch_freq_offset_estimation_stats),0,1},\ + {"ulsch_decoding", &(phyvars->ulsch_decoding_stats),0,1},\ + {"ulsch_demodulation", &(phyvars->ulsch_demodulation_stats),0,1},\ + {"ulsch_rate_unmatching", &(phyvars->ulsch_rate_unmatching_stats),0,1},\ + {"ulsch_turbo_decoding", &(phyvars->ulsch_turbo_decoding_stats),0,1},\ + {"ulsch_deinterleaving", &(phyvars->ulsch_deinterleaving_stats),0,1},\ + {"ulsch_demultiplexing", &(phyvars->ulsch_demultiplexing_stats),0,1},\ + {"ulsch_llr", &(phyvars->ulsch_llr_stats),0,1},\ + {"ulsch_tc_init", &(phyvars->ulsch_tc_init_stats),0,1},\ + {"ulsch_tc_alpha", &(phyvars->ulsch_tc_alpha_stats),0,1},\ + {"ulsch_tc_beta", &(phyvars->ulsch_tc_beta_stats),0,1},\ + {"ulsch_tc_gamma", &(phyvars->ulsch_tc_gamma_stats),0,1},\ + {"ulsch_tc_ext", &(phyvars->ulsch_tc_ext_stats),0,1},\ + {"ulsch_tc_intl1", &(phyvars->ulsch_tc_intl1_stats),0,1},\ + {"ulsch_tc_intl2", &(phyvars->ulsch_tc_intl2_stats),0,1},\ } #define CPU_MACENB_MEASURE \ { \ - {"eNB_scheduler", &(macvars->eNB_scheduler),0},\ - {"schedule_si", &(macvars->schedule_si),0},\ - {"schedule_ra", &(macvars->schedule_ra),0},\ - {"schedule_ulsch", &(macvars->schedule_ulsch),0},\ - {"fill_DLSCH_dci", &(macvars->fill_DLSCH_dci),0},\ - {"schedule_dlsch_pre", &(macvars->schedule_dlsch_preprocessor),0},\ - {"schedule_dlsch", &(macvars->schedule_dlsch),0},\ - {"schedule_mch", &(macvars->schedule_mch),0},\ - {"rx_ulsch_sdu", &(macvars->rx_ulsch_sdu),0},\ - {"schedule_pch", &(macvars->schedule_pch),0},\ + {"eNB_scheduler", &(macvars->eNB_scheduler),0,1},\ + {"schedule_si", &(macvars->schedule_si),0,1},\ + {"schedule_ra", &(macvars->schedule_ra),0,1},\ + {"schedule_ulsch", &(macvars->schedule_ulsch),0,1},\ + {"fill_DLSCH_dci", &(macvars->fill_DLSCH_dci),0,1},\ + {"schedule_dlsch_pre", &(macvars->schedule_dlsch_preprocessor),0,1},\ + {"schedule_dlsch", &(macvars->schedule_dlsch),0,1},\ + {"schedule_mch", &(macvars->schedule_mch),0,1},\ + {"rx_ulsch_sdu", &(macvars->rx_ulsch_sdu),0,1},\ + {"schedule_pch", &(macvars->schedule_pch),0,1},\ } #define CPU_PDCPENB_MEASURE \ { \ - {"pdcp_run", &(pdcpvars->pdcp_run),0},\ - {"data_req", &(pdcpvars->data_req),0},\ - {"data_ind", &(pdcpvars->data_ind),0},\ - {"apply_security", &(pdcpvars->apply_security),0},\ - {"validate_security", &(pdcpvars->validate_security),0},\ - {"pdcp_ip", &(pdcpvars->pdcp_ip),0},\ - {"ip_pdcp", &(pdcpvars->ip_pdcp),0},\ + {"pdcp_run", &(pdcpvars->pdcp_run),0,1},\ + {"data_req", &(pdcpvars->data_req),0,1},\ + {"data_ind", &(pdcpvars->data_ind),0,1},\ + {"apply_security", &(pdcpvars->apply_security),0,1},\ + {"validate_security", &(pdcpvars->validate_security),0,1},\ + {"pdcp_ip", &(pdcpvars->pdcp_ip),0,1},\ + {"ip_pdcp", &(pdcpvars->ip_pdcp),0,1},\ } +/* from openair1/PHY/defs_nr_UE.h */ +#define CPU_PHYNRUE_MEASURE \ +{ \ + {"phy_proc", &(UE->phy_proc[0]),0,RX_NB_TH},\ + {"phy_proc_rx", &(UE-> phy_proc_rx[0]),0,RX_NB_TH},\ + {"phy_proc_tx", &(UE->phy_proc_tx),0,1},\ + {"ofdm_mod_stats", &(UE->ofdm_mod_stats),0,1},\ + {"ulsch_encoding_stats", &(UE->ulsch_encoding_stats),0,1},\ + {"ulsch_modulation_stats", &(UE->ulsch_modulation_stats),0,1},\ + {"ulsch_segmentation_stats", &(UE->ulsch_segmentation_stats),0,1},\ + {"ulsch_rate_matching_stats", &(UE->ulsch_rate_matching_stats),0,1},\ + {"ulsch_turbo_encoding_stats", &(UE->ulsch_turbo_encoding_stats),0,1},\ + {"ulsch_interleaving_stats", &(UE->ulsch_interleaving_stats),0,1},\ + {"ulsch_multiplexing_stats", &(UE->ulsch_multiplexing_stats),0,1},\ + {"generic_stat", &(UE->generic_stat),0,1},\ + {"generic_stat_bis", &(UE->generic_stat_bis[0][0]),0,RX_NB_TH,LTE_SLOTS_PER_SUBFRAME},\ + {"ofdm_demod_stats", &(UE->ofdm_demod_stats),0,1},\ + {"dlsch_rx_pdcch_stats", &(UE->dlsch_rx_pdcch_stats),0,1},\ + {"rx_dft_stats", &(UE->rx_dft_stats),0,1},\ + {"dlsch_c...timation_stats", &(UE->dlsch_channel_estimation_stats),0,1},\ + {"dlsch_f...timation_stats", &(UE->dlsch_freq_offset_estimation_stats),0,1},\ + {"dlsch_demodulation_stats", &(UE->dlsch_demodulation_stats),0,1},\ + {"dlsch_rate_unmatching_stats", &(UE->dlsch_rate_unmatching_stats),0,1},\ + {"dlsch_turbo_decoding_stats", &(UE->dlsch_turbo_decoding_stats),0,1},\ + {"dlsch_deinterleaving_stats", &(UE->dlsch_deinterleaving_stats),0,1},\ + {"dlsch_llr_stats", &(UE->dlsch_llr_stats),0,1},\ + {"dlsch_unscrambling_stats", &(UE->dlsch_unscrambling_stats),0,1},\ + {"dlsch_rate_matching_stats", &(UE->dlsch_rate_matching_stats),0,1},\ + {"dlsch_turbo_encoding_stats", &(UE->dlsch_turbo_encoding_stats),0,1},\ + {"dlsch_interleaving_stats", &(UE->dlsch_interleaving_stats),0,1},\ + {"dlsch_tc_init_stats", &(UE->dlsch_tc_init_stats),0,1},\ + {"dlsch_tc_alpha_stats", &(UE->dlsch_tc_alpha_stats),0,1},\ + {"dlsch_tc_beta_stats", &(UE->dlsch_tc_beta_stats),0,1},\ + {"dlsch_tc_gamma_stats", &(UE->dlsch_tc_gamma_stats),0,1},\ + {"dlsch_tc_ext_stats", &(UE->dlsch_tc_ext_stats),0,1},\ + {"dlsch_tc_intl1_stats", &(UE->dlsch_tc_intl1_stats),0,1},\ + {"dlsch_tc_intl2_stats", &(UE->dlsch_tc_intl2_stats),0,1},\ + {"tx_prach", &(UE->tx_prach),0,1},\ + {"dlsch_encoding_SIC_stats", &(UE->dlsch_encoding_SIC_stats),0,1},\ + {"dlsch_scrambling_SIC_stats", &(UE->dlsch_scrambling_SIC_stats),0,1},\ + {"dlsch_modulation_SIC_stats", &(UE->dlsch_modulation_SIC_stats),0,1},\ + {"dlsch...ping_unit_SIC_stats", &(UE->dlsch_llr_stripping_unit_SIC_stats),0,1},\ + {"dlsch_unscrambling_SIC_stats", &(UE->dlsch_unscrambling_SIC_stats),0,1},\ + {"ue_front_end_stat", &(UE->ue_front_end_stat[0]),0,RX_NB_TH},\ + {"ue_front_end_per_slot_stat", &(UE->ue_front_end_per_slot_stat[0][0]),0,RX_NB_TH,LTE_SLOTS_PER_SUBFRAME},\ + {"pdcch_procedures_stat", &(UE->pdcch_procedures_stat[0]),0,RX_NB_TH},\ + {"pdsch_procedures_stat", &(UE->pdsch_procedures_stat[0]),0,RX_NB_TH},\ + {"pdsch_procedures_per_slot_stat", &(UE->pdsch_procedures_per_slot_stat[0][0]),0,RX_NB_TH,LTE_SLOTS_PER_SUBFRAME},\ + {"dlsch_procedures_stat", &(UE->dlsch_procedures_stat[0]),0,RX_NB_TH},\ + {"dlsch_decoding_stats", &(UE->dlsch_decoding_stats[0]),0,RX_NB_TH},\ + {"dlsch_llr_stats_para", &(UE->dlsch_llr_stats_parallelization[0][0]),0,RX_NB_TH,LTE_SLOTS_PER_SUBFRAME},\ +} #endif diff --git a/common/utils/telnetsrv/telnetsrv_measurements.c b/common/utils/telnetsrv/telnetsrv_measurements.c index 4a11e7c2dd..786cbd094c 100644 --- a/common/utils/telnetsrv/telnetsrv_measurements.c +++ b/common/utils/telnetsrv/telnetsrv_measurements.c @@ -64,13 +64,30 @@ void measurcmd_display_groups(telnet_printfunc_t prnt,telnet_measurgroupdef_t *m } /* measurcmd_display_groups */ /*----------------------------------------------------------------------------------------------------*/ /* cpu measurements functions */ -void measurcmd_display_cpumeasures(telnet_printfunc_t prnt, telnet_cpumeasurdef_t *cpumeasure, int cpumeasure_size) { - for (int i=0; istatname, - ((cpumeasure+i)->astatptr->trials!=0)?(((cpumeasure+i)->astatptr->diff)/((cpumeasure+i)->astatptr->trials))/cpufreq/1000:0, - (cpumeasure+i)->astatptr->trials, ((i%2)==1)?"|\n":" | " ); - } + +static char *stridx(int max,int i, char *buff) { + if (max>1) + sprintf(buff,"[%d]",i); + else + sprintf(buff," "); + return buff; + +} +void measurcmd_display_cpumeasures(telnet_printfunc_t prnt, telnet_cpumeasurdef_t *cpumeasure, int cpumeasure_size) { + int p=0; + char stridx1[16]; + char stridx2[16]; + for (int i=0; istatname, + stridx(cpumeasure[i].num_occur1,o1,stridx1),stridx(cpumeasure[i].num_occur2,o2,stridx2), + ((cpumeasure+i+o1+o2)->astatptr->trials!=0)?(((cpumeasure+i+o1+o2)->astatptr->diff)/((cpumeasure+i+o1+o2)->astatptr->trials))/cpufreq/1000:0, + (cpumeasure+i+o1+o2)->astatptr->trials, ((p%2)==1)?"|\n":" | " ); + p++; + } prnt("\n\n"); } /* measurcmd_display_measures */ @@ -137,11 +154,17 @@ int measurcmd_show(char *buf, int debug, telnet_printfunc_t prnt) { } telnet_measurgroupdef_t *measurgroups; int num_measurgroups = fptr( &measurgroups); - + int s = sscanf(buf,"%ms %i-%i\n",&subcmd, &idx1,&idx2); if (s>0) { - if ( strcmp(subcmd,"groups") == 0) { + if ( strcmp(subcmd,"inq") == 0) { + notifiedFIFO_elt_t *msg =newNotifiedFIFO_elt(sizeof(time_stats_msg_t),0,NULL,NULL); + time_stats_msg_t *msgdata=NotifiedFifoData(msg); + msgdata->msgid = TIMESTAT_MSGID_DISPLAY; + msgdata->displayFunc = prnt; + pushNotifiedFIFO(&measur_fifo, msg); + } else if ( strcmp(subcmd,"groups") == 0){ measurcmd_display_groups(prnt,measurgroups,num_measurgroups); badcmd=0; } else { @@ -182,13 +205,13 @@ int measurcmd_cpustats(char *buf, int debug, telnet_printfunc_t prnt) { int badcmd=1; if (debug > 0) - prnt(" measurcmd_show received %s\n",buf); + prnt(" measurcmd_cpustats received %s\n",buf); int s = sscanf(buf,"%ms %i-%i\n",&subcmd, &idx1,&idx2); if (s>0) { if ( strcmp(subcmd,"enable") == 0) { - cpumeas(CPUMEAS_ENABLE); + badcmd=0; } else if ( strcmp(subcmd,"disable") == 0) { cpumeas(CPUMEAS_DISABLE); @@ -203,6 +226,64 @@ int measurcmd_cpustats(char *buf, int debug, telnet_printfunc_t prnt) { free(subcmd); return CMDSTATUS_FOUND; } + +void measurcmd_async_help(telnet_printfunc_t prnt) { +} + +int measurcmd_async(char *buf, int debug, telnet_printfunc_t prnt) { + char *subcmd=NULL; + int idx1, idx2; + int okcmd=0; + + if (buf == NULL) { + measurcmd_async_help(prnt); + return CMDSTATUS_FOUND; + } + if (debug > 0) + prnt(" measurcmd_async received %s\n",buf); + + + int s = sscanf(buf,"%ms %i-%i\n",&subcmd, &idx1,&idx2); + + if (s==1) { + if ( strcmp(subcmd,"enable") == 0) { + init_meas(); + okcmd=1; + } else if ( strcmp(subcmd,"disable") == 0) { + end_meas(); + okcmd=1; + } + } else if ( s == 3 ) { + int msgid; + if ( strcmp(subcmd,"enable") == 0) { + msgid = TIMESTAT_MSGID_ENABLE; + okcmd=1; + } else if ( strcmp(subcmd,"disable") == 0) { + msgid = TIMESTAT_MSGID_DISABLE; + okcmd=1; + } else if ( strcmp(subcmd,"display") == 0) { + msgid = TIMESTAT_MSGID_DISPLAY; + okcmd=1; + } + if (okcmd) { + notifiedFIFO_elt_t *nfe = newNotifiedFIFO_elt(sizeof(time_stats_msg_t),0,NULL,NULL); + time_stats_msg_t *msg = (time_stats_msg_t *)NotifiedFifoData(nfe); + msg->msgid = msgid ; + msg->displayFunc = prnt; + for(int i=idx1; itimestat_id =i; + pushNotifiedFIFO(&measur_fifo, nfe); + } + } + } + + if (!(okcmd)) { + prnt("Unknown command: %s\n",buf); + } + + free(subcmd); + return CMDSTATUS_FOUND; +} /*-------------------------------------------------------------------------------------*/ /* function called at telnet server init to add the measur command */ diff --git a/common/utils/telnetsrv/telnetsrv_measurements.h b/common/utils/telnetsrv/telnetsrv_measurements.h index 08136df0fd..99ae695f41 100644 --- a/common/utils/telnetsrv/telnetsrv_measurements.h +++ b/common/utils/telnetsrv/telnetsrv_measurements.h @@ -49,6 +49,9 @@ typedef struct cpumeasurdef { char statname[TELNET_MAXMEASURNAME_LEN]; time_stats_t *astatptr; unsigned int statemask; + uint8_t num_occur1; + uint8_t num_occur2; + uint8_t num_occur3; } telnet_cpumeasurdef_t; typedef struct ltemeasurdef { @@ -60,6 +63,7 @@ typedef struct ltemeasurdef { #define GROUP_LTESTATS 0 #define GROUP_CPUSTATS 1 + typedef void(*measur_dislayfunc_t)(telnet_printfunc_t prnt); typedef struct mesurgroupdef { char groupname[TELNET_MAXMEASURNAME_LEN]; @@ -79,9 +83,11 @@ typedef struct mesurgroupdef { #ifdef TELNETSRV_MEASURMENTS_MAIN int measurcmd_show(char *buf, int debug, telnet_printfunc_t prnt); int measurcmd_cpustats(char *buf, int debug, telnet_printfunc_t prnt); +int measurcmd_async(char *buf, int debug, telnet_printfunc_t prnt); telnetshell_cmddef_t measur_cmdarray[] = { - {"show", "groups | " , measurcmd_show}, + {"show", "groups | | inq" , measurcmd_show}, {"cpustats","[enable | disable]",measurcmd_cpustats}, + {"async","[enable | disable]",measurcmd_async}, {"","",NULL} }; diff --git a/doc/BUILD.md b/doc/BUILD.md index 166563877e..40b63ac697 100644 --- a/doc/BUILD.md +++ b/doc/BUILD.md @@ -88,6 +88,21 @@ You can build any oai softmodem executable separately, you may not need all of t After completing the build, the binaries are available in the `cmake_targets/ran_build/build` directory. A copy is also available in the `target/bin` directory, with all binaries suffixed by the 3GPP release number, today .Rel15. +When installing the pre-requisites, especially the `UHD` driver, you can now specify if you want to install from source or not. + +- For `fedora`-based OS, it was already the case all the time. But now you can specify which version to install. +- For `ubuntu` OS, the Ettus PPA currently installs the following versions: + * `Ubuntu16.04`: --> version `3.15.0.0` + * `Ubuntu18.04`: --> version `4.1.0.0` + +```bash +export BUILD_UHD_FROM_SOURCE=True +export UHD_VERSION=3.15.0.0 +./build_oai -I -w USRP +``` + +The `UHD_VERSION` env variable `SHALL` be a valid tag (minus `v`) from the `https://github.com/EttusResearch/uhd.git` repository. + ## Issue when building `nasmeh` module ## A lot of users and contributors have faced the issue: `nasmesh` module does not build. diff --git a/doc/RUNMODEM.md b/doc/RUNMODEM.md index dc7a982310..d063afd5d9 100644 --- a/doc/RUNMODEM.md +++ b/doc/RUNMODEM.md @@ -203,10 +203,7 @@ UE on machine 2: - - - - +[Selecting an alternative ldpc implementation at run time](../openair1/PHY/CODING/DOC/LDPCImplementation.md) [oai wiki home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home) diff --git a/doc/testing_gnb_w_cots_ue_resources/gnb.conf b/doc/testing_gnb_w_cots_ue_resources/gnb.conf index c4a8d512b8..97935f92ee 100755 --- a/doc/testing_gnb_w_cots_ue_resources/gnb.conf +++ b/doc/testing_gnb_w_cots_ue_resources/gnb.conf @@ -275,6 +275,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/docker/Dockerfile.eNB.rhel8.2 b/docker/Dockerfile.eNB.rhel8.2 index 90c807fc0e..0522271df0 100644 --- a/docker/Dockerfile.eNB.rhel8.2 +++ b/docker/Dockerfile.eNB.rhel8.2 @@ -41,17 +41,23 @@ RUN python3 ./docker/scripts/generateTemplate.py ./docker/scripts/enb_parameters #start from scratch for target executable FROM registry.access.redhat.com/ubi8/ubi:latest as oai-enb +ENV TZ=Europe/Paris RUN yum update -y && \ yum install -y --enablerepo="ubi-8-codeready-builder" \ lksctp-tools \ nettle \ + tzdata \ procps-ng \ atlas \ + python3 \ + python3-pip \ net-tools \ iputils \ iproute \ libyaml && \ + pip3 install six && \ + pip3 install requests && \ echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf && \ echo "/usr/local/lib64" >> /etc/ld.so.conf.d/local-lib.conf @@ -78,6 +84,8 @@ COPY --from=enb-build /lib64/libconfig.so.9 /lib64 COPY --from=enb-build /lib64/libblas.so.3 /lib64 COPY --from=enb-build /lib64/liblapack.so.3 /lib64 COPY --from=enb-build /lib64/liblapacke.so.3 /lib64 + +# Now we are copying from builder-image the UHD files. COPY --from=enb-build /lib64/libboost_chrono.so.1.66.0 /lib64 COPY --from=enb-build /lib64/libboost_date_time.so.1.66.0 /lib64 COPY --from=enb-build /lib64/libboost_filesystem.so.1.66.0 /lib64 @@ -88,7 +96,14 @@ COPY --from=enb-build /lib64/libboost_system.so.1.66.0 /lib64 COPY --from=enb-build /lib64/libboost_unit_test_framework.so.1.66.0 /lib64 COPY --from=enb-build /lib64/libboost_atomic.so.1.66.0 /lib64 COPY --from=enb-build /lib64/libboost_timer.so.1.66.0 /lib64 -COPY --from=enb-build /usr/local/lib64/libuhd.so.4.0.0 /usr/local/lib64 +COPY --from=enb-build /lib64/libboost_regex.so.1.66.0 /lib64 + +COPY --from=enb-build /usr/local/bin/uhd_find_devices /usr/local/bin +COPY --from=enb-build /usr/local/lib64/libuhd.so.3.15.0 /usr/local/lib64 +COPY --from=enb-build /usr/local/lib64/uhd/utils/uhd_images_downloader.py /opt/oai-enb/bin + +WORKDIR /usr/local/share/uhd/rfnoc +COPY --from=enb-build /usr/local/share/uhd/rfnoc/ . RUN ldconfig diff --git a/docker/Dockerfile.eNB.ubuntu18 b/docker/Dockerfile.eNB.ubuntu18 index c4393dc78e..cf748784e5 100644 --- a/docker/Dockerfile.eNB.ubuntu18 +++ b/docker/Dockerfile.eNB.ubuntu18 @@ -25,7 +25,7 @@ # #--------------------------------------------------------------------- -FROM ran-build:latest AS enb-build +FROM ran-build:latest AS enb-build RUN rm -Rf /oai-ran WORKDIR /oai-ran @@ -42,8 +42,7 @@ RUN python3 ./docker/scripts/generateTemplate.py ./docker/scripts/enb_parameters #start from scratch for target executable FROM ubuntu:bionic as oai-enb ENV DEBIAN_FRONTEND=noninteractive -ENV TZ=Europe -RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone +ENV TZ=Europe/Paris RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ @@ -60,16 +59,12 @@ RUN apt-get update && \ iputils-ping \ iproute2 \ iperf \ - libyaml-0-2 && \ - # Install UHD driver from ettus ppa - # At time of writing, it is 3.14 - add-apt-repository ppa:ettusresearch/uhd --yes && \ - apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ python \ + python3 \ + python3-six \ + python3-requests \ libusb-1.0-0 \ - libuhd003 \ - uhd-host && \ + libyaml-0-2 && \ rm -rf /var/lib/apt/lists/* WORKDIR /opt/oai-enb/bin @@ -90,6 +85,17 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so.Rel15 /usr/local/lib/ RUN /bin/bash -c "ln -s /usr/local/lib/librfsimulator.so.Rel15 /usr/local/lib/librfsimulator.so" COPY --from=enb-build /usr/local/lib/libprotobuf-c.so.1 . +# Now we are copying from builder-image the UHD files. +COPY --from=enb-build /usr/local/bin/uhd_find_devices /usr/local/bin +COPY --from=enb-build /usr/local/lib/libuhd.so.3.15.0 /usr/local/lib +COPY --from=enb-build /usr/local/lib/uhd/utils/uhd_images_downloader.py /opt/oai-enb/bin +WORKDIR /usr/lib/x86_64-linux-gnu +COPY --from=enb-build /usr/lib/x86_64-linux-gnu/libboost_date_time.so.1.65.1 . +COPY --from=enb-build /usr/lib/x86_64-linux-gnu/libboost_filesystem.so.1.65.1 . +COPY --from=enb-build /usr/lib/x86_64-linux-gnu/libboost_regex.so.1.65.1 . +COPY --from=enb-build /usr/lib/x86_64-linux-gnu/libboost_serialization.so.1.65.1 . +COPY --from=enb-build /usr/lib/x86_64-linux-gnu/libboost_thread.so.1.65.1 . +COPY --from=enb-build /usr/lib/x86_64-linux-gnu/libboost_system.so.1.65.1 . RUN ldconfig diff --git a/docker/Dockerfile.gNB.rhel8.2 b/docker/Dockerfile.gNB.rhel8.2 index 9ee0bf9ae9..b34a9d242d 100644 --- a/docker/Dockerfile.gNB.rhel8.2 +++ b/docker/Dockerfile.gNB.rhel8.2 @@ -41,6 +41,7 @@ RUN python3 ./docker/scripts/generateTemplate.py ./docker/scripts/gnb_parameters #start from scratch for target executable FROM registry.access.redhat.com/ubi8/ubi:latest as oai-gnb +ENV TZ=Europe/Paris RUN yum repolist --disablerepo=* && \ yum update -y && \ @@ -51,9 +52,14 @@ RUN yum repolist --disablerepo=* && \ atlas \ lksctp-tools \ nettle \ + tzdata \ + python3 \ + python3-pip \ net-tools \ iputils \ libyaml && \ + pip3 install six && \ + pip3 install requests && \ echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf && \ echo "/usr/local/lib64" >> /etc/ld.so.conf.d/local-lib.conf @@ -84,6 +90,8 @@ COPY --from=gnb-build /lib64/libforms.so.2 /lib64 COPY --from=gnb-build /lib64/libblas.so.3 /lib64 COPY --from=gnb-build /lib64/liblapack.so.3 /lib64 COPY --from=gnb-build /lib64/liblapacke.so.3 /lib64 + +# Now we are copying from builder-image the UHD files. COPY --from=gnb-build /lib64/libboost_chrono.so.1.66.0 /lib64 COPY --from=gnb-build /lib64/libboost_date_time.so.1.66.0 /lib64 COPY --from=gnb-build /lib64/libboost_filesystem.so.1.66.0 /lib64 @@ -94,7 +102,14 @@ COPY --from=gnb-build /lib64/libboost_system.so.1.66.0 /lib64 COPY --from=gnb-build /lib64/libboost_unit_test_framework.so.1.66.0 /lib64 COPY --from=gnb-build /lib64/libboost_atomic.so.1.66.0 /lib64 COPY --from=gnb-build /lib64/libboost_timer.so.1.66.0 /lib64 -COPY --from=gnb-build /usr/local/lib64/libuhd.so.4.0.0 /usr/local/lib64 +COPY --from=gnb-build /lib64/libboost_regex.so.1.66.0 /lib64 + +COPY --from=gnb-build /usr/local/bin/uhd_find_devices /usr/local/bin +COPY --from=gnb-build /usr/local/lib64/libuhd.so.3.15.0 /usr/local/lib64 +COPY --from=gnb-build /usr/local/lib64/uhd/utils/uhd_images_downloader.py /opt/oai-gnb/bin + +WORKDIR /usr/local/share/uhd/rfnoc +COPY --from=gnb-build /usr/local/share/uhd/rfnoc/ . RUN ldconfig diff --git a/docker/Dockerfile.gNB.ubuntu18 b/docker/Dockerfile.gNB.ubuntu18 index 990c4363e5..cfd9d82144 100644 --- a/docker/Dockerfile.gNB.ubuntu18 +++ b/docker/Dockerfile.gNB.ubuntu18 @@ -59,16 +59,12 @@ RUN apt-get update && \ net-tools \ iproute2 \ iputils-ping \ - libyaml-0-2 && \ - # Install UHD driver from ettus ppa - # At time of writing, it is 3.14 - add-apt-repository ppa:ettusresearch/uhd --yes && \ - apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ python \ + python3 \ + python3-six \ + python3-requests \ libusb-1.0-0 \ - libuhd003 \ - uhd-host && \ + libyaml-0-2 && \ rm -rf /var/lib/apt/lists/* WORKDIR /opt/oai-gnb/bin @@ -93,6 +89,18 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so.Rel15 /usr/local/lib/ RUN /bin/bash -c "ln -s /usr/local/lib/librfsimulator.so.Rel15 /usr/local/lib/librfsimulator.so" COPY --from=gnb-build /usr/local/lib/libprotobuf-c.so.1 . +# Now we are copying from builder-image the UHD files. +COPY --from=gnb-build /usr/local/bin/uhd_find_devices /usr/local/bin +COPY --from=gnb-build /usr/local/lib/libuhd.so.3.15.0 /usr/local/lib +COPY --from=gnb-build /usr/local/lib/uhd/utils/uhd_images_downloader.py /opt/oai-gnb/bin +WORKDIR /usr/lib/x86_64-linux-gnu +COPY --from=gnb-build /usr/lib/x86_64-linux-gnu/libboost_date_time.so.1.65.1 . +COPY --from=gnb-build /usr/lib/x86_64-linux-gnu/libboost_filesystem.so.1.65.1 . +COPY --from=gnb-build /usr/lib/x86_64-linux-gnu/libboost_regex.so.1.65.1 . +COPY --from=gnb-build /usr/lib/x86_64-linux-gnu/libboost_serialization.so.1.65.1 . +COPY --from=gnb-build /usr/lib/x86_64-linux-gnu/libboost_thread.so.1.65.1 . +COPY --from=gnb-build /usr/lib/x86_64-linux-gnu/libboost_system.so.1.65.1 . + RUN ldconfig # Copy the relevant configuration files for gNB diff --git a/docker/Dockerfile.lteRU.rhel8.2 b/docker/Dockerfile.lteRU.rhel8.2 index 314c01dff3..7e2a054a12 100644 --- a/docker/Dockerfile.lteRU.rhel8.2 +++ b/docker/Dockerfile.lteRU.rhel8.2 @@ -48,9 +48,13 @@ RUN yum update -y && \ tzdata \ procps-ng \ atlas \ + python3 \ + python3-pip \ net-tools \ iputils \ iproute && \ + pip3 install six && \ + pip3 install requests && \ echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf && \ echo "/usr/local/lib64" >> /etc/ld.so.conf.d/local-lib.conf @@ -66,11 +70,12 @@ COPY --from=ru-build /oai-ran/targets/bin/liboai_usrpdevif.so.Rel15 . COPY --from=ru-build /oai-ran/targets/bin/libparams_libconfig.so . COPY --from=ru-build /oai-ran/cmake_targets/ran_build/build/libdfts.so . -# Copying from the ran-build image the USRP needed packages COPY --from=ru-build /lib64/libconfig.so.9 /lib64 COPY --from=ru-build /lib64/libblas.so.3 /lib64 COPY --from=ru-build /lib64/liblapack.so.3 /lib64 COPY --from=ru-build /lib64/liblapacke.so.3 /lib64 + +# Copying from the ran-build image the USRP needed packages COPY --from=ru-build /lib64/libboost_chrono.so.1.66.0 /lib64 COPY --from=ru-build /lib64/libboost_date_time.so.1.66.0 /lib64 COPY --from=ru-build /lib64/libboost_filesystem.so.1.66.0 /lib64 @@ -81,7 +86,14 @@ COPY --from=ru-build /lib64/libboost_system.so.1.66.0 /lib64 COPY --from=ru-build /lib64/libboost_unit_test_framework.so.1.66.0 /lib64 COPY --from=ru-build /lib64/libboost_atomic.so.1.66.0 /lib64 COPY --from=ru-build /lib64/libboost_timer.so.1.66.0 /lib64 -COPY --from=ru-build /usr/local/lib64/libuhd.so.4.0.0 /usr/local/lib64 +COPY --from=ru-build /lib64/libboost_regex.so.1.66.0 /lib64 + +COPY --from=ru-build /usr/local/bin/uhd_find_devices /usr/local/bin +COPY --from=ru-build /usr/local/lib64/libuhd.so.3.15.0 /usr/local/lib64 +COPY --from=ru-build /usr/local/lib64/uhd/utils/uhd_images_downloader.py /opt/oai-lte-ru/bin + +WORKDIR /usr/local/share/uhd/rfnoc +COPY --from=ru-build /usr/local/share/uhd/rfnoc/ . RUN /bin/bash -c "ln -s /usr/local/lib/liboai_eth_transpro.so.Rel15 /usr/local/lib/liboai_transpro.so" && \ /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so.Rel15 /usr/local/lib/liboai_device.so" && \ diff --git a/docker/Dockerfile.lteRU.ubuntu18 b/docker/Dockerfile.lteRU.ubuntu18 index fa99827d94..eafb8fa8af 100644 --- a/docker/Dockerfile.lteRU.ubuntu18 +++ b/docker/Dockerfile.lteRU.ubuntu18 @@ -54,17 +54,13 @@ RUN apt-get update && \ libatlas3-base \ libconfig9 \ net-tools \ + python \ + python3 \ + python3-six \ + python3-requests \ + libusb-1.0-0 \ iputils-ping \ iproute2 && \ - # Install UHD driver from ettus ppa - # At time of writing, it is 3.14 - add-apt-repository ppa:ettusresearch/uhd --yes && \ - apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ - python \ - libusb-1.0-0 \ - libuhd003 \ - uhd-host && \ rm -rf /var/lib/apt/lists/* WORKDIR /opt/oai-lte-ru/bin @@ -78,6 +74,19 @@ COPY --from=ru-build /oai-ran/targets/bin/librfsimulator.so.Rel15 . COPY --from=ru-build /oai-ran/targets/bin/liboai_usrpdevif.so.Rel15 . COPY --from=ru-build /oai-ran/targets/bin/libparams_libconfig.so . COPY --from=ru-build /oai-ran/cmake_targets/ran_build/build/libdfts.so . + +# Now we are copying from builder-image the UHD files. +COPY --from=ru-build /usr/local/bin/uhd_find_devices /usr/local/bin +COPY --from=ru-build /usr/local/lib/libuhd.so.3.15.0 /usr/local/lib +COPY --from=ru-build /usr/local/lib/uhd/utils/uhd_images_downloader.py /opt/oai-lte-ru/bin +WORKDIR /usr/lib/x86_64-linux-gnu +COPY --from=ru-build /usr/lib/x86_64-linux-gnu/libboost_date_time.so.1.65.1 . +COPY --from=ru-build /usr/lib/x86_64-linux-gnu/libboost_filesystem.so.1.65.1 . +COPY --from=ru-build /usr/lib/x86_64-linux-gnu/libboost_regex.so.1.65.1 . +COPY --from=ru-build /usr/lib/x86_64-linux-gnu/libboost_serialization.so.1.65.1 . +COPY --from=ru-build /usr/lib/x86_64-linux-gnu/libboost_thread.so.1.65.1 . +COPY --from=ru-build /usr/lib/x86_64-linux-gnu/libboost_system.so.1.65.1 . + RUN /bin/bash -c "ln -s /usr/local/lib/liboai_eth_transpro.so.Rel15 /usr/local/lib/liboai_transpro.so" && \ /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so.Rel15 /usr/local/lib/liboai_device.so" && \ /bin/bash -c "ln -s /usr/local/lib/librfsimulator.so.Rel15 /usr/local/lib/librfsimulator.so" && \ diff --git a/docker/Dockerfile.lteUE.rhel8.2 b/docker/Dockerfile.lteUE.rhel8.2 index 936780297a..a6814be136 100644 --- a/docker/Dockerfile.lteUE.rhel8.2 +++ b/docker/Dockerfile.lteUE.rhel8.2 @@ -42,17 +42,23 @@ RUN python3 ./docker/scripts/generateTemplate.py ./docker/scripts/lte_ue_paramet #start from scratch for target executable FROM registry.access.redhat.com/ubi8/ubi:latest as oai-lte-ue +ENV TZ=Europe/Paris RUN yum update -y && \ yum install -y --enablerepo="ubi-8-codeready-builder" \ lksctp-tools \ procps-ng \ nettle \ + tzdata \ atlas \ + python3 \ + python3-pip \ iproute \ net-tools \ iputils \ libyaml && \ + pip3 install six && \ + pip3 install requests && \ echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf && \ echo "/usr/local/lib64" >> /etc/ld.so.conf.d/local-lib.conf @@ -82,6 +88,8 @@ COPY --from=lte-ue-build /lib64/libconfig.so.9 /lib64 COPY --from=lte-ue-build /lib64/libblas.so.3 /lib64 COPY --from=lte-ue-build /lib64/liblapack.so.3 /lib64 COPY --from=lte-ue-build /lib64/liblapacke.so.3 /lib64 + +# Now we are copying from builder-image the UHD files. COPY --from=lte-ue-build /lib64/libboost_chrono.so.1.66.0 /lib64 COPY --from=lte-ue-build /lib64/libboost_date_time.so.1.66.0 /lib64 COPY --from=lte-ue-build /lib64/libboost_filesystem.so.1.66.0 /lib64 @@ -92,7 +100,14 @@ COPY --from=lte-ue-build /lib64/libboost_system.so.1.66.0 /lib64 COPY --from=lte-ue-build /lib64/libboost_unit_test_framework.so.1.66.0 /lib64 COPY --from=lte-ue-build /lib64/libboost_atomic.so.1.66.0 /lib64 COPY --from=lte-ue-build /lib64/libboost_timer.so.1.66.0 /lib64 -COPY --from=lte-ue-build /usr/local/lib64/libuhd.so.4.0.0 /usr/local/lib64 +COPY --from=lte-ue-build /lib64/libboost_regex.so.1.66.0 /lib64 + +COPY --from=lte-ue-build /usr/local/bin/uhd_find_devices /usr/local/bin +COPY --from=lte-ue-build /usr/local/lib64/libuhd.so.3.15.0 /usr/local/lib64 +COPY --from=lte-ue-build /usr/local/lib64/uhd/utils/uhd_images_downloader.py /opt/oai-lte-ue/bin + +WORKDIR /usr/local/share/uhd/rfnoc +COPY --from=lte-ue-build /usr/local/share/uhd/rfnoc/ . RUN ldconfig diff --git a/docker/Dockerfile.lteUE.ubuntu18 b/docker/Dockerfile.lteUE.ubuntu18 index 34cbe651ad..6d54ab08fc 100644 --- a/docker/Dockerfile.lteUE.ubuntu18 +++ b/docker/Dockerfile.lteUE.ubuntu18 @@ -43,8 +43,7 @@ RUN python3 ./docker/scripts/generateTemplate.py ./docker/scripts/lte_ue_paramet #start from scratch for target executable FROM ubuntu:bionic as oai-lte-ue ENV DEBIAN_FRONTEND=noninteractive -ENV TZ=Europe -RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone +ENV TZ=Europe/Paris RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ @@ -58,19 +57,15 @@ RUN apt-get update && \ libconfig9 \ openssl \ net-tools \ + python \ + python3 \ + python3-six \ + python3-requests \ + libusb-1.0-0 \ iputils-ping \ iproute2 \ iperf \ libyaml-0-2 && \ - # Install UHD driver from ettus ppa - # At time of writing, it is 3.14 - add-apt-repository ppa:ettusresearch/uhd --yes && \ - apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ - python \ - libusb-1.0-0 \ - libuhd003 \ - uhd-host && \ rm -rf /var/lib/apt/lists/* WORKDIR /opt/oai-lte-ue/bin @@ -95,6 +90,18 @@ RUN /bin/bash -c "ln -s /usr/local/lib/librfsimulator.so.Rel15 /usr/local/lib/li COPY --from=lte-ue-build /usr/local/lib/libprotobuf-c.so.1 . +# Now we are copying from builder-image the UHD files. +COPY --from=lte-ue-build /usr/local/bin/uhd_find_devices /usr/local/bin +COPY --from=lte-ue-build /usr/local/lib/libuhd.so.3.15.0 /usr/local/lib +COPY --from=lte-ue-build /usr/local/lib/uhd/utils/uhd_images_downloader.py /opt/oai-lte-ue/bin +WORKDIR /usr/lib/x86_64-linux-gnu +COPY --from=lte-ue-build /usr/lib/x86_64-linux-gnu/libboost_date_time.so.1.65.1 . +COPY --from=lte-ue-build /usr/lib/x86_64-linux-gnu/libboost_filesystem.so.1.65.1 . +COPY --from=lte-ue-build /usr/lib/x86_64-linux-gnu/libboost_regex.so.1.65.1 . +COPY --from=lte-ue-build /usr/lib/x86_64-linux-gnu/libboost_serialization.so.1.65.1 . +COPY --from=lte-ue-build /usr/lib/x86_64-linux-gnu/libboost_thread.so.1.65.1 . +COPY --from=lte-ue-build /usr/lib/x86_64-linux-gnu/libboost_system.so.1.65.1 . + RUN ldconfig # Copy the relevant configuration files for UE diff --git a/docker/Dockerfile.nrUE.rhel8.2 b/docker/Dockerfile.nrUE.rhel8.2 index 56fc746ade..ec74d11940 100644 --- a/docker/Dockerfile.nrUE.rhel8.2 +++ b/docker/Dockerfile.nrUE.rhel8.2 @@ -51,9 +51,13 @@ RUN yum update -y && \ iputils \ iproute \ atlas \ + python3 \ + python3-pip \ libXpm \ libX11 \ libyaml && \ + pip3 install six && \ + pip3 install requests && \ echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf && \ echo "/usr/local/lib64" >> /etc/ld.so.conf.d/local-lib.conf @@ -87,6 +91,8 @@ COPY --from=nr-ue-build /lib64/libblas.so.3 /lib64 COPY --from=nr-ue-build /lib64/liblapack.so.3 /lib64 COPY --from=nr-ue-build /lib64/liblapacke.so.3 /lib64 COPY --from=nr-ue-build /lib64/libforms.so.2 /lib64 + +# Now we are copying from builder-image the UHD files. COPY --from=nr-ue-build /lib64/libboost_chrono.so.1.66.0 /lib64 COPY --from=nr-ue-build /lib64/libboost_date_time.so.1.66.0 /lib64 COPY --from=nr-ue-build /lib64/libboost_filesystem.so.1.66.0 /lib64 @@ -97,7 +103,15 @@ COPY --from=nr-ue-build /lib64/libboost_system.so.1.66.0 /lib64 COPY --from=nr-ue-build /lib64/libboost_unit_test_framework.so.1.66.0 /lib64 COPY --from=nr-ue-build /lib64/libboost_atomic.so.1.66.0 /lib64 COPY --from=nr-ue-build /lib64/libboost_timer.so.1.66.0 /lib64 -COPY --from=nr-ue-build /usr/local/lib64/libuhd.so.4.0.0 /usr/local/lib64 +COPY --from=nr-ue-build /lib64/libboost_regex.so.1.66.0 /lib64 + +COPY --from=nr-ue-build /usr/local/bin/uhd_find_devices /usr/local/bin +COPY --from=nr-ue-build /usr/local/lib64/libuhd.so.3.15.0 /usr/local/lib64 +COPY --from=nr-ue-build /usr/local/lib64/uhd/utils/uhd_images_downloader.py /opt/oai-nr-ue/bin + +WORKDIR /usr/local/share/uhd/rfnoc +COPY --from=nr-ue-build /usr/local/share/uhd/rfnoc/ . + RUN ldconfig diff --git a/docker/Dockerfile.nrUE.ubuntu18 b/docker/Dockerfile.nrUE.ubuntu18 index fc30af7286..49e3f3213b 100644 --- a/docker/Dockerfile.nrUE.ubuntu18 +++ b/docker/Dockerfile.nrUE.ubuntu18 @@ -55,19 +55,15 @@ RUN apt-get update && \ libconfig9 \ openssl \ net-tools \ + python \ + python3 \ + python3-six \ + python3-requests \ + libusb-1.0-0 \ iputils-ping \ iproute2 \ iperf \ libyaml-0-2 && \ - # Install UHD driver from ettus ppa - # At time of writing, it is 3.14 - add-apt-repository ppa:ettusresearch/uhd --yes && \ - apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ - python \ - libusb-1.0-0 \ - libuhd003 \ - uhd-host && \ rm -rf /var/lib/apt/lists/* WORKDIR /opt/oai-nr-ue/bin @@ -95,6 +91,18 @@ RUN /bin/bash -c "ln -s /usr/local/lib/librfsimulator.so.Rel15 /usr/local/lib/li COPY --from=nr-ue-build /usr/local/lib/libprotobuf-c.so.1 . +# Now we are copying from builder-image the UHD files. +COPY --from=nr-ue-build /usr/local/bin/uhd_find_devices /usr/local/bin +COPY --from=nr-ue-build /usr/local/lib/libuhd.so.3.15.0 /usr/local/lib +COPY --from=nr-ue-build /usr/local/lib/uhd/utils/uhd_images_downloader.py /opt/oai-nr-ue/bin +WORKDIR /usr/lib/x86_64-linux-gnu +COPY --from=nr-ue-build /usr/lib/x86_64-linux-gnu/libboost_date_time.so.1.65.1 . +COPY --from=nr-ue-build /usr/lib/x86_64-linux-gnu/libboost_filesystem.so.1.65.1 . +COPY --from=nr-ue-build /usr/lib/x86_64-linux-gnu/libboost_regex.so.1.65.1 . +COPY --from=nr-ue-build /usr/lib/x86_64-linux-gnu/libboost_serialization.so.1.65.1 . +COPY --from=nr-ue-build /usr/lib/x86_64-linux-gnu/libboost_thread.so.1.65.1 . +COPY --from=nr-ue-build /usr/lib/x86_64-linux-gnu/libboost_system.so.1.65.1 . + RUN ldconfig WORKDIR /opt/oai-nr-ue diff --git a/docker/Dockerfile.ran.rhel8.2 b/docker/Dockerfile.ran.rhel8.2 index 3972fd0c35..4d15220ca8 100644 --- a/docker/Dockerfile.ran.rhel8.2 +++ b/docker/Dockerfile.ran.rhel8.2 @@ -28,6 +28,9 @@ FROM registry.access.redhat.com/ubi8/ubi:latest AS ran-build ARG NEEDED_GIT_PROXY +ENV TZ=Europe/Paris +ENV BUILD_UHD_FROM_SOURCE=True +ENV UHD_VERSION=3.15.0.0 COPY tmp/ca/redhat-uep.pem /etc/rhsm/ca COPY tmp/entitlement/*.pem /etc/pki/entitlement diff --git a/docker/Dockerfile.ran.ubuntu18 b/docker/Dockerfile.ran.ubuntu18 index 4b296408fd..3ef81ec030 100644 --- a/docker/Dockerfile.ran.ubuntu18 +++ b/docker/Dockerfile.ran.ubuntu18 @@ -29,8 +29,9 @@ FROM ubuntu:bionic AS ran-build ARG NEEDED_GIT_PROXY ENV DEBIAN_FRONTEND=noninteractive -ENV TZ=Europe -RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone +ENV TZ=Europe/Paris +ENV BUILD_UHD_FROM_SOURCE=True +ENV UHD_VERSION=3.15.0.0 #install developers pkg/repo RUN apt-get update && \ diff --git a/docker/scripts/enb_entrypoint.sh b/docker/scripts/enb_entrypoint.sh index 2e8886e855..ff92e3c86f 100755 --- a/docker/scripts/enb_entrypoint.sh +++ b/docker/scripts/enb_entrypoint.sh @@ -46,11 +46,11 @@ done # Load the USRP binaries if [[ -v USE_B2XX ]]; then - /usr/lib/uhd/utils/uhd_images_downloader.py -t b2xx + $PREFIX/bin/uhd_images_downloader.py -t b2xx elif [[ -v USE_X3XX ]]; then - /usr/lib/uhd/utils/uhd_images_downloader.py -t x3xx + $PREFIX/bin/uhd_images_downloader.py -t x3xx elif [[ -v USE_N3XX ]]; then - /usr/lib/uhd/utils/uhd_images_downloader.py -t n3xx + $PREFIX/bin/uhd_images_downloader.py -t n3xx fi echo "==================================" diff --git a/docker/scripts/gnb_entrypoint.sh b/docker/scripts/gnb_entrypoint.sh index d59018b56f..36160b136b 100755 --- a/docker/scripts/gnb_entrypoint.sh +++ b/docker/scripts/gnb_entrypoint.sh @@ -39,11 +39,11 @@ done # Load the USRP binaries if [[ -v USE_B2XX ]]; then - /usr/lib/uhd/utils/uhd_images_downloader.py -t b2xx + $PREFIX/bin/uhd_images_downloader.py -t b2xx elif [[ -v USE_X3XX ]]; then - /usr/lib/uhd/utils/uhd_images_downloader.py -t x3xx + $PREFIX/bin/uhd_images_downloader.py -t x3xx elif [[ -v USE_N3XX ]]; then - /usr/lib/uhd/utils/uhd_images_downloader.py -t n3xx + $PREFIX/bin/uhd_images_downloader.py -t n3xx fi echo "==================================" diff --git a/docker/scripts/lte_ru_entrypoint.sh b/docker/scripts/lte_ru_entrypoint.sh index f466e25ec2..93122b0d02 100755 --- a/docker/scripts/lte_ru_entrypoint.sh +++ b/docker/scripts/lte_ru_entrypoint.sh @@ -35,11 +35,11 @@ done # Load the USRP binaries if [[ -v USE_B2XX ]]; then - /usr/lib/uhd/utils/uhd_images_downloader.py -t b2xx + $PREFIX/bin/uhd_images_downloader.py -t b2xx elif [[ -v USE_X3XX ]]; then - /usr/lib/uhd/utils/uhd_images_downloader.py -t x3xx + $PREFIX/bin/uhd_images_downloader.py -t x3xx elif [[ -v USE_N3XX ]]; then - /usr/lib/uhd/utils/uhd_images_downloader.py -t n3xx + $PREFIX/bin/uhd_images_downloader.py -t n3xx fi echo "==================================" diff --git a/docker/scripts/lte_ue_entrypoint.sh b/docker/scripts/lte_ue_entrypoint.sh index 235128f738..de7ae8b496 100755 --- a/docker/scripts/lte_ue_entrypoint.sh +++ b/docker/scripts/lte_ue_entrypoint.sh @@ -39,11 +39,11 @@ $PREFIX/bin/conf2uedata -c $PREFIX/etc/ue_usim.conf -o $PREFIX # Load the USRP binaries if [[ -v USE_B2XX ]]; then - /usr/lib/uhd/utils/uhd_images_downloader.py -t b2xx + $PREFIX/bin/uhd_images_downloader.py -t b2xx elif [[ -v USE_X3XX ]]; then - /usr/lib/uhd/utils/uhd_images_downloader.py -t x3xx + $PREFIX/bin/uhd_images_downloader.py -t x3xx elif [[ -v USE_N3XX ]]; then - /usr/lib/uhd/utils/uhd_images_downloader.py -t n3xx + $PREFIX/bin/uhd_images_downloader.py -t n3xx fi # in case we have conf file, append diff --git a/docker/scripts/nr_ue_entrypoint.sh b/docker/scripts/nr_ue_entrypoint.sh index 691258b8fa..91d25c9e1e 100755 --- a/docker/scripts/nr_ue_entrypoint.sh +++ b/docker/scripts/nr_ue_entrypoint.sh @@ -34,11 +34,11 @@ done # Load the USRP binaries if [[ -v USE_B2XX ]]; then - /usr/lib/uhd/utils/uhd_images_downloader.py -t b2xx + $PREFIX/bin/uhd_images_downloader.py -t b2xx elif [[ -v USE_X3XX ]]; then - /usr/lib/uhd/utils/uhd_images_downloader.py -t x3xx + $PREFIX/bin/uhd_images_downloader.py -t x3xx elif [[ -v USE_N3XX ]]; then - /usr/lib/uhd/utils/uhd_images_downloader.py -t n3xx + $PREFIX/bin/uhd_images_downloader.py -t n3xx fi # in case we have conf file, append diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index ce09531e78..95b983190e 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -49,6 +49,7 @@ #include "SCHED_NR/fapi_nr_l1.h" #include "PHY/NR_TRANSPORT/nr_transport_proto.h" #include "PHY/MODULATION/nr_modulation.h" +#include "PHY/NR_TRANSPORT/nr_dlsch.h" #undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all //#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all @@ -88,6 +89,7 @@ #include "executables/softmodem-common.h" #include #include +#include #include //#define DEBUG_THREADS 1 @@ -114,19 +116,36 @@ time_stats_t softmodem_stats_rx_sf; // total rx time void tx_func(void *param) { - processingData_L1_t *info = (processingData_L1_t *) param; + processingData_L1tx_t *info = (processingData_L1tx_t *) param; PHY_VARS_gNB *gNB = info->gNB; - int frame_tx = info->frame_tx; - int slot_tx = info->slot_tx; + int frame_tx = info->frame; + int slot_tx = info->slot; - phy_procedures_gNB_TX(gNB, frame_tx,slot_tx, 1); + phy_procedures_gNB_TX(info, + frame_tx, + slot_tx, + 1); + info->slot = -1; + //if ((frame_tx&127) == 0) dump_pdsch_stats(fd,gNB); - // start FH TX processing - notifiedFIFO_elt_t *res; + // If the later of the 2 L1 tx thread finishes first, + // we wait for the earlier one to finish and start the RU thread + // to avoid realtime issues with USRP + + // Start RU TX processing. + notifiedFIFO_elt_t *res; res = pullTpool(gNB->resp_RU_tx, gNB->threadPool); processingData_RU_t *syncMsg = (processingData_RU_t *)NotifiedFifoData(res); + LOG_D(PHY,"waiting for previous tx to finish, next slot %d,%d\n",syncMsg->next_slot,slot_tx); + while (syncMsg->next_slot != slot_tx) { + pushNotifiedFIFO(gNB->resp_RU_tx, res); + res = pullTpool(gNB->resp_RU_tx, gNB->threadPool); + syncMsg = (processingData_RU_t *)NotifiedFifoData(res); + } + LOG_D(PHY,"previous tx finished, next slot %d,%d\n",syncMsg->next_slot,slot_tx); syncMsg->frame_tx = frame_tx; syncMsg->slot_tx = slot_tx; + syncMsg->next_slot = get_next_downlink_slot(gNB, &gNB->gNB_config, frame_tx, slot_tx); syncMsg->timestamp_tx = info->timestamp_tx; syncMsg->ru = gNB->RU_list[0]; res->key = slot_tx; @@ -184,7 +203,7 @@ void rx_func(void *param) { int down_removed = 0; int pucch_removed = 0; for (int i = 0; i < rnti_to_remove_count; i++) { - LOG_W(PHY, "to remove rnti %d\n", rnti_to_remove[i]); + LOG_W(NR_PHY, "to remove rnti %d\n", rnti_to_remove[i]); void clean_gNB_ulsch(NR_gNB_ULSCH_t *ulsch); void clean_gNB_dlsch(NR_gNB_DLSCH_t *dlsch); int j; @@ -201,13 +220,6 @@ void rx_func(void *param) { } up_removed++; } - for (j = 0; j < NUMBER_OF_NR_DLSCH_MAX; j++) - if (gNB->dlsch[j][0]->rnti == rnti_to_remove[i]) { - gNB->dlsch[j][0]->rnti = 0; - gNB->dlsch[j][0]->harq_mask = 0; - //clean_gNB_dlsch(gNB->dlsch[j][0]); - down_removed++; - } for (j = 0; j < NUMBER_OF_NR_PUCCH_MAX; j++) if (gNB->pucch[j]->active > 0 && gNB->pucch[j]->pucch_pdu.rnti == rnti_to_remove[i]) { @@ -224,7 +236,7 @@ void rx_func(void *param) { gNB->prach_vars.list[j].frame = -1; #endif } - if (rnti_to_remove_count) LOG_W(PHY, "to remove rnti_to_remove_count=%d, up_removed=%d down_removed=%d pucch_removed=%d\n", rnti_to_remove_count, up_removed, down_removed, pucch_removed); + if (rnti_to_remove_count) LOG_W(NR_PHY, "to remove rnti_to_remove_count=%d, up_removed=%d down_removed=%d pucch_removed=%d\n", rnti_to_remove_count, up_removed, down_removed, pucch_removed); rnti_to_remove_count = 0; if (pthread_mutex_unlock(&rnti_to_remove_mutex)) exit(1); @@ -255,7 +267,6 @@ void rx_func(void *param) { LOG_D(PHY,"%s() Exit proc[rx:%d%d tx:%d%d]\n", __FUNCTION__, frame_rx, slot_rx, frame_tx, slot_tx); // Call the scheduler - start_meas(&gNB->ul_indication_stats); pthread_mutex_lock(&gNB->UL_INFO_mutex); gNB->UL_INFO.frame = frame_rx; @@ -266,16 +277,17 @@ void rx_func(void *param) { pthread_mutex_unlock(&gNB->UL_INFO_mutex); stop_meas(&gNB->ul_indication_stats); - notifiedFIFO_elt_t *res; - if (tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT) { + notifiedFIFO_elt_t *res; res = pullTpool(gNB->resp_L1_tx, gNB->threadPool); - processingData_L1_t *syncMsg = (processingData_L1_t *)NotifiedFifoData(res); + processingData_L1tx_t *syncMsg = (processingData_L1tx_t *)NotifiedFifoData(res); + while (syncMsg->slot != slot_tx) { + pushNotifiedFIFO(gNB->resp_L1_tx, res); + res = pullTpool(gNB->resp_L1_tx, gNB->threadPool); + syncMsg = (processingData_L1tx_t *)NotifiedFifoData(res); + } syncMsg->gNB = gNB; - syncMsg->frame_rx = frame_rx; - syncMsg->slot_rx = slot_rx; - syncMsg->frame_tx = frame_tx; - syncMsg->slot_tx = slot_tx; + AssertFatal(syncMsg->slot == slot_tx, "Thread message slot and logical slot number do not match\n"); syncMsg->timestamp_tx = info->timestamp_tx; res->key = slot_tx; pushTpool(gNB->threadPool, res); @@ -325,7 +337,6 @@ static void *process_stats_thread(void *param) { PHY_VARS_gNB *gNB = (PHY_VARS_gNB *)param; - reset_meas(&gNB->phy_proc_tx); reset_meas(&gNB->dlsch_encoding_stats); reset_meas(&gNB->phy_proc_rx); reset_meas(&gNB->ul_indication_stats); @@ -337,7 +348,8 @@ static void *process_stats_thread(void *param) { while(!oai_exit) { sleep(1); - print_meas(&gNB->phy_proc_tx, "L1 Tx processing", NULL, NULL); + print_meas(gNB->phy_proc_tx_0, "L1 Tx processing thread 0", NULL, NULL); + print_meas(gNB->phy_proc_tx_1, "L1 Tx processing thread 1", NULL, NULL); print_meas(&gNB->dlsch_encoding_stats, "DLSCH encoding", NULL, NULL); print_meas(&gNB->phy_proc_rx, "L1 Rx processing", NULL, NULL); print_meas(&gNB->ul_indication_stats, "UL Indication", NULL, NULL); @@ -356,6 +368,7 @@ void *nrL1_stats_thread(void *param) { fd=fopen("nrL1_stats.log","w"); AssertFatal(fd!=NULL,"Cannot open nrL1_stats.log\n"); dump_nr_I0_stats(fd,gNB); + dump_pdsch_stats(fd,gNB); dump_pusch_stats(fd,gNB); // nr_dump_uci_stats(fd,eNB,eNB->proc.L1_proc_tx.frame_tx); fclose(fd); @@ -390,14 +403,38 @@ void init_gNB_Tpool(int inst) { // L1 RX result FIFO gNB->resp_L1 = (notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t)); initNotifiedFIFO(gNB->resp_L1); + notifiedFIFO_elt_t *msg = newNotifiedFIFO_elt(sizeof(processingData_L1_t),0,gNB->resp_L1,rx_func); + pushNotifiedFIFO(gNB->resp_L1,msg); // to unblock the process in the beginning // L1 TX result FIFO gNB->resp_L1_tx = (notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t)); initNotifiedFIFO(gNB->resp_L1_tx); + // we create 2 threads for L1 tx processing + notifiedFIFO_elt_t *msgL1Tx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t),0,gNB->resp_L1_tx,tx_func); + processingData_L1tx_t *msgDataTx = (processingData_L1tx_t *)NotifiedFifoData(msgL1Tx); + init_DLSCH_struct(gNB, msgDataTx); + msgDataTx->slot = -1; + memset(msgDataTx->ssb, 0, 64*sizeof(NR_gNB_SSB_t)); + reset_meas(&msgDataTx->phy_proc_tx); + gNB->phy_proc_tx_0 = &msgDataTx->phy_proc_tx; + pushNotifiedFIFO(gNB->resp_L1_tx,msgL1Tx); // to unblock the process in the beginning + + msgL1Tx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t),0,gNB->resp_L1_tx,tx_func); + msgDataTx = (processingData_L1tx_t *)NotifiedFifoData(msgL1Tx); + init_DLSCH_struct(gNB, msgDataTx); + msgDataTx->slot = -1; + memset(msgDataTx->ssb, 0, 64*sizeof(NR_gNB_SSB_t)); + reset_meas(&msgDataTx->phy_proc_tx); + gNB->phy_proc_tx_1 = &msgDataTx->phy_proc_tx; + pushNotifiedFIFO(gNB->resp_L1_tx,msgL1Tx); // to unblock the process in the beginning // RU TX result FIFO gNB->resp_RU_tx = (notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t)); initNotifiedFIFO(gNB->resp_RU_tx); + notifiedFIFO_elt_t *msgRUTx = newNotifiedFIFO_elt(sizeof(processingData_RU_t),0,gNB->resp_RU_tx,ru_tx_func); + processingData_RU_t *msgData = (processingData_RU_t*)msgRUTx->msgData; + msgData->next_slot = sf_ahead*gNB->frame_parms.slots_per_subframe; // first Tx slot + pushNotifiedFIFO(gNB->resp_RU_tx,msgRUTx); // to unblock the process in the beginning // Stats measurement thread if(opp_enabled == 1) threadCreate(&proc->process_stats_thread, process_stats_thread,(void *)gNB, "time_meas", -1, OAI_PRIORITY_RT_LOW); diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 2de04f4e7f..336b7bec12 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -33,6 +33,7 @@ #include "common/utils/assertions.h" #include "common/utils/system.h" +#include "common/ran_context.h" #include "../../ARCH/COMMON/common_lib.h" #include "../../ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h" @@ -47,8 +48,6 @@ #include "PHY/INIT/phy_init.h" #include "SCHED_NR/sched_nr.h" -#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" - #include "common/utils/LOG/log.h" #include "common/utils/LOG/vcd_signal_dumper.h" @@ -301,15 +300,20 @@ void fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) { /* Input Fronthaul from south RCC/RAU */ // Synchronous if5 from south + +uint64_t ts_rx[20]; void fh_if5_south_in(RU_t *ru, int *frame, int *tti) { NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; RU_proc_t *proc = &ru->proc; recv_IF5(ru, &proc->timestamp_rx, *tti, IF5_RRH_GW_UL); - proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_subframe*10))&1023; - uint32_t idx_sf = proc->timestamp_rx / fp->samples_per_subframe; - proc->tti_rx = (idx_sf * fp->slots_per_subframe + (int)round((float)(proc->timestamp_rx % fp->samples_per_subframe) / fp->samples_per_slot0))%(fp->slots_per_frame); + if (proc->first_rx == 1) ru->ts_offset = proc->timestamp_rx; + proc->frame_rx = ((proc->timestamp_rx-ru->ts_offset) / (fp->samples_per_subframe*10))&1023; + proc->tti_rx = fp->get_slot_from_timestamp(proc->timestamp_rx-ru->ts_offset,fp); +//(idx_sf * fp->slots_per_subframe + (int)round((float)(proc->timestamp_rx % fp->samples_per_subframe) / fp->samples_per_slot0))%(fp->slots_per_frame); + ts_rx[*tti] = proc->timestamp_rx; + LOG_D(PHY,"IF5 %d.%d => RX %d.%d first_rx %d\n",*frame,*tti,proc->frame_rx,proc->tti_rx,proc->first_rx); if (proc->first_rx == 0) { if (proc->tti_rx != *tti) { @@ -318,7 +322,7 @@ void fh_if5_south_in(RU_t *ru, } if (proc->frame_rx != *frame) { - LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",proc->frame_rx,*frame); + LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->frame_rx %d frame %d proc->tti_rx %d tti %d)\n",proc->frame_rx,*frame,proc->tti_rx,*tti); exit_fun("Exiting"); } } else { @@ -610,6 +614,7 @@ void rx_rf(RU_t *ru,int *frame,int *slot) { openair0_timestamp ts,old_ts; AssertFatal(*slotslots_per_frame && *slot>=0, "slot %d is illegal (%d)\n",*slot,fp->slots_per_frame); + start_meas(&ru->rx_fhaul); for (i=0; inb_rx; i++) rxp[i] = (void *)&ru->common.rxdata[i][fp->get_samples_slot_timestamp(*slot,fp,0)]; @@ -653,11 +658,11 @@ void rx_rf(RU_t *ru,int *frame,int *slot) { proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_subframe*10))&1023; proc->tti_rx = fp->get_slot_from_timestamp(proc->timestamp_rx,fp); // synchronize first reception to frame 0 subframe 0 - LOG_D(PHY,"RU %d/%d TS %llu (off %d), frame %d, slot %d.%d / %d\n", + LOG_D(PHY,"RU %d/%d TS %llu , frame %d, slot %d.%d / %d\n", ru->idx, 0, - (unsigned long long int)proc->timestamp_rx, - (int)ru->ts_offset,proc->frame_rx,proc->tti_rx,proc->tti_tx,fp->slots_per_frame); + (unsigned long long int)(proc->timestamp_rx+ru->ts_offset), + proc->frame_rx,proc->tti_rx,proc->tti_tx,fp->slots_per_frame); // dump VCD output for first RU in list if (ru == RC.ru[0]) { @@ -683,12 +688,14 @@ void rx_rf(RU_t *ru,int *frame,int *slot) { } //printf("timestamp_rx %lu, frame %d(%d), subframe %d(%d)\n",ru->timestamp_rx,proc->frame_rx,frame,proc->tti_rx,subframe); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, (proc->timestamp_rx+ru->ts_offset)&0xffffffff ); if (rxs != samples_per_slot) { //exit_fun( "problem receiving samples" ); LOG_E(PHY, "problem receiving samples\n"); } + + stop_meas(&ru->rx_fhaul); } @@ -698,13 +705,13 @@ void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) { nfapi_nr_config_request_scf_t *cfg = &ru->config; void *txp[ru->nb_tx]; unsigned int txs; - int i,txsymb; + int i,txsymb=fp->symbols_per_slot; T(T_ENB_PHY_OUTPUT_SIGNAL, T_INT(0), T_INT(0), T_INT(frame), T_INT(slot), T_INT(0), T_BUFFER(&ru->common.txdata[0][fp->get_samples_slot_timestamp(slot,fp,0)], fp->samples_per_subframe * 4)); int slot_type = nr_slot_select(cfg,frame,slot%fp->slots_per_frame); int prevslot_type = nr_slot_select(cfg,frame,(slot+(fp->slots_per_frame-1))%fp->slots_per_frame); int nextslot_type = nr_slot_select(cfg,frame,(slot+1)%fp->slots_per_frame); - int sf_extension = 0; //sf_extension = ru->sf_extension; + int sf_extension = 0; int siglen=fp->get_samples_per_slot(slot,fp); int flags=1; @@ -730,9 +737,10 @@ void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) { flags = 3; // end of burst } - if (slot_type == NR_DOWNLINK_SLOT && prevslot_type == NR_UPLINK_SLOT) + if (slot_type == NR_DOWNLINK_SLOT && prevslot_type == NR_UPLINK_SLOT) { flags = 2; // start of burst - + sf_extension = ru->sf_extension; + } if (slot_type == NR_DOWNLINK_SLOT && nextslot_type == NR_UPLINK_SLOT) flags = 3; // end of burst } @@ -758,27 +766,28 @@ void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) { flags |= beam<<8; LOG_D(HW,"slot %d, beam %d\n",slot,ru->common.beam_id[0][slot*fp->symbols_per_slot]); } + if (proc->first_tx == 1) proc->first_tx = 0; VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_WRITE_FLAGS, flags ); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, frame ); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, slot ); for (i=0; inb_tx; i++) - txp[i] = (void *)&ru->common.txdata[i][fp->get_samples_slot_timestamp(slot,fp,0)-sf_extension]; - - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (timestamp-ru->openair0_cfg.tx_sample_advance)&0xffffffff ); + txp[i] = (void *)&ru->common.txdata[i][fp->get_samples_slot_timestamp(slot,fp,0)]-sf_extension*sizeof(int32_t); + + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (timestamp+ru->ts_offset-ru->openair0_cfg.tx_sample_advance)&0xffffffff ); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 ); - // prepare tx buffer pointers + // prepare tx buffer pointers txs = ru->rfdevice.trx_write_func(&ru->rfdevice, timestamp+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension, txp, siglen+sf_extension, ru->nb_tx, flags); - LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, slot %di, returned %d\n",ru->idx, - (long long unsigned int)timestamp,frame,proc->frame_tx_unwrap,slot, txs); + LOG_D(PHY,"[TXPATH] RU %d aa %d tx_rf, writing to TS %llu, %d.%d, unwrapped_frame %d, slot %d, flags %d, siglen+sf_extension %d, returned %d, E %f\n",ru->idx,i, + (long long unsigned int)(timestamp+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension),frame,slot,proc->frame_tx_unwrap,slot, flags, siglen+sf_extension, txs,10*log10((double)signal_energy(txp[0],siglen+sf_extension))); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 ); - //AssertFatal(txs == 0,"trx write function error %d\n", txs); + //AssertFatal(txs == 0,"trx write function error %d\n", txs); } } @@ -793,79 +802,86 @@ void fill_rf_config(RU_t *ru, char *rf_config_file) { if (mu == NR_MU_0) { switch(N_RB) { - case 270: - if (fp->threequarter_fs) { - cfg->sample_rate=92.16e6; - cfg->samples_per_frame = 921600; - cfg->tx_bw = 50e6; - cfg->rx_bw = 50e6; - } else { - cfg->sample_rate=61.44e6; - cfg->samples_per_frame = 614400; - cfg->tx_bw = 50e6; - cfg->rx_bw = 50e6; - } - - case 216: - if (fp->threequarter_fs) { - cfg->sample_rate=46.08e6; - cfg->samples_per_frame = 460800; - cfg->tx_bw = 40e6; - cfg->rx_bw = 40e6; - } else { - cfg->sample_rate=61.44e6; - cfg->samples_per_frame = 614400; - cfg->tx_bw = 40e6; - cfg->rx_bw = 40e6; - } - - break; - - case 106: - if (fp->threequarter_fs) { - cfg->sample_rate=23.04e6; - cfg->samples_per_frame = 230400; - cfg->tx_bw = 20e6; - cfg->rx_bw = 20e6; - } else { - cfg->sample_rate=30.72e6; - cfg->samples_per_frame = 307200; - cfg->tx_bw = 20e6; - cfg->rx_bw = 20e6; - } - - break; - - case 52: - if (fp->threequarter_fs) { - cfg->sample_rate=11.52e6; - cfg->samples_per_frame = 115200; - cfg->tx_bw = 10e6; - cfg->rx_bw = 10e6; - } else { - cfg->sample_rate=15.36e6; - cfg->samples_per_frame = 153600; - cfg->tx_bw = 10e6; - cfg->rx_bw = 10e6; - } - - case 25: - if (fp->threequarter_fs) { - cfg->sample_rate=5.76e6; - cfg->samples_per_frame = 57600; - cfg->tx_bw = 5e6; - cfg->rx_bw = 5e6; - } else { - cfg->sample_rate=7.68e6; - cfg->samples_per_frame = 76800; - cfg->tx_bw = 5e6; - cfg->rx_bw = 5e6; - } - - break; - - default: - AssertFatal(0==1,"N_RB %d not yet supported for numerology %d\n",N_RB,mu); + case 270: + if (fp->threequarter_fs) { + cfg->sample_rate=92.16e6; + cfg->samples_per_frame = 921600; + cfg->tx_bw = 50e6; + cfg->rx_bw = 50e6; + } else { + cfg->sample_rate=61.44e6; + cfg->samples_per_frame = 614400; + cfg->tx_bw = 50e6; + cfg->rx_bw = 50e6; + } + case 216: + if (fp->threequarter_fs) { + cfg->sample_rate=46.08e6; + cfg->samples_per_frame = 460800; + cfg->tx_bw = 40e6; + cfg->rx_bw = 40e6; + } + else { + cfg->sample_rate=61.44e6; + cfg->samples_per_frame = 614400; + cfg->tx_bw = 40e6; + cfg->rx_bw = 40e6; + } + break; + case 160: //30 MHz + case 133: //25 MHz + if (fp->threequarter_fs) { + AssertFatal(1==0,"N_RB %d cannot use 3/4 sampling\n",N_RB); + } + else { + cfg->sample_rate=30.72e6; + cfg->samples_per_frame = 307200; + cfg->tx_bw = 20e6; + cfg->rx_bw = 20e6; + } + case 106: + if (fp->threequarter_fs) { + cfg->sample_rate=23.04e6; + cfg->samples_per_frame = 230400; + cfg->tx_bw = 20e6; + cfg->rx_bw = 20e6; + } + else { + cfg->sample_rate=30.72e6; + cfg->samples_per_frame = 307200; + cfg->tx_bw = 20e6; + cfg->rx_bw = 20e6; + } + break; + case 52: + if (fp->threequarter_fs) { + cfg->sample_rate=11.52e6; + cfg->samples_per_frame = 115200; + cfg->tx_bw = 10e6; + cfg->rx_bw = 10e6; + } + else { + cfg->sample_rate=15.36e6; + cfg->samples_per_frame = 153600; + cfg->tx_bw = 10e6; + cfg->rx_bw = 10e6; + } + case 25: + if (fp->threequarter_fs) { + cfg->sample_rate=5.76e6; + cfg->samples_per_frame = 57600; + cfg->tx_bw = 5e6; + cfg->rx_bw = 5e6; + } + else { + cfg->sample_rate=7.68e6; + cfg->samples_per_frame = 76800; + cfg->tx_bw = 5e6; + cfg->rx_bw = 5e6; + } + break; + default: + AssertFatal(0==1,"N_RB %d not yet supported for numerology %d\n",N_RB,mu); } } else if (mu == NR_MU_1) { switch(N_RB) { @@ -896,6 +912,19 @@ void fill_rf_config(RU_t *ru, char *rf_config_file) { cfg->rx_bw = 80e6; } break; + case 162 : + if (fp->threequarter_fs) { + AssertFatal(1==0,"N_RB %d cannot use 3/4 sampling\n",N_RB); + } + else { + cfg->sample_rate=61.44e6; + cfg->samples_per_frame = 614400; + cfg->tx_bw = 60e6; + cfg->rx_bw = 60e6; + } + + break; + case 133 : if (fp->threequarter_fs) { AssertFatal(1==0,"N_RB %d cannot use 3/4 sampling\n",N_RB); @@ -1139,8 +1168,7 @@ void *ru_stats_thread(void *param) { print_meas(&ru->ofdm_total_stats,"feptx_total",NULL,NULL); } - if (ru->fh_north_asynch_in) print_meas(&ru->rx_fhaul,"rx_fhaul",NULL,NULL); - + print_meas(&ru->rx_fhaul,"rx_fhaul",NULL,NULL); print_meas(&ru->tx_fhaul,"tx_fhaul",NULL,NULL); if (ru->fh_north_out) { @@ -1216,7 +1244,9 @@ void *ru_thread( void *param ) { int slot = fp->slots_per_frame-1; int frame = 1023; char threadname[40]; - int aa; + int initial_wait=0; + int opp_enabled0 = opp_enabled; + nfapi_nr_config_request_scf_t *cfg = &ru->config; // set default return value ru_thread_status = 0; @@ -1236,22 +1266,25 @@ void *ru_thread( void *param ) { exit(-1); } } else { + nr_init_frame_parms(&ru->config, fp); + nr_dump_frame_parms(fp); + fill_rf_config(ru,ru->rf_config_file); + nr_phy_init_RU(ru); + // Start IF device if any if (ru->nr_start_if) { LOG_I(PHY,"Starting IF interface for RU %d\n",ru->idx); AssertFatal(ru->nr_start_if(ru,NULL) == 0, "Could not start the IF device\n"); - if (ru->if_south == LOCAL_RF) ret = connect_rau(ru); - else ret = attach_rru(ru); + if (ru->has_ctrl_prt > 0) { + if (ru->if_south == LOCAL_RF) ret = connect_rau(ru); + else ret = attach_rru(ru); + + AssertFatal(ret==0,"Cannot connect to remote radio\n"); + } - AssertFatal(ret==0,"Cannot connect to remote radio\n"); } - - if (ru->if_south == LOCAL_RF) { // configure RF parameters only - nr_init_frame_parms(&ru->config, fp); - nr_dump_frame_parms(fp); - fill_rf_config(ru,ru->rf_config_file); - nr_phy_init_RU(ru); + else if (ru->if_south == LOCAL_RF) { // configure RF parameters only ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); AssertFatal(ret==0,"Cannot connect to local radio\n"); } @@ -1263,20 +1296,15 @@ void *ru_thread( void *param ) { } sf_ahead = (uint16_t) ceil((float)6/(0x01<numerology_index)); - LOG_I(PHY, "Signaling main thread that RU %d is ready\n",ru->idx); + LOG_I(PHY, "Signaling main thread that RU %d is ready, sf_ahead %d\n",ru->idx,sf_ahead); pthread_mutex_lock(&RC.ru_mutex); RC.ru_mask &= ~(1<idx); pthread_cond_signal(&RC.ru_cond); pthread_mutex_unlock(&RC.ru_mutex); wait_sync("ru_thread"); - notifiedFIFO_elt_t *msg = newNotifiedFIFO_elt(sizeof(processingData_L1_t),0,gNB->resp_L1,rx_func); - notifiedFIFO_elt_t *msgL1Tx = newNotifiedFIFO_elt(sizeof(processingData_L1_t),0,gNB->resp_L1_tx,tx_func); - notifiedFIFO_elt_t *msgRUTx = newNotifiedFIFO_elt(sizeof(processingData_L1_t),0,gNB->resp_RU_tx,ru_tx_func); + processingData_L1_t *syncMsg; notifiedFIFO_elt_t *res; - pushNotifiedFIFO(gNB->resp_L1,msg); // to unblock the process in the beginning - pushNotifiedFIFO(gNB->resp_L1_tx,msgL1Tx); // to unblock the process in the beginning - pushNotifiedFIFO(gNB->resp_RU_tx,msgRUTx); // to unblock the process in the beginning if(!emulate_rf) { // Start RF device if any @@ -1316,6 +1344,19 @@ void *ru_thread( void *param ) { if (ru->fh_south_in) ru->fh_south_in(ru,&frame,&slot); else AssertFatal(1==0, "No fronthaul interface at south port"); + if (initial_wait == 1 && proc->frame_rx < 300 && ru->fh_south_in == rx_rf) { + if (proc->frame_rx>0 && ((proc->frame_rx % 100) == 0) && proc->tti_rx==0) { + LOG_I(PHY,"delay processing to let RX stream settle, frame %d (trials %d)\n",proc->frame_rx,ru->rx_fhaul.trials); + print_meas(&ru->rx_fhaul,"rx_fhaul",NULL,NULL); + reset_meas(&ru->rx_fhaul); + } + continue; + } + if (proc->frame_rx>=300) { + initial_wait=0; + opp_enabled = opp_enabled0; + } + if (initial_wait == 0 && ru->rx_fhaul.trials > 1000) reset_meas(&ru->rx_fhaul); proc->timestamp_tx = proc->timestamp_rx + (sf_ahead*fp->samples_per_subframe); proc->frame_tx = (proc->tti_rx > (fp->slots_per_frame-1-(fp->slots_per_subframe*sf_ahead))) ? (proc->frame_rx+1)&1023 : proc->frame_rx; proc->tti_tx = (proc->tti_rx + (fp->slots_per_subframe*sf_ahead))%fp->slots_per_frame; @@ -1336,12 +1377,13 @@ void *ru_thread( void *param ) { ru->feprx(ru,proc->tti_rx); //LOG_M("rxdata.m","rxs",ru->common.rxdata[0],1228800,1,1); LOG_D(PHY,"RU proc: frame_rx = %d, tti_rx = %d\n", proc->frame_rx, proc->tti_rx); +/* LOG_D(PHY,"Copying rxdataF from RU to gNB\n"); - for (aa=0; aanb_rx; aa++) + for (int aa=0; aanb_rx; aa++) memcpy((void *)RC.gNB[0]->common_vars.rxdataF[aa], (void *)ru->common.rxdataF[aa], fp->symbols_per_slot*fp->ofdm_symbol_size*sizeof(int32_t)); - +*/ if (IS_SOFTMODEM_DOSCOPE && RC.gNB[0]->scopeData) ((scopeData_t *)RC.gNB[0]->scopeData)->slotFunc(ru->common.rxdataF[0],proc->tti_rx, RC.gNB[0]->scopeData); @@ -1405,13 +1447,24 @@ void *ru_thread( void *param ) { else LOG_I(PHY,"RU %d rf device stopped\n",ru->idx); } - delNotifiedFIFO_elt(msg); - delNotifiedFIFO_elt(msgL1Tx); - delNotifiedFIFO_elt(msgRUTx); + res = pullNotifiedFIFO(gNB->resp_L1); + delNotifiedFIFO_elt(res); + res = pullNotifiedFIFO(gNB->resp_L1_tx); + delNotifiedFIFO_elt(res); + res = pullNotifiedFIFO(gNB->resp_L1_tx); + delNotifiedFIFO_elt(res); + res = pullNotifiedFIFO(gNB->resp_RU_tx); + delNotifiedFIFO_elt(res); + ru_thread_status = 0; return &ru_thread_status; } +int start_streaming(RU_t *ru) { + LOG_I(PHY,"Starting streaming on third-party RRU\n"); + return(ru->ifdevice.thirdparty_startstreaming(&ru->ifdevice)); +} + int nr_start_if(struct RU_t_s *ru, struct PHY_VARS_gNB_s *gNB) { return(ru->ifdevice.trx_start_func(&ru->ifdevice)); } @@ -1668,6 +1721,7 @@ void set_function_spec_param(RU_t *ru) { switch (ru->if_south) { case LOCAL_RF: // this is an RU with integrated RF (RRU, gNB) + reset_meas(&ru->rx_fhaul); if (ru->function == NGFI_RRU_IF5) { // IF5 RRU ru->do_prach = 0; // no prach processing in RU ru->fh_north_in = NULL; // no shynchronous incoming fronthaul from north @@ -1705,7 +1759,6 @@ void set_function_spec_param(RU_t *ru) { ru->ifdevice.host_type = RRU_HOST; ru->rfdevice.host_type = RRU_HOST; ru->ifdevice.eth_params = &ru->eth_params; - reset_meas(&ru->rx_fhaul); reset_meas(&ru->tx_fhaul); reset_meas(&ru->compression); reset_meas(&ru->transport); @@ -1757,7 +1810,7 @@ void set_function_spec_param(RU_t *ru) { ru->fh_south_in = fh_if5_south_in; // synchronous IF5 reception ru->fh_south_out = fh_if5_south_out; // synchronous IF5 transmission ru->fh_south_asynch_in = NULL; // no asynchronous UL - ru->start_rf = NULL; // no local RF + ru->start_rf = ru->eth_params.transp_preference == ETH_UDP_IF5_ECPRI_MODE ? start_streaming : NULL; ru->stop_rf = NULL; ru->start_write_thread = NULL; ru->nr_start_if = nr_start_if; // need to start if interface for IF5 @@ -2013,7 +2066,7 @@ static void NRRCconfig_RU(void) { RC.ru[j]->max_pdschReferenceSignalPower = *(RUParamList.paramarray[j][RU_MAX_RS_EPRE_IDX].uptr);; RC.ru[j]->max_rxgain = *(RUParamList.paramarray[j][RU_MAX_RXGAIN_IDX].uptr); RC.ru[j]->num_bands = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt; - + RC.ru[j]->sf_extension = *(RUParamList.paramarray[j][RU_SF_EXTENSION_IDX].uptr); for (i=0; inum_bands; i++) RC.ru[j]->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i]; } //strcmp(local_rf, "yes") == 0 else { @@ -2030,6 +2083,12 @@ static void NRRCconfig_RU(void) { RC.ru[j]->if_south = REMOTE_IF5; RC.ru[j]->function = NGFI_RAU_IF5; RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE; + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_ecpri_if5") == 0) { + RC.ru[j]->if_south = REMOTE_IF5; + RC.ru[j]->function = NGFI_RAU_IF5; + RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF5_ECPRI_MODE; + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_ecpri_if5") == 0) { + RC.ru[j]->if_south = REMOTE_IF5; } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) { RC.ru[j]->if_south = REMOTE_IF5; RC.ru[j]->function = NGFI_RAU_IF5; diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index c38c5217ae..3a6a795bb0 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -321,8 +321,8 @@ void set_options(int CC_id, PHY_VARS_NR_UE *UE){ UE->rf_map.card = card_offset; UE->rf_map.chain = CC_id + chain_offset; - LOG_I(PHY,"Set UE mode %d, UE_fo_compensation %d, UE_scan_carrier %d, UE_no_timing_correction %d \n, do_prb_interpolation %d\n", - UE->mode, UE->UE_fo_compensation, UE->UE_scan_carrier, UE->no_timing_correction, UE->prb_interpolation); + LOG_I(PHY,"Set UE mode %d, UE_fo_compensation %d, UE_scan_carrier %d, UE_no_timing_correction %d \n, do_prb_interpolation %d\n", + UE->mode, UE->UE_fo_compensation, UE->UE_scan_carrier, UE->no_timing_correction, UE->prb_interpolation); // Set FP variables @@ -331,7 +331,7 @@ void set_options(int CC_id, PHY_VARS_NR_UE *UE){ LOG_I(PHY, "Set UE frame_type %d\n", fp->frame_type); } - LOG_I(PHY, "Set UE nb_rx_antenna %d, nb_tx_antenna %d, threequarter_fs %d\n", fp->nb_antennas_rx, fp->nb_antennas_tx, fp->threequarter_fs); + LOG_I(PHY, "Set UE nb_rx_antenna %d, nb_tx_antenna %d, threequarter_fs %d, ssb_start_subcarrier %d\n", fp->nb_antennas_rx, fp->nb_antennas_tx, fp->threequarter_fs, fp->ssb_start_subcarrier); fp->ofdm_offset_divisor = nrUE_params.ofdm_offset_divisor; @@ -438,7 +438,7 @@ int main( int argc, char **argv ) { itti_init(TASK_MAX, tasks_info); init_opt() ; - load_nrLDPClib(); + load_nrLDPClib(NULL); if (ouput_vcd) { vcd_signal_dumper_init("/tmp/openair_dump_nrUE.vcd"); diff --git a/executables/nr-uesoftmodem.h b/executables/nr-uesoftmodem.h index 8469ffe790..7f47ed5eb3 100644 --- a/executables/nr-uesoftmodem.h +++ b/executables/nr-uesoftmodem.h @@ -50,7 +50,7 @@ { NOL2CONNECT_OPT, CONFIG_HLP_NOL2CN, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \ { CALIBPRACH_OPT, CONFIG_HLP_CALPRACH, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \ { DUMPFRAME_OPT, CONFIG_HLP_DUMPFRAME, PARAMFLAG_BOOL, iptr:&dumpframe, defintval:0, TYPE_INT, 0}, \ - {"ue-rxgain", CONFIG_HLP_UERXG, 0, dblptr:&(rx_gain[0][0]), defdblval:0, TYPE_DOUBLE,0}, \ + {"ue-rxgain", CONFIG_HLP_UERXG, 0, dblptr:&(rx_gain[0][0]), defdblval:110, TYPE_DOUBLE,0}, \ {"ue-rxgain-off", CONFIG_HLP_UERXGOFF, 0, dblptr:&rx_gain_off, defdblval:0, TYPE_DOUBLE,0}, \ {"ue-txgain", CONFIG_HLP_UETXG, 0, dblptr:&(tx_gain[0][0]), defdblval:0, TYPE_DOUBLE,0}, \ {"ue-nb-ant-rx", CONFIG_HLP_UENANTR, 0, u8ptr:&(fp->nb_antennas_rx), defuintval:1, TYPE_UINT8, 0}, \ diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h index c6a1eb44e4..3a7022a502 100644 --- a/executables/softmodem-common.h +++ b/executables/softmodem-common.h @@ -155,10 +155,10 @@ extern int usrp_tx_thread; {"nokrnmod", CONFIG_HLP_NOKRNMOD, PARAMFLAG_BOOL, uptr:&nokrnmod, defintval:0, TYPE_INT, 0}, \ {"nbiot-disable", CONFIG_HLP_DISABLNBIOT, PARAMFLAG_BOOL, uptr:&nonbiot, defuintval:0, TYPE_INT, 0}, \ {"use-256qam-table", CONFIG_HLP_256QAM, PARAMFLAG_BOOL, iptr:&USE_256QAM_TABLE, defintval:0, TYPE_INT, 0}, \ - {"do-prb-interpolation", CONFIG_HLP_PRBINTER, PARAMFLAG_BOOL, iptr:&PRB_INTERPOLATION, defintval:0, TYPE_INT, 0}, \ - {"usrp-tx-thread-config",CONFIG_HLP_USRP_THREAD, 0, iptr:&usrp_tx_thread, defstrval:0, TYPE_INT, 0}, \ - {"nfapi", CONFIG_HLP_NFAPI, 0, u8ptr:&nfapi_mode, defintval:0, TYPE_UINT8, 0}, \ - {"non-stop", CONFIG_HLP_NONSTOP, PARAMFLAG_BOOL, iptr:&NON_STOP, defintval:0, TYPE_INT, 0}, \ + {"do-prb-interpolation", CONFIG_HLP_PRBINTER, PARAMFLAG_BOOL, iptr:&PRB_INTERPOLATION, defintval:0, TYPE_INT, 0}, \ + {"usrp-tx-thread-config", CONFIG_HLP_USRP_THREAD, 0, iptr:&usrp_tx_thread, defstrval:0, TYPE_INT, 0}, \ + {"nfapi", CONFIG_HLP_NFAPI, 0, u8ptr:&nfapi_mode, defintval:0, TYPE_UINT8, 0}, \ + {"non-stop", CONFIG_HLP_NONSTOP, PARAMFLAG_BOOL, iptr:&NON_STOP, defintval:0, TYPE_INT, 0}, \ } diff --git a/nfapi/oai_integration/nfapi_pnf.c b/nfapi/oai_integration/nfapi_pnf.c index 2b1900200a..4edbeee342 100644 --- a/nfapi/oai_integration/nfapi_pnf.c +++ b/nfapi/oai_integration/nfapi_pnf.c @@ -1104,25 +1104,70 @@ void pnf_phy_deallocate_p7_vendor_ext(nfapi_p7_message_header_t *header) { free(header); } +notifiedFIFO_elt_t *l1tx_message_extract(PHY_VARS_gNB *gNB, int frame, int slot) { + notifiedFIFO_elt_t *res; + notifiedFIFO_elt_t *freeRes = NULL; + + // check first message + res = pullTpool(gNB->resp_L1_tx, gNB->threadPool); + processingData_L1tx_t *msgTx = (processingData_L1tx_t *)NotifiedFifoData(res); + if (msgTx->slot == slot) { + return res; + } + if (msgTx->slot == -1) { + freeRes = res; + } + + // check second message + pushNotifiedFIFO(gNB->resp_L1_tx,res); + res = pullTpool(gNB->resp_L1_tx, gNB->threadPool); + msgTx = (processingData_L1tx_t *)NotifiedFifoData(res); + if (msgTx->slot == slot) { + return res; + } + if (msgTx->slot == -1) { + freeRes = res; + } + + if (freeRes) { + msgTx = (processingData_L1tx_t *)NotifiedFifoData(res); + msgTx->num_pdsch_slot=0; + msgTx->pdcch_pdu.pdcch_pdu_rel15.numDlDci = 0; + msgTx->ul_pdcch_pdu.pdcch_pdu.pdcch_pdu_rel15.numDlDci = 0; + msgTx->slot = slot; + msgTx->frame = frame; + return freeRes; + } + pushNotifiedFIFO(gNB->resp_L1_tx,res); + AssertFatal(1==0, "It means both L1 Tx messages are still waiting to be processed. This happens when L1 Tx processing is too slow. Message slot %d, scheduled slot %d\n", + msgTx->slot, slot); +} int pnf_phy_ul_dci_req(gNB_L1_rxtx_proc_t *proc, nfapi_pnf_p7_config_t *pnf_p7, nfapi_nr_ul_dci_request_t *req) { // LOG_D(PHY,"[PNF] HI_DCI0_REQUEST SFN/SF:%05d dci:%d hi:%d\n", NFAPI_SFNSF2DEC(req->sfn_sf), req->hi_dci0_request_body.number_of_dci, req->hi_dci0_request_body.number_of_hi); struct PHY_VARS_gNB_s *gNB = RC.gNB[0]; + + // extract the next available thread message (priority to message with current slot, then free message) + notifiedFIFO_elt_t *res; + res = l1tx_message_extract(gNB, req->SFN, req->Slot); + processingData_L1tx_t *msgTx = (processingData_L1tx_t *)NotifiedFifoData(res); + if (proc ==NULL) proc = &gNB->proc.L1_proc; - for (int i=0; inumPdus; i++) { - if (req->ul_dci_pdu_list[i].PDUType == 0) { - nfapi_nr_ul_dci_request_pdus_t *ul_dci_req_pdu = &req->ul_dci_pdu_list[i]; - handle_nfapi_nr_ul_dci_pdu(gNB, req->SFN, req->Slot, ul_dci_req_pdu); + if (req->numPdus > 0) { + if (req->ul_dci_pdu_list[req->numPdus-1].PDUType == 0) { // copy only the last PDU (PHY can have only one UL PDCCH pdu) + msgTx->ul_pdcch_pdu = req->ul_dci_pdu_list[req->numPdus-1]; // copy the last pdu } else { - LOG_E(PHY,"[PNF] UL_DCI_REQ sfn_slot:%d PDU[%d] - unknown pdu type:%d\n", NFAPI_SFNSLOT2DEC(req->SFN, req->Slot), i, req->ul_dci_pdu_list[i].PDUType); + LOG_E(PHY,"[PNF] UL_DCI_REQ sfn_slot:%d PDU[%d] - unknown pdu type:%d\n", NFAPI_SFNSLOT2DEC(req->SFN, req->Slot), req->numPdus-1, req->ul_dci_pdu_list[req->numPdus-1].PDUType); } } + pushNotifiedFIFO(gNB->resp_L1_tx,res); + return 0; } @@ -1193,14 +1238,17 @@ int pnf_phy_dl_tti_req(gNB_L1_rxtx_proc_t *proc, nfapi_pnf_p7_config_t *pnf_p7, for (int i=0; idl_tti_request_body.nPDUs; i++) { // NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() sfn/sf:%d PDU[%d] size:%d pdcch_vars->num_dci:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), i, dl_config_pdu_list[i].pdu_size,pdcch_vars->num_dci); + notifiedFIFO_elt_t *res; + res = l1tx_message_extract(gNB, sfn, slot); + processingData_L1tx_t *msgTx = (processingData_L1tx_t *)NotifiedFifoData(res); if (dl_tti_pdu_list[i].PDUType == NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE) { - nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdu=&dl_tti_pdu_list[i]; - handle_nfapi_nr_pdcch_pdu(gNB, sfn, slot, &dl_tti_pdu->pdcch_pdu); + // we trust the scheduler sends only one PDCCH PDU per slot + msgTx->pdcch_pdu = dl_tti_pdu_list[i].pdcch_pdu; // fills the last received PDCCH PDU } else if (dl_tti_pdu_list[i].PDUType == NFAPI_NR_DL_TTI_SSB_PDU_TYPE) { //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() PDU:%d BCH: pdu_index:%u pdu_length:%d sdu_length:%d BCH_SDU:%x,%x,%x\n", __FUNCTION__, i, pdu_index, bch_pdu->bch_pdu_rel8.length, tx_request_pdu[sfn][sf][pdu_index]->segments[0].segment_length, sdu[0], sdu[1], sdu[2]); - handle_nr_nfapi_ssb_pdu(gNB, sfn, slot, &dl_tti_pdu_list[i]); + handle_nr_nfapi_ssb_pdu(msgTx, sfn, slot, &dl_tti_pdu_list[i]); gNB->pbch_configured=1; } else if (dl_tti_pdu_list[i].PDUType == NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE) { @@ -1209,21 +1257,11 @@ int pnf_phy_dl_tti_req(gNB_L1_rxtx_proc_t *proc, nfapi_pnf_p7_config_t *pnf_p7, nfapi_nr_pdu_t *tx_data = tx_data_request[sfn][slot][rel15_pdu->pduIndex]; if (tx_data != NULL) { - int UE_id = find_nr_dlsch(rel15_pdu->rnti,gNB,SEARCH_EXIST_OR_FREE); - AssertFatal(UE_id!=-1,"no free or exiting dlsch_context\n"); - AssertFatal(UE_id= %d(NUMBER_OF_UE_MAX)\n",UE_id,NUMBER_OF_UE_MAX); - NR_gNB_DLSCH_t *dlsch0 = gNB->dlsch[UE_id][0]; - int harq_pid = dlsch0->harq_ids[sfn%2][slot]; - - if(harq_pid >= dlsch0->Mdlharq) { - LOG_E(PHY,"pnf_phy_dl_config_req illegal harq_pid %d\n", harq_pid); - return(-1); - } - - uint8_t *dlsch_sdu = nr_tx_pdus[UE_id][harq_pid]; - memcpy(dlsch_sdu, tx_data->TLVs[0].value.direct,tx_data->PDU_length); + uint8_t *dlsch_sdu = (uint8_t *)tx_data->TLVs[0].value.direct; //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() DLSCH:pdu_index:%d handle_nfapi_dlsch_pdu(eNB, proc_rxtx, dlsch_pdu, transport_blocks:%d sdu:%p) eNB->pdcch_vars[proc->subframe_tx & 1].num_pdcch_symbols:%d\n", __FUNCTION__, rel8_pdu->pdu_index, rel8_pdu->transport_blocks, dlsch_sdu, eNB->pdcch_vars[proc->subframe_tx & 1].num_pdcch_symbols); - handle_nr_nfapi_pdsch_pdu(gNB, sfn, slot,pdsch_pdu, dlsch_sdu); + AssertFatal(msgTx->num_pdsch_slot < gNB->number_of_nr_dlsch_max,"Number of PDSCH PDUs %d exceeded the limit %d\n", + msgTx->num_pdsch_slot,gNB->number_of_nr_dlsch_max); + handle_nr_nfapi_pdsch_pdu(msgTx, pdsch_pdu, dlsch_sdu); } else { NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() DLSCH NULL TX PDU SFN/SF:%d PDU_INDEX:%d\n", __FUNCTION__, NFAPI_SFNSLOT2DEC(sfn,slot), rel15_pdu->pduIndex); @@ -1231,11 +1269,12 @@ int pnf_phy_dl_tti_req(gNB_L1_rxtx_proc_t *proc, nfapi_pnf_p7_config_t *pnf_p7, } else if (dl_tti_pdu_list[i].PDUType == NFAPI_NR_DL_TTI_CSI_RS_PDU_TYPE) { nfapi_nr_dl_tti_csi_rs_pdu *csi_rs_pdu = &dl_tti_pdu_list[i].csi_rs_pdu; - handle_nfapi_nr_csirs_pdu(gNB, sfn, slot, csi_rs_pdu); + handle_nfapi_nr_csirs_pdu(msgTx, sfn, slot, csi_rs_pdu); } else { NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() UNKNOWN:%d\n", __FUNCTION__, dl_tti_pdu_list[i].PDUType); } + pushNotifiedFIFO(gNB->resp_L1_tx,res); } if(req->vendor_extension) diff --git a/openair1/PHY/CODING/DOC/LDPCImplementation.md b/openair1/PHY/CODING/DOC/LDPCImplementation.md index 89ae6b4dbb..c5411540b6 100644 --- a/openair1/PHY/CODING/DOC/LDPCImplementation.md +++ b/openair1/PHY/CODING/DOC/LDPCImplementation.md @@ -1,11 +1,13 @@ -#LDPC coder/decoder implementation +# LDPC coder/decoder implementation The LDPC coder and decoder are implemented in a shared library, dynamically loaded at run-time using the [oai shared library loader](file://../../../../common/utils/DOC/loader.md). The code loading the LDPC library is in [nrLDPC_load.c](file://../nrLDPC_load.c), in function `load_nrLDPClib`, which must be called at init time. ## Selecting the LDPC library at run time By default the function `int load_nrLDPClib(void)` looks for `libldpc.so`, this default behavior can be changed using the oai loader configuration options in the configuration file or from the command line as shown below: ->loading `libldpc_optim8seg.so` instead of `libldpc.so` +#### Examples of ldpc shared lib selection when running nr softmodem's: + +loading `libldpc_optim8seg.so` instead of `libldpc.so`: ``` ./nr-softmodem -O libconfig:gnb.band78.tm1.106PRB.usrpx300.conf:dbgl5 --loader.ldpc.shlibversion _optim8seg @@ -18,9 +20,160 @@ By default the function `int load_nrLDPClib(void)` looks for `libldpc.so`, this ........................ ``` -Today, this mechanism is not available in the `ldpctest` phy simulator which doesn't initialize the [configuration module](file://../../../../common/config/DOC/config.md). loads `libldpc.so` and `libldpc_orig.so` to compare the performance of the two implementations. +loading `libldpc_cl.so` instead of `libldpc.so`: -###LDPC libraries -Libraries implementing the LDPC algorithms must be named `libldpc<_version>.so`, they must implement two functions: `nrLDPC_decod` and `nrLDPC_encod`. The prototypes for these functions is defined in [nrLDPC_defs.h](file://nrLDPC_defs.h). +`make ldpc_cl` + +`cp ../../../openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_kernels_CL.cl` + +`./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --sa --log_config.gtpu_log_level info --loader.ldpc.shlibversion _cl` + +``` [LOADER] library libldpc_cl.so successfully loaded +------------------------------------------------ +[HW] Platform 0, OpenCL profile FULL_PROFILE +[HW] Platform 0, OpenCL version OpenCL 2.1 LINUX +[HW] Device 0 is available +[HW] Device 0, type 2 = 0x00000002: cpu +[HW] Device 0, number of Compute Units: 8 +[HW] Device 0, max Work Items dimension: 3 +[HW] Device 0, max Work Items size for dimension: 0 8192 +[HW] Device 0, max Work Items size for dimension: 1 8192 +[HW] Device 0, max Work Items size for dimension: 2 8192 +[New Thread 0x7fffcc258700 (LWP 3945123)] +[New Thread 0x7fffc3e57700 (LWP 3945124)] +[New Thread 0x7fffcbe57700 (LWP 3945125)] +[New Thread 0x7fffcba56700 (LWP 3945126)] +[New Thread 0x7fffcb254700 (LWP 3945128)] +[New Thread 0x7fffcb655700 (LWP 3945127)] +[New Thread 0x7fffcae53700 (LWP 3945129)] +[HW] Platform 1, OpenCL profile FULL_PROFILE +[HW] Platform 1, OpenCL version OpenCL 2.0 beignet 1.3 +[New Thread 0x7fffc965a700 (LWP 3945130)] +[Thread 0x7fffc965a700 (LWP 3945130) exited] +[HW] Device 0 is available +[HW] Device 0, type 4 = 0x00000004: gpu +[HW] Device 0, number of Compute Units: 20 +[HW] Device 0, max Work Items dimension: 3 +[HW] Device 0, max Work Items size for dimension: 0 512 +[HW] Device 0, max Work Items size for dimension: 1 512 +[HW] Device 0, max Work Items size for dimension: 2 512 +----------------------------------------------------------------- +``` + +`./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim --sa -O libconfig:/usr/local/oai/conf/nrue_sim.conf:dbgl5 --nokrnmod --loader.ldpc.shlibversion _cl --log_config.hw_log_level info` + +```[CONFIG] shlibversion set to _cl from command line +............................................................ +[CONFIG] loader.ldpc 1 options set from command line +[LOADER] library libldpc_cl.so successfully loaded +[HW] Platform 0, OpenCL profile FULL_PROFILE +[HW] Platform 0, OpenCL version OpenCL 2.1 LINUX +[HW] Device 0 is available +[HW] Device 0, type 2 = 0x00000002: cpu +[HW] Device 0, number of Compute Units: 8 +[HW] Device 0, max Work Items dimension: 3 +[HW] Device 0, max Work Items size for dimension: 0 8192 +[HW] Device 0, max Work Items size for dimension: 1 8192 +[HW] Device 0, max Work Items size for dimension: 2 8192 +[New Thread 0x7fffecccc700 (LWP 3945413)] +[New Thread 0x7fffec8cb700 (LWP 3945415)] +[New Thread 0x7fffec4ca700 (LWP 3945414)] +[New Thread 0x7fffdf7fd700 (LWP 3945417)] +[New Thread 0x7fffdfbfe700 (LWP 3945418)] +[New Thread 0x7fffdffff700 (LWP 3945416)] +[New Thread 0x7fffd73fc700 (LWP 3945419)] +[HW] Platform 1, OpenCL profile FULL_PROFILE +[HW] Platform 1, OpenCL version OpenCL 2.0 beignet 1.3 +[New Thread 0x7fffde105700 (LWP 3945420)] +[Thread 0x7fffde105700 (LWP 3945420) exited] +[HW] Device 0 is available +[HW] Device 0, type 4 = 0x00000004: gpu +[HW] Device 0, number of Compute Units: 20 +[HW] Device 0, max Work Items dimension: 3 +[HW] Device 0, max Work Items size for dimension: 0 512 +[HW] Device 0, max Work Items size for dimension: 1 512 +[HW] Device 0, max Work Items size for dimension: 2 512 +------------------------------------------------------------ +​``` +``` + +A mechanism to select ldpc implementation is also available in the `ldpctest` phy simulator via the `-v`option, which can be used to specify the version of the ldpc shared library to be used. + +#### Examples of ldpc shared lib selection when running ldpctest: + +Loading libldpc_cuda.so, the cuda implementation of the ldpc decoder: + +```$ ./ldpctest -v _cuda +Initializing random number generator, seed 0 +block length 8448: +n_trials 1: +SNR0 -2.000000: +[CONFIG] get parameters from cmdline , debug flags: 0x00400000 +[CONFIG] log_config: 2/3 parameters successfully set +[CONFIG] log_config: 53/53 parameters successfully set +[CONFIG] log_config: 53/53 parameters successfully set +[CONFIG] log_config: 16/16 parameters successfully set +[CONFIG] log_config: 16/16 parameters successfully set +log init done +[CONFIG] loader: 2/2 parameters successfully set +[CONFIG] loader.ldpc: 1/2 parameters successfully set +[LOADER] library libldpc_cuda.so successfully loaded +................................... +​``` +``` + +Loading libldpc_cl.so, the opencl implementation of the ldpc decoder: + +`make ldpc_cl` + +`cp ../../../openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_kernels_CL.cl` + +`./ldpctest -v _cl` + +```$ ./ldpctest -v _cl +Initializing random number generator, seed 0 +block length 8448: +n_trials 1: +SNR0 -2.000000: +[CONFIG] get parameters from cmdline , debug flags: 0x00400000 +[CONFIG] log_config: 2/3 parameters successfully set +[CONFIG] log_config: 53/53 parameters successfully set +[CONFIG] log_config: 53/53 parameters successfully set +[CONFIG] log_config: 16/16 parameters successfully set +[CONFIG] log_config: 16/16 parameters successfully set +log init done +[CONFIG] loader: 2/2 parameters successfully set +[CONFIG] loader.ldpc: 1/2 parameters successfully set +[LOADER] library libldpc_cl.so successfully loaded +[HW] Platform 0, OpenCL profile FULL_PROFILE +[HW] Platform 0, OpenCL version OpenCL 2.1 LINUX +[HW] Device 0 is available +[HW] Device 0, type 2 = 0x00000002: cpu +[HW] Device 0, number of Compute Units: 8 +[HW] Device 0, max Work Items dimension: 3 +[HW] Device 0, max Work Items size for dimension: 0 8192 +[HW] Device 0, max Work Items size for dimension: 1 8192 +[HW] Device 0, max Work Items size for dimension: 2 8192 +[HW] Platform 1, OpenCL profile FULL_PROFILE +[HW] Platform 1, OpenCL version OpenCL 2.0 beignet 1.3 +[HW] Device 0 is available +[HW] Device 0, type 4 = 0x00000004: gpu +[HW] Device 0, number of Compute Units: 20 +[HW] Device 0, max Work Items dimension: 3 +[HW] Device 0, max Work Items size for dimension: 0 512 +[HW] Device 0, max Work Items size for dimension: 1 512 +[HW] Device 0, max Work Items size for dimension: 2 512 +................................ +​``` +``` + + + +### LDPC libraries +Libraries implementing the LDPC algorithms must be named `libldpc<_version>.so`, they must implement three functions: `nrLDPC_initcall` `nrLDPC_decod` and `nrLDPC_encod`. The prototypes for these functions is defined in [nrLDPC_defs.h](file://nrLDPC_defs.h). + +`libldpc_cuda.so`has been tested with the `ldpctest` executable, usage from the softmodem's has to be tested. + +`libldpc_cl`is under development. [oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home) diff --git a/openair1/PHY/CODING/TESTBENCH/ldpctest.c b/openair1/PHY/CODING/TESTBENCH/ldpctest.c index 91c5d59611..aff707a1d5 100644 --- a/openair1/PHY/CODING/TESTBENCH/ldpctest.c +++ b/openair1/PHY/CODING/TESTBENCH/ldpctest.c @@ -101,8 +101,8 @@ int test_ldpc(short No_iteration, unsigned int *crc_misses, time_stats_t *time_optim, time_stats_t *time_decoder, - n_iter_stats_t *dec_iter, - short run_cuda) + n_iter_stats_t *dec_iter + ) { //clock initiate //time_stats_t time,time_optim,tinput,tprep,tparity,toutput, time_decoder; @@ -393,28 +393,13 @@ int test_ldpc(short No_iteration, decParams.R=code_rate_vec[R_ind];//13; decParams.numMaxIter=No_iteration; decParams.outMode = nrLDPC_outMode_BIT; + decParams.block_length=block_length; //decParams.outMode =nrLDPC_outMode_LLRINT8; -#ifdef CUDA_FLAG - set_compact_BG(Zc,BG); - init_LLR_DMA_for_CUDA(&decParams, (int8_t*)channel_output_fixed[j], (int8_t*)estimated_output[j], block_length); -#endif + nrLDPC_initcall(&decParams, (int8_t*)channel_output_fixed[j], (int8_t*)estimated_output[j]); for(j=0;j 1280, 2401 -> 2560 - + char *ldpc_version=NULL; /* version of the ldpc decoder library to use (XXX suffix to use when loading libldpc_XXX.so */ short No_iteration=5; int n_segments=1; //double rate=0.333; - short run_cuda = 0; int nom_rate=1; int denom_rate=3; @@ -544,7 +526,7 @@ int main(int argc, char *argv[]) short BG=0,Zc,Kb=0; - while ((c = getopt (argc, argv, "q:r:s:S:l:G:n:d:i:t:u:h")) != -1) + while ((c = getopt (argc, argv, "q:r:s:S:l:G:n:d:i:t:u:hv:")) != -1) switch (c) { case 'q': @@ -564,7 +546,7 @@ int main(int argc, char *argv[]) break; case 'G': - run_cuda = atoi(optarg); + ldpc_version="_cuda"; break; case 'n': @@ -590,9 +572,11 @@ int main(int argc, char *argv[]) case 'u': test_uncoded = atoi(optarg); break; - + case 'v': + ldpc_version=strdup(optarg); + break; case 'h': - default: + default: printf("CURRENTLY SUPPORTED CODE RATES: \n"); printf("BG1 (blocklength > 3840): 1/3, 2/3, 22/25 (8/9) \n"); printf("BG2 (blocklength <= 3840): 1/5, 1/3, 2/3 \n\n"); @@ -609,6 +593,7 @@ int main(int argc, char *argv[]) printf("-t SNR simulation step, Default: 0.1\n"); printf("-i Max decoder iterations, Default: 5\n"); printf("-u Set SNR per coded bit, Default: 0\n"); + printf("-v XXX Set ldpc shared library version. libldpc_XXX.so will be used \n"); exit(1); break; } @@ -619,7 +604,10 @@ int main(int argc, char *argv[]) printf("SNR0 %f: \n", SNR0); - load_nrLDPClib(); + if (ldpc_version != NULL) + load_nrLDPClib(ldpc_version); + else + load_nrLDPClib(NULL); load_nrLDPClib_ref("_orig", &encoder_orig); //for (block_length=8;block_length<=MAX_BLOCK_LENGTH;block_length+=8) @@ -691,8 +679,7 @@ int main(int argc, char *argv[]) &crc_misses, time_optim, time_decoder, - dec_iter, - run_cuda); + dec_iter); printf("SNR %f, BLER %f (%u/%d)\n", SNR, (float)decoded_errors[i]/(float)n_trials, decoded_errors[i], n_trials); printf("SNR %f, BER %f (%u/%d)\n", SNR, (float)errors_bit/(float)n_trials/(float)block_length/(double)n_segments, decoded_errors[i], n_trials); diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c index 3226c97f87..166cd9a5a3 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c @@ -46,7 +46,8 @@ #endif static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, t_nrLDPC_procBuf* p_procBuf, uint32_t numLLR, t_nrLDPC_lut* p_lut, t_nrLDPC_dec_params* p_decParams, t_nrLDPC_time_stats* p_profiler); - +void nrLDPC_initcall(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_out) { +} int32_t nrLDPC_decod(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_out, t_nrLDPC_procBuf* p_procBuf, t_nrLDPC_time_stats* p_profiler) { uint32_t numLLR; @@ -55,7 +56,6 @@ int32_t nrLDPC_decod(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_ t_nrLDPC_lut* p_lut = &lut; //printf("p_procBuf->cnProcBuf = %p\n", p_procBuf->cnProcBuf); - // Initialize decoder core(s) with correct LUTs numLLR = nrLDPC_init(p_decParams, p_lut); @@ -231,7 +231,7 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, t_nrLDP // First iteration finished - while ( (i < (numMaxIter-1)) && (pcRes != 0) ) + while ( (i < numMaxIter) && (pcRes != 0) ) { // Increase iteration counter i++; diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c new file mode 100644 index 0000000000..58e6b507af --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c @@ -0,0 +1,436 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + /*! \file nrLDPC_decoder_CL.c +* \brief ldpc decoder, openCL implementaion +* \author Francois TABURET +* \date 2021 +* \version 1.0 +* \note initial implem - translation of cuda version +*/ +/* uses HW component id for log messages ( --log_config.hw_log_level ) */ +#include +#include +#include +#include +#include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h" +#include "PHY/CODING/nrLDPC_decoder/nrLDPCdecoder_defs.h" +#include "assertions.h" +#include "common/utils/LOG/log.h" + +#define MAX_ITERATION 2 +#define MC 1 + +#define MAX_OCLDEV 10 +#define MAX_OCLRUNTIME 5 + + +#define CLSETKERNELARG(A,B,C,D) \ +rt=clSetKernelArg(A,B,C,D) ;\ +AssertFatal(rt == CL_SUCCESS, "Error %d setting kernel argument index %d\n" , (int)rt, B); + +typedef struct{ + char x; + char y; + short value; +} h_element; +#include "../nrLDPC_decoder_LYC/bgs/BG1_compact_in_C.h" + +typedef struct{ + cl_uint max_CU; + cl_uint max_WID; + size_t *max_WIS; +} ocldev_t; + +typedef struct { + cl_kernel cnp_kernel_1st; + cl_kernel cnp_kernel; + cl_kernel vnp_kernel_normal; + cl_kernel pack_decoded_bit; +} oclkernels_t; + +typedef struct{ + cl_uint num_devices; + cl_device_id devices[MAX_OCLDEV]; + ocldev_t ocldev[MAX_OCLDEV]; + cl_context context; + cl_program program; + cl_mem dev_h_compact1; + cl_mem dev_h_compact2; + cl_mem dev_const_llr; + cl_mem dev_llr; + cl_mem dev_dt; + cl_mem dev_tmp; + oclkernels_t kernels[MAX_OCLDEV]; + cl_command_queue queue[MAX_OCLDEV]; +} oclruntime_t; + +typedef struct{ + oclruntime_t runtime[MAX_OCLRUNTIME]; +} ocl_t; + + + +ocl_t ocl; + + +void set_compact_BG(int Zc,short BG){ + cl_uint rt; + int row,col; + if(BG == 1){ + row = 46; + col = 68; + } + else{ + row = 42; + col = 52; + } + int compact_row = 30; + int compact_col = 19; + if(BG==2){compact_row = 10, compact_col = 23;} + int memorySize_h_compact1 = row * compact_col * sizeof(h_element); + int memorySize_h_compact2 = compact_row * col * sizeof(h_element); + int lift_index = 0; + short lift_set[][9] = { + {2,4,8,16,32,64,128,256}, + {3,6,12,24,48,96,192,384}, + {5,10,20,40,80,160,320}, + {7,14,28,56,112,224}, + {9,18,36,72,144,288}, + {11,22,44,88,176,352}, + {13,26,52,104,208}, + {15,30,60,120,240}, + {0} + }; + + for(int i = 0; lift_set[i][0] != 0; i++){ + for(int j = 0; lift_set[i][j] != 0; j++){ + if(Zc == lift_set[i][j]){ + lift_index = i; + break; + } + } + } + printf("\nZc = %d BG = %d\n",Zc,BG); + ocl.runtime[0].dev_h_compact1 = clCreateBuffer(ocl.runtime[0].context, CL_MEM_READ_ONLY|CL_MEM_HOST_WRITE_ONLY, memorySize_h_compact1, NULL, (cl_int *)&rt); + AssertFatal(rt == CL_SUCCESS, "Error %d creating buffer dev_h_compact1 for platform %i \n" , (int)rt, 0); + ocl.runtime[0].dev_h_compact2 = clCreateBuffer(ocl.runtime[0].context, CL_MEM_READ_ONLY|CL_MEM_HOST_WRITE_ONLY, memorySize_h_compact2, NULL, (cl_int *)&rt); + AssertFatal(rt == CL_SUCCESS, "Error %d creating buffer dev_h_compact2 for platform %i \n" , (int)rt, 0); + h_element *h1; + h_element *h2; + switch(lift_index){ + case 0: + h1 = host_h_compact1_I0; + h2 = host_h_compact2_I0; + break; + case 1: + h1 = host_h_compact1_I1; + h2 = host_h_compact2_I1; + break; + case 2: + h1 = host_h_compact1_I2; + h2 = host_h_compact2_I2; + break; + case 3: + h1 = host_h_compact1_I3; + h2 = host_h_compact2_I3; + break; + case 4: + h1 = host_h_compact1_I4; + h2 = host_h_compact2_I4; + break; + case 5: + h1 = host_h_compact1_I5; + h2 = host_h_compact2_I5; + break; + case 6: + h1 = host_h_compact1_I6; + h2 = host_h_compact2_I6; + break; + case 7: + h1 = host_h_compact1_I7; + h2 = host_h_compact2_I7; + break; + default: + AssertFatal(0, "Invalid lift_index value %i\n" , lift_index); + break; + } + rt = clEnqueueWriteBuffer(ocl.runtime[0].queue[0], ocl.runtime[0].dev_h_compact1, CL_TRUE, 0,memorySize_h_compact1, h1, 0, NULL, NULL); + AssertFatal(rt == CL_SUCCESS, "Error %d moving h_compact1 memory to pltf %i dev %i\n" , (int)rt, 0,0); + rt = clEnqueueWriteBuffer(ocl.runtime[0].queue[0], ocl.runtime[0].dev_h_compact2, CL_TRUE, 0,memorySize_h_compact2, h2, 0, NULL, NULL); + AssertFatal(rt == CL_SUCCESS, "Error %d moving h_compact2 memory to pltf %i dev %i\n" , (int)rt, 0,0); + // return 0; +} +void cl_error_callback(const char* errinfo, const void* private_info, size_t cb, void* user_data) { + oclruntime_t *runtime = (oclruntime_t *)user_data; + LOG_E(HW,"OpenCL accelerator error %s\n", errinfo ); +} + +char *clutil_getstrdev(int intdev) { + static char retstring[255]=""; + char *retptr=retstring; + retptr+=sprintf(retptr,"0x%08x: ",(uint32_t)intdev); + if (intdev & CL_DEVICE_TYPE_CPU) + retptr+=sprintf(retptr,"%s","cpu "); + if (intdev & CL_DEVICE_TYPE_GPU) + retptr+=sprintf(retptr,"%s","gpu "); + if (intdev & CL_DEVICE_TYPE_ACCELERATOR) + retptr+=sprintf(retptr,"%s","acc "); + return retstring; +} + +void get_CompilErr(cl_program program, int pltf) { + + // Determine the size of the log + size_t log_size; + for(int i=0; i0 , "clGetPlatformIDs: no cl compatible platform found\n"); + for (int i=0 ; i<(int)num_platforms_found ; i++) { + char stringval[255]; + rt = clGetPlatformInfo(platforms[i],CL_PLATFORM_PROFILE, sizeof(stringval),stringval,NULL); + AssertFatal(rt == CL_SUCCESS, "clGetPlatformInfo PROFILE error %d\n" , (int)rt); + LOG_I(HW,"Platform %i, OpenCL profile %s\n", i,stringval ); + rt = clGetPlatformInfo(platforms[i],CL_PLATFORM_VERSION, sizeof(stringval),stringval,NULL); + AssertFatal(rt == CL_SUCCESS, "clGetPlatformInfo VERSION error %d\n" , (int)rt); + LOG_I(HW,"Platform %i, OpenCL version %s\n", i,stringval ); + rt = clGetDeviceIDs(platforms[i],CL_DEVICE_TYPE_ALL, sizeof(ocl.runtime[i].devices)/sizeof(cl_device_id),ocl.runtime[i].devices,&(ocl.runtime[i].num_devices)); + AssertFatal(rt == CL_SUCCESS, "clGetDeviceIDs error %d\n" , (int)rt); + int devok=0; + for (int j=0; j0) { + ocl.runtime[i].context = clCreateContext(NULL, ocl.runtime[i].num_devices, ocl.runtime[i].devices, cl_error_callback, &(ocl.runtime[i]), (cl_int *)&rt); + AssertFatal(rt == CL_SUCCESS, "Error %d creating context for platform %i\n" , (int)rt, i); + for(int dev=0; dev0, "No openCL device available to accelerate ldpc\n"); + return 0; +} + + +void nrLDPC_initcall(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_out) { + set_compact_BG(p_decParams->Z,p_decParams->BG); +// init_LLR_DMA(p_decParams, p_llr, p_out); +} + + +int32_t nrLDPC_decod(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_out,t_nrLDPC_procBuf* p_procBuf, t_nrLDPC_time_stats *time_decoder) +{ + uint16_t Zc = p_decParams->Z; + uint8_t BG = p_decParams->BG; +// uint8_t numMaxIter = p_decParams->numMaxIter; + int block_length = p_decParams->block_length; +// e_nrLDPC_outMode outMode = p_decParams->outMode; + uint8_t row,col; + if(BG == 1){ + row = 46; + col = 68; + } + else{ + row = 42; + col = 52; + } + +// alloc memory +// unsigned char *hard_decision = (unsigned char*)p_out; +// gpu + int memorySize_llr = col * Zc * sizeof(char) * MC; +// cudaCheck( cudaMemcpyToSymbol(dev_const_llr, p_llr, memorySize_llr_cuda) ); +// cudaCheck( cudaMemcpyToSymbol(dev_llr, p_llr, memorySize_llr_cuda) ); + int rt = clEnqueueWriteBuffer(ocl.runtime[0].queue[0], ocl.runtime[0].dev_const_llr, CL_TRUE, 0, + memorySize_llr, p_llr, 0, NULL, NULL); + AssertFatal(rt == CL_SUCCESS, "Error %d moving p_llr data to read only memory in pltf %i dev %i\n" , (int)rt, 0,0); + rt = clEnqueueWriteBuffer(ocl.runtime[0].queue[0], ocl.runtime[0].dev_llr, CL_TRUE, 0, + memorySize_llr, p_llr, 0, NULL, NULL); + AssertFatal(rt == CL_SUCCESS, "Error %d moving p_llr data to read-write memory in pltf %i dev %i\n" , (int)rt, 0,0); +// Define CUDA kernel dimension +// int blockSizeX = Zc; +// dim3 dimGridKernel1(row, MC, 1); // dim of the thread blocks +// dim3 dimBlockKernel1(blockSizeX, 1, 1); + +// dim3 dimGridKernel2(col, MC, 1); +// dim3 dimBlockKernel2(blockSizeX, 1, 1); +// cudaDeviceSynchronize(); + +// lauch kernel + size_t global_item_sizek0[2] = {row*Zc,MC}; // Process the entire lists + size_t global_item_sizek1[2] = {col*Zc,MC}; // Process the entire lists + size_t local_item_sizek[2] = {128,1}; // Divide work items into groups of 128 + + for(int ii = 0; ii < MAX_ITERATION; ii++){ + // first kernel + if(ii == 0){ +// ldpc_cnp_kernel_1st_iter +// <<>> +// ( BG, row, col, Zc); + CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel_1st, 0, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_llr)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel_1st, 1, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_dt)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel_1st, 2, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_h_compact1)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel_1st, 3, sizeof(int), (void *)&(BG)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel_1st, 4, sizeof(int), (void *)&(row)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel_1st, 5, sizeof(int), (void *)&(col)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel_1st, 6, sizeof(int), (void *)&(Zc)); + rt = clEnqueueNDRangeKernel(ocl.runtime[0].queue[0], ocl.runtime[0].kernels[0].cnp_kernel_1st, 2, NULL, + global_item_sizek0, local_item_sizek, 0, NULL, NULL); + AssertFatal(rt == CL_SUCCESS, "Error %d enqueing cnp_kernel_1st \n" , (int)rt); + }else{ +// ldpc_cnp_kernel +// <<>> +// ( BG, row, col, Zc); + CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel, 0, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_llr)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel, 1, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_dt)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel, 2, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_h_compact1)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel, 3, sizeof(int), (void *)&(BG)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel, 4, sizeof(int), (void *)&(row)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel, 5, sizeof(int), (void *)&(col)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel, 6, sizeof(int), (void *)&(Zc)); + rt = clEnqueueNDRangeKernel(ocl.runtime[0].queue[0], ocl.runtime[0].kernels[0].cnp_kernel, 2, NULL, + global_item_sizek0, local_item_sizek, 0, NULL, NULL); + AssertFatal(rt == CL_SUCCESS, "Error %d enqueing cnp_kernel\n" , (int)rt); + } + // second kernel +// ldpc_vnp_kernel_normal +// <<>> +// // (dev_llr, dev_const_llr,BG, row, col, Zc); +// (BG, row, col, Zc); + CLSETKERNELARG(ocl.runtime[0].kernels[0].vnp_kernel_normal, 0, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_llr)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].vnp_kernel_normal, 1, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_dt)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].vnp_kernel_normal, 2, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_const_llr)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].vnp_kernel_normal, 3, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_h_compact2)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].vnp_kernel_normal, 4, sizeof(int), (void *)&(BG)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].vnp_kernel_normal, 5, sizeof(int), (void *)&(row)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].vnp_kernel_normal, 6, sizeof(int), (void *)&(col)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].vnp_kernel_normal, 7, sizeof(int), (void *)&(Zc)); + rt = clEnqueueNDRangeKernel(ocl.runtime[0].queue[0], ocl.runtime[0].kernels[0].vnp_kernel_normal, 2, NULL, + global_item_sizek1, local_item_sizek, 0, NULL, NULL); + AssertFatal(rt == CL_SUCCESS, "Error %d enqueing vnp_kernel_normal \n" , (int)rt); + } + +// int pack = (block_length/128)+1; +// dim3 pack_block(pack, MC, 1); +// pack_decoded_bit<<>>( col, Zc); + CLSETKERNELARG(ocl.runtime[0].kernels[0].pack_decoded_bit, 0, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_llr)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].pack_decoded_bit, 1, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_tmp)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].pack_decoded_bit, 2, sizeof(int), (void *)&(col)); + CLSETKERNELARG(ocl.runtime[0].kernels[0].pack_decoded_bit, 3, sizeof(int), (void *)&(Zc)); + + // Execute the OpenCL kernel on the list + size_t global_item_size[2] = {block_length,MC}; // Process the entire lists + size_t local_item_size[2] = {128,1}; // Divide work items into groups of 128 + rt = clEnqueueNDRangeKernel(ocl.runtime[0].queue[0], ocl.runtime[0].kernels[0].pack_decoded_bit, 2, NULL, + global_item_size, local_item_size, 0, NULL, NULL); + AssertFatal(rt == CL_SUCCESS, "Error %d enqueing pack_decoded_bit \n" , (int)rt); +// cudaCheck( cudaMemcpyFromSymbol((void*)hard_decision, (const void*)dev_tmp, (block_length/8)*sizeof(unsigned char)) ); +// cudaDeviceSynchronize(); + + rt = clEnqueueReadBuffer(ocl.runtime[0].queue[0], ocl.runtime[0].dev_tmp, CL_TRUE, 0, + (block_length/8)*sizeof(unsigned char) , p_llr, 0, NULL, NULL); + AssertFatal(rt == CL_SUCCESS, "Error %d moving p_llr data to pltf %i dev %i\n" , (int)rt, 0,0); + return MAX_ITERATION; + +} diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_kernels_CL.cl b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_kernels_CL.cl new file mode 100644 index 0000000000..d5e2fa5695 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_kernels_CL.cl @@ -0,0 +1,302 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file PHY/CODING/nrLDPC_decoder_kernels_CL.cl +* \brief kernel functions for ldpc decoder accelerated via openCL +* \author Francois TABURET +* \date 2021 +* \version 1.0 +* \company Nokia BellLabs France +* \email: francois.taburet@nokia-bell-labs.com +* \note initial implem - translation of cuda version +* \warning +*/ +#define define MAX_ITERATION 2 +#define MC 1 + +#define INT32_MAX 2147483647 + +typedef struct{ + char x; + char y; + short value; +} h_element; + +//__global char dev_dt [46*68*384]; +//__local char *dev_t; +//__global char dev_llr[68*384]; +//__global unsigned char dev_tmp[68*384]; + + + + +//__constant h_element dev_h_compact1[46*19] = {}; // used in kernel 1 +//__constant h_element dev_h_compact2[68*30] = {}; // used in kernel 2 + +// __device__ __constantant__ h_element dev_h_compact1[46*19]; // used in kernel 1 +// __device__ __constantant__ h_element dev_h_compact2[68*30]; // used in kernel 2 + +// row and col element count +__constant char h_ele_row_bg1_count[46] = { + 19, 19, 19, 19, 3, 8, 9, 7, 10, 9, + 7, 8, 7, 6, 7, 7, 6, 6, 6, 6, + 6, 6, 5, 5, 6, 5, 5, 4, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, + 4, 5, 4, 5, 5, 4}; +__constant char h_ele_col_bg1_count[68] = { + 30, 28, 7, 11, 9, 4, 8, 12, 8, 7, + 12, 10, 12, 11, 10, 7, 10, 10, 13, 7, + 8, 11, 12, 5, 6, 6, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1}; +__constant char h_ele_row_bg2_count[42] = { + 8, 10, 8, 10, 4, 6, 6, 6, 4, 5, + 5, 5, 4, 5, 5, 4, 5, 5, 4, 4, + 4, 4, 3, 4, 4, 3, 5, 3, 4, 3, + 5, 3, 4, 4, 4, 4, 4, 3, 4, 4, + 4, 4}; +__constant char h_ele_col_bg2_count[52] = { + 22, 23, 10, 5, 5, 14, 7, 13, 6, 8, + 9, 16, 9, 12, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1}; + + + +// Kernel 1 +__kernel void ldpc_cnp_kernel_1st_iter( __global char * dev_llr, __global char * dev_dt, __local h_element *dev_h_compact1, int BG, int row, int col, int Zc) +{ +// int iMCW = blockIdx.y; // codeword id +// int iBlkRow = blockIdx.x; // block row in h_base +// int iSubRow = threadIdx.x; // row index in sub_block of h_base +// if(blockIdx.x == 0 && threadIdx.x == 1) printf("cnp %d\n", threadIdx.x); + int iMCW = get_group_id(1); // codeword id + int iBlkRow = get_group_id(0); // block row in h_base + int iBlkCol; // block col in h_base + int iSubRow = get_local_id(0);; // row index in sub_block of h_base + int iCol; // overall col index in h_base + int offsetR; + int shift_t; + +// For 2-min algorithm. + int Q_sign = 0; + int sq; + int Q, Q_abs; + int R_temp; + + int sign = 1; + int rmin1 = INT32_MAX; + int rmin2 = INT32_MAX; + char idx_min = 0; + + h_element h_element_t; + int s = (BG==1)? h_ele_row_bg1_count[iBlkRow]:h_ele_row_bg2_count[iBlkRow]; + offsetR = (iMCW * row*col*Zc) + iBlkRow * Zc + iSubRow; // row*col*Zc = size of dev_dt +// if(blockIdx.x == 0 && threadIdx.x == 1) printf("s: %d, offset %d\n", s, offsetR); +// The 1st recursion + for(int i = 0; i < s; i++) // loop through all the ZxZ sub-blocks in a row + { + h_element_t = dev_h_compact1[i*row+iBlkRow]; // compact_col == row + + iBlkCol = h_element_t.y; + shift_t = h_element_t.value; + + shift_t = (iSubRow + shift_t) % Zc; + iCol = (iMCW * col*Zc) + iBlkCol * Zc + shift_t; // col*Zc = size of llr + Q = dev_llr[iCol]; + Q_abs = (Q>0)? Q : -Q; + sq = Q < 0; +// if(blockIdx.x == 0 && threadIdx.x == 1) printf("i %d, icol %d, Q: %d\n", i, iCol, Q); + // quick version + sign = sign * (1 - sq * 2); + Q_sign |= sq << i; + + if (Q_abs < rmin1){ + rmin2 = rmin1; + rmin1 = Q_abs; + idx_min = i; + } else if (Q_abs < rmin2){ + rmin2 = Q_abs; + } + } + +// if(blockIdx.x == 0 && threadIdx.x == 1)printf("min1 %d, min2 %d, min1_idx %d\n", rmin1, rmin2, idx_min); + +// The 2nd recursion + for(int i = 0; i < s; i++){ + // v0: Best performance so far. 0.75f is the value of alpha. + sq = 1 - 2 * ((Q_sign >> i) & 0x01); + R_temp = 0.75f * sign * sq * (i != idx_min ? rmin1 : rmin2); + // write results to global memory + h_element_t = dev_h_compact1[i*row+iBlkRow]; + int addr_temp = offsetR + h_element_t.y * row * Zc; + dev_dt[addr_temp] = R_temp; +// if(blockIdx.x == 0 && threadIdx.x == 1)printf("R_temp %d, temp_addr %d\n", R_temp, addr_temp); + } +} + +// Kernel_1 +__kernel void ldpc_cnp_kernel( __global char * dev_llr, __global char * dev_dt, __local h_element *dev_h_compact1, int BG, int row, int col, int Zc) +{ +// if(blockIdx.x == 0 && threadIdx.x == 1) printf("cnp\n"); +// int iMCW = blockIdx.y; +// int iBlkRow = blockIdx.x; // block row in h_base // block col in h_base +// int iSubRow = threadIdx.x; // row index in sub_block of h_base + int iMCW = get_group_id(1); + int iBlkRow = get_group_id(0); // block row in h_base + int iBlkCol; // block col in h_base + int iSubRow = get_local_id(0);; // row index in sub_block of h_base + int iCol; // overall col index in h_base + int offsetR; + int shift_t; + +// For 2-min algorithm. + int Q_sign = 0; + int sq; + int Q, Q_abs; + int R_temp; + + int sign = 1; + int rmin1 = INT32_MAX; + int rmin2 = INT32_MAX; + char idx_min = 0; + + h_element h_element_t; + int s = (BG==1)? h_ele_row_bg1_count[iBlkRow]: h_ele_row_bg2_count[iBlkRow]; + offsetR = (iMCW *row*col*Zc) + iBlkRow * Zc + iSubRow; // row * col * Zc = size of dev_dt +// if(blockIdx.x == 0 && threadIdx.x == 1) printf("s: %d, offset %d\n", s, offsetR); +// The 1st recursion + for(int i = 0; i < s; i++) // loop through all the ZxZ sub-blocks in a row + { + h_element_t = dev_h_compact1[i*row+iBlkRow]; + + iBlkCol = h_element_t.y; + shift_t = h_element_t.value; + shift_t = (iSubRow + shift_t) % Zc; + iCol = iBlkCol * Zc + shift_t; + + R_temp = dev_dt[offsetR + iBlkCol * row * Zc]; + + Q = dev_llr[iMCW * (col*Zc) + iCol] - R_temp; + Q_abs = (Q>0)? Q : -Q; +// if(blockIdx.x == 0 && threadIdx.x == 1) printf("i %d, icol %d, Q: %d\n", i, iCol, Q); + sq = Q < 0; + sign = sign * (1 - sq * 2); + Q_sign |= sq << i; + + if (Q_abs < rmin1){ + rmin2 = rmin1; + rmin1 = Q_abs; + idx_min = i; + } else if (Q_abs < rmin2){ + rmin2 = Q_abs; + } + + } + +// if(blockIdx.x == 0 && threadIdx.x == 1)printf("min1 %d, min2 %d, min1_idx %d\n", rmin1, rmin2, idx_min); + +// The 2nd recursion + for(int i = 0; i < s; i ++){ + sq = 1 - 2 * ((Q_sign >> i) & 0x01); + R_temp = 0.75f * sign * sq * (i != idx_min ? rmin1 : rmin2); + + + // write results to global memory + h_element_t = dev_h_compact1[i*row+iBlkRow]; + int addr_temp = h_element_t.y * row * Zc + offsetR; + dev_dt[addr_temp] = R_temp; +// if(blockIdx.x == 0 && threadIdx.x == 1)printf("R_temp %d, temp_addr %d\n", R_temp, addr_temp); + } +} + +// Kernel 2: VNP processing +__kernel void +ldpc_vnp_kernel_normal(__global char * dev_llr, __global char * dev_dt, __global char * dev_const_llr, __local h_element *dev_h_compact2, int BG, int row, int col, int Zc) +{ +// int iMCW = blockIdx.y; +// int iBlkCol = blockIdx.x; +// int iSubCol = threadIdx.x; + int iMCW = get_group_id(1); + int iBlkCol = get_group_id(0); + int iBlkRow; + int iSubCol = get_local_id(0); + int iRow; + int iCol; + + int shift_t, sf; + int APP; + + h_element h_element_t; + + // update all the llr values + iCol = iBlkCol * Zc + iSubCol; + APP = dev_const_llr[iMCW *col*Zc + iCol]; + int offsetDt = iMCW *row*col*Zc + iBlkCol * row * Zc; + int s = (BG==1)? h_ele_col_bg1_count[iBlkCol]:h_ele_col_bg2_count[iBlkCol]; + + for(int i = 0; i < s; i++) + { + h_element_t = dev_h_compact2[i*col+iBlkCol]; + + shift_t = h_element_t.value%Zc; + iBlkRow = h_element_t.x; + + sf = iSubCol - shift_t; + sf = (sf + Zc) % Zc; + + iRow = iBlkRow * Zc + sf; + APP = APP + dev_dt[offsetDt + iRow]; + } + if(APP > SCHAR_MAX) APP = SCHAR_MAX; + if(APP < SCHAR_MIN) APP = SCHAR_MIN; + // write back to device global memory + dev_llr[iMCW *col*Zc + iCol] = APP; +} + + +__kernel void pack_decoded_bit(__global unsigned char * dev_llr, __global unsigned char * dev_tmp, int col, int Zc) +{ +// int iMCW = blockIdx.y; +// int btid = threadIdx.x; + unsigned char tmp[128]; + int iMCW = get_group_id(1); + int btid = get_local_id(0); + int tid = iMCW * col*Zc + get_group_id(0)*128 + btid; + tmp[btid] = 0; + + if(dev_llr[tid] < 0){ + tmp[btid] = 1 << (7-(btid&7)); + } +// __syncthreads(); + + if(btid < 16){ + dev_tmp[iMCW * col*Zc + get_group_id(0)*16+btid] = 0; + for(int i = 0; i < 8; i++){ + dev_tmp[iMCW * col*Zc + get_group_id(0)*16+btid] += tmp[btid*8+i]; + } + } +} + diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h index e5b99246d5..99b6f75f93 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_types.h @@ -70,6 +70,7 @@ typedef struct nrLDPC_dec_params { uint16_t Z; /**< Lifting size */ uint8_t R; /**< Decoding rate: Format 15,13,... for code rates 1/5, 1/3,... */ uint8_t numMaxIter; /**< Maximum number of iterations */ + int block_length; e_nrLDPC_outMode outMode; /**< Output format */ } t_nrLDPC_dec_params; diff --git a/openair1/PHY/CODING/nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu b/openair1/PHY/CODING/nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu index 931d500338..72517edcdd 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu +++ b/openair1/PHY/CODING/nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu @@ -7,14 +7,14 @@ * \note * \warning */ - +#include #include #include #include #include #include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h" #include "PHY/CODING/nrLDPC_decoder/nrLDPCdecoder_defs.h" - +#include "assertions.h" #include "bgs/BG1_I0" #include "bgs/BG1_I1" #include "bgs/BG1_I2" @@ -462,10 +462,11 @@ void read_BG(int BG, int *h, int row, int col) } extern "C" -void init_LLR_DMA_for_CUDA(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_out, int block_length){ +void init_LLR_DMA(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_out){ uint16_t Zc = p_decParams->Z; uint8_t BG = p_decParams->BG; + int block_length = p_decParams->block_length; uint8_t row,col; if(BG == 1){ row = 46; @@ -483,14 +484,60 @@ void init_LLR_DMA_for_CUDA(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8 } +using namespace std ; + +/* from here: entry points in decoder shared lib */ extern "C" -int32_t nrLDPC_decoder_LYC(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_out, int block_length, time_stats_t *time_decoder) +int ldpc_autoinit(void) { // called by the library loader +/*int devices = 0; + + cudaError_t err = cudaGetDeviceCount(&devices); + AssertFatal(devices>0,"\nNo cuda GPU found\n\n"); + + const int kb = 1024; + const int mb = kb * kb; + wcout << "NBody.GPU" << endl << "=========" << endl << endl; + + wcout << "CUDA version: v" << CUDART_VERSION << endl; + + + wcout << "CUDA Devices: " << endl << endl; + + for(int i = 0; i < devices; ++i) + { + cudaDeviceProp props; + cudaGetDeviceProperties(&props, i); + wcout << i << ": " << props.name << ": " << props.major << "." << props.minor << endl; + wcout << " Global memory: " << props.totalGlobalMem / mb << "mb" << endl; + wcout << " Shared memory: " << props.sharedMemPerBlock / kb << "kb" << endl; + wcout << " Constant memory: " << props.totalConstMem / kb << "kb" << endl; + wcout << " Block registers: " << props.regsPerBlock << endl << endl; + + wcout << " Warp size: " << props.warpSize << endl; + wcout << " Threads per block: " << props.maxThreadsPerBlock << endl; + wcout << " Max block dimensions: [ " << props.maxThreadsDim[0] << ", " << props.maxThreadsDim[1] << ", " << props.maxThreadsDim[2] << " ]" << endl; + wcout << " Max grid dimensions: [ " << props.maxGridSize[0] << ", " << props.maxGridSize[1] << ", " << props.maxGridSize[2] << " ]" << endl; + wcout << endl; + } +*/ + warmup_for_GPU(); + return 0; +} + +extern "C" +void nrLDPC_initcall(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_out) { + set_compact_BG(p_decParams->Z,p_decParams->BG); + init_LLR_DMA(p_decParams, p_llr, p_out); +} + + +extern "C" +int32_t nrLDPC_decod(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_out,t_nrLDPC_procBuf* p_procBuf, t_nrLDPC_time_stats *time_decoder) { - - uint16_t Zc = p_decParams->Z; uint8_t BG = p_decParams->BG; uint8_t numMaxIter = p_decParams->numMaxIter; + int block_length = p_decParams->block_length; e_nrLDPC_outMode outMode = p_decParams->outMode; cudaError_t cudaStatus; uint8_t row,col; diff --git a/openair1/PHY/CODING/nrLDPC_defs.h b/openair1/PHY/CODING/nrLDPC_defs.h index b96067f4b6..321ecaab7d 100644 --- a/openair1/PHY/CODING/nrLDPC_defs.h +++ b/openair1/PHY/CODING/nrLDPC_defs.h @@ -45,6 +45,7 @@ typedef struct { time_stats_t *toutput; }encoder_implemparams_t; #define INIT0_LDPCIMPLEMPARAMS {0,0,0,NULL,NULL,NULL,NULL} +typedef void(*nrLDPC_initcallfunc_t)(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_out); typedef int(*nrLDPC_encoderfunc_t)(unsigned char **,unsigned char **,int,int,short, short, encoder_implemparams_t*); //============================================================================================================================ // decoder interface @@ -56,4 +57,4 @@ typedef int(*nrLDPC_encoderfunc_t)(unsigned char **,unsigned char **,int,int,sho \param p_profiler LDPC profiler statistics */ typedef int32_t(*nrLDPC_decoderfunc_t)(t_nrLDPC_dec_params* , int8_t*, int8_t* , t_nrLDPC_procBuf* , t_nrLDPC_time_stats* ); -#endif \ No newline at end of file +#endif diff --git a/openair1/PHY/CODING/nrLDPC_extern.h b/openair1/PHY/CODING/nrLDPC_extern.h index c0bfa0fdd8..b75b38fc76 100644 --- a/openair1/PHY/CODING/nrLDPC_extern.h +++ b/openair1/PHY/CODING/nrLDPC_extern.h @@ -23,13 +23,16 @@ #ifdef LDPC_LOADER nrLDPC_decoderfunc_t nrLDPC_decoder; nrLDPC_encoderfunc_t nrLDPC_encoder; +nrLDPC_initcallfunc_t nrLDPC_initcall; #else /* functions to load the LDPC shared lib, implemented in openair1/PHY/CODING/nrLDPC_load.c */ -extern int load_nrLDPClib(void) ; +extern int load_nrLDPClib(char *version) ; extern int load_nrLDPClib_ref(char *libversion, nrLDPC_encoderfunc_t * nrLDPC_encoder_ptr); // for ldpctest /* ldpc coder/decoder functions, as loaded by load_nrLDPClib(). */ +extern nrLDPC_initcallfunc_t nrLDPC_initcall; + extern nrLDPC_decoderfunc_t nrLDPC_decoder; extern nrLDPC_encoderfunc_t nrLDPC_encoder; // inline functions: #include "openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init_mem.h" -#endif \ No newline at end of file +#endif diff --git a/openair1/PHY/CODING/nrLDPC_load.c b/openair1/PHY/CODING/nrLDPC_load.c index a74bdf7bd1..23e5032bad 100644 --- a/openair1/PHY/CODING/nrLDPC_load.c +++ b/openair1/PHY/CODING/nrLDPC_load.c @@ -42,22 +42,32 @@ /* function description array, to be used when loading the encoding/decoding shared lib */ -static loader_shlibfunc_t shlib_fdesc[2]; +static loader_shlibfunc_t shlib_fdesc[3]; -char *arg[64]={"ldpctest","-O","cmdlineonly::dbgl0"}; +/* arguments used when called from phy simulators exec's which do not use the config module */ +/* arg is used to initialize the config module so that the loader works as expected */ +char *arg[64]={"ldpctest","-O","cmdlineonly::dbgl0",NULL,NULL}; -int load_nrLDPClib(void) { +int load_nrLDPClib(char *version) { char *ptr = (char*)config_get_if(); + char libname[64]="ldpc"; + if ( ptr==NULL ) {// phy simulators, config module possibly not loaded - load_configmodule(3,(char **)arg,CONFIG_ENABLECMDLINEONLY) ; + load_configmodule(0,(char **)NULL,CONFIG_ENABLECMDLINEONLY) ; logInit(); } shlib_fdesc[0].fname = "nrLDPC_decod"; shlib_fdesc[1].fname = "nrLDPC_encod"; - int ret=load_module_shlib("ldpc",shlib_fdesc,sizeof(shlib_fdesc)/sizeof(loader_shlibfunc_t),NULL); + shlib_fdesc[2].fname = "nrLDPC_initcall"; + int ret; + if (version) + ret=load_module_version_shlib(libname,version,shlib_fdesc,sizeof(shlib_fdesc)/sizeof(loader_shlibfunc_t),NULL); + else + ret=load_module_shlib(libname,shlib_fdesc,sizeof(shlib_fdesc)/sizeof(loader_shlibfunc_t),NULL); AssertFatal( (ret >= 0),"Error loading ldpc decoder"); nrLDPC_decoder = (nrLDPC_decoderfunc_t)shlib_fdesc[0].fptr; nrLDPC_encoder = (nrLDPC_encoderfunc_t)shlib_fdesc[1].fptr; + nrLDPC_initcall = (nrLDPC_initcallfunc_t)shlib_fdesc[2].fptr; return 0; } @@ -65,10 +75,8 @@ int load_nrLDPClib_ref(char *libversion, nrLDPC_encoderfunc_t * nrLDPC_encoder_p loader_shlibfunc_t shlib_encoder_fdesc; shlib_encoder_fdesc.fname = "nrLDPC_encod"; - char libpath[64]; - sprintf(libpath,"ldpc%s",libversion); - int ret=load_module_shlib(libpath,&shlib_encoder_fdesc,1,NULL); - AssertFatal( (ret >= 0),"Error loading ldpc encoder %s\n",libpath); + int ret=load_module_version_shlib("ldpc",libversion,&shlib_encoder_fdesc,1,NULL); + AssertFatal( (ret >= 0),"Error loading ldpc encoder %s\n",(libversion==NULL)?"":libversion); *nrLDPC_encoder_ptr = (nrLDPC_encoderfunc_t)shlib_encoder_fdesc.fptr; return 0; } diff --git a/openair1/PHY/CODING/nrPolar_tools/nr_polar_encoder.c b/openair1/PHY/CODING/nrPolar_tools/nr_polar_encoder.c index e61b3dff9b..1dfaed8b94 100644 --- a/openair1/PHY/CODING/nrPolar_tools/nr_polar_encoder.c +++ b/openair1/PHY/CODING/nrPolar_tools/nr_polar_encoder.c @@ -258,10 +258,11 @@ static inline void polar_rate_matching(const t_nrPolar_params *polarParams,void // handle rate matching with a single 128 bit word using bit shuffling // can be done with SIMD intrisics if needed if (polarParams->groupsize < 8) { - AssertFatal(polarParams->encoderLength<=128,"Need to handle groupsize<8 and N>128\n"); + AssertFatal(polarParams->encoderLength<=512,"Need to handle groupsize(%d)<8 and N(%d)>512\n",polarParams->groupsize,polarParams->encoderLength); uint128_t *out128=(uint128_t*)out; uint128_t *in128=(uint128_t*)in; - *out128=0; + for (int i=0;iencoderLength>>7;i++) + out128[i]=0; uint128_t tmp0; #ifdef DEBUG_POLAR_ENCODER uint128_t tmp1; @@ -270,15 +271,21 @@ static inline void polar_rate_matching(const t_nrPolar_params *polarParams,void #ifdef DEBUG_POLAR_ENCODER printf("%d<-%u : %llx.%llx =>",i,polarParams->rate_matching_pattern[i],((uint64_t *)out)[1],((uint64_t *)out)[0]); #endif - tmp0 = (*in128&(((uint128_t)1)<rate_matching_pattern[i])); + uint8_t pi=polarParams->rate_matching_pattern[i]; + uint8_t pi7=pi>>7; + uint8_t pimod128=pi&127; + uint8_t imod128=i&127; + uint8_t i7=i>>7; + + tmp0 = (in128[pi7]&(((uint128_t)1)<<(pimod128))); + if (tmp0!=0) { - *out128 = *out128 | ((uint128_t)1)<%llx.%llx => %llx.%llx\n", - ((uint64_t *)&tmp0)[1],((uint64_t *)&tmp0)[0], - ((uint64_t *)&tmp1)[1],((uint64_t *)&tmp1)[0], - ((uint64_t *)out)[1],((uint64_t *)out)[0]); + printf("%llx.%llx<->%llx.%llx => %llx.%llx\n", + ((uint64_t *)&tmp0)[1],((uint64_t *)&tmp0)[0], + ((uint64_t *)&tmp1)[1],((uint64_t *)&tmp1)[0], + ((uint64_t *)out)[1],((uint64_t *)out)[0]); #endif } } diff --git a/openair1/PHY/CODING/nr_segmentation.c b/openair1/PHY/CODING/nr_segmentation.c index 1d80a83131..0eede23766 100644 --- a/openair1/PHY/CODING/nr_segmentation.c +++ b/openair1/PHY/CODING/nr_segmentation.c @@ -92,9 +92,7 @@ if ((Kprime%Kb) > 0) else Z = (Kprime/Kb); -#ifdef DEBUG_SEGMENTATION - printf("nr segmetation B %u Bprime %u Kprime %u z %u \n", B, Bprime, Kprime, Z); -#endif + LOG_D(PHY,"nr segmetation B %u Bprime %u Kprime %u z %u \n", B, Bprime, Kprime, Z); if (Z <= 2) { *K = 2; @@ -148,10 +146,8 @@ else *F = ((*K) - Kprime); -#ifdef DEBUG_SEGMENTATION - printf("final nr seg output Z %u K %u F %u \n", *Zout, *K, *F); - printf("C %u, K %u, Bprime_bytes %u, Bprime %u, F %u\n",*C,*K,Bprime>>3,Bprime,*F); -#endif + LOG_D(PHY,"final nr seg output Z %u K %u F %u \n", *Zout, *K, *F); + LOG_D(PHY,"C %u, K %u, Bprime_bytes %u, Bprime %u, F %u\n",*C,*K,Bprime>>3,Bprime,*F); if ((input_buffer) && (output_buffers)) { diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 32e190679d..cd4848ea8c 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -21,6 +21,7 @@ #include "executables/nr-softmodem-common.h" #include "common/utils/nr/nr_common.h" +#include "common/ran_context.h" #include "PHY/defs_gNB.h" #include "PHY/phy_extern.h" #include "PHY/NR_REFSIG/nr_refsig.h" @@ -35,7 +36,6 @@ #include "MBSFN-SubframeConfigList.h"*/ #include "openair1/PHY/defs_RU.h" #include "openair1/PHY/CODING/nrLDPC_extern.h" -#include "LAYER2/NR_MAC_gNB/mac_proto.h" #include "assertions.h" #include @@ -108,7 +108,7 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, crcTableInit(); init_scrambling_luts(); init_pucch2_luts(); - load_nrLDPClib(); + load_nrLDPClib(NULL); // PBCH DMRS gold sequences generation nr_init_pbch_dmrs(gNB); //PDCCH DMRS init @@ -124,6 +124,7 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, for (int symb=0; symbsymbols_per_slot; symb++) { pdcch_dmrs[slot][symb] = (uint32_t *)malloc16(NR_MAX_PDCCH_DMRS_INIT_LENGTH_DWORD*sizeof(uint32_t)); + LOG_D(PHY,"pdcch_dmrs[%d][%d] %p\n",slot,symb,pdcch_dmrs[slot][symb]); AssertFatal(pdcch_dmrs[slot][symb]!=NULL, "NR init: pdcch_dmrs for slot %d symbol %d - malloc failed\n", slot, symb); } } @@ -518,45 +519,38 @@ void nr_phy_config_request(NR_PHY_Config_t *phy_config) { LOG_I(PHY,"gNB %d configured\n",Mod_id); } - -void init_nr_transport(PHY_VARS_gNB *gNB) { - int i; - int j; +void init_DLSCH_struct(PHY_VARS_gNB *gNB, processingData_L1tx_t *msg) { NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; - LOG_I(PHY, "Initialise nr transport\n"); uint16_t grid_size = cfg->carrier_config.dl_grid_size[fp->numerology_index].value; + msg->num_pdsch_slot = 0; + + for (int i=0; inumber_of_nr_dlsch_max; i++) { + LOG_I(PHY,"Allocating Transport Channel Buffers for DLSCH %d/%d\n",i,gNB->number_of_nr_dlsch_max); + for (int j=0; j<2; j++) { + msg->dlsch[i][j] = new_gNB_dlsch(fp,1,16,NSOFT,0,grid_size); + AssertFatal(msg->dlsch[i][j]!=NULL,"Can't initialize dlsch %d \n", i); + } + } +} + +void init_nr_transport(PHY_VARS_gNB *gNB) { + NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; + LOG_I(PHY, "Initialise nr transport\n"); memset(gNB->num_pdsch_rnti, 0, sizeof(uint16_t)*80); - for (i=0; i pdcch_pdu[i].frame=-1; - LOG_I(PHY,"Initializing UL PDCCH list for UL PDCCH %d/%d\n",i,NUMBER_OF_NR_PDCCH_MAX); - gNB->ul_pdcch_pdu[i].frame=-1; - } - - for (i=0; ipucch[i] = new_gNB_pucch(); AssertFatal(gNB->pucch[i]!=NULL,"Can't initialize pucch %d \n", i); } - for (i=0; inumber_of_nr_dlsch_max; i++) { - - LOG_I(PHY,"Allocating Transport Channel Buffers for DLSCH %d/%d\n",i,gNB->number_of_nr_dlsch_max); - - for (j=0; j<2; j++) { - gNB->dlsch[i][j] = new_gNB_dlsch(fp,1,16,NSOFT,0,grid_size); - AssertFatal(gNB->dlsch[i][j]!=NULL,"Can't initialize dlsch %d \n", i); - } - } - - for (i=0; inumber_of_nr_ulsch_max; i++) { + for (int i=0; inumber_of_nr_ulsch_max; i++) { LOG_I(PHY,"Allocating Transport Channel Buffer for ULSCH %d/%d\n",i,gNB->number_of_nr_ulsch_max); - for (j=0; j<2; j++) { + for (int j=0; j<2; j++) { // ULSCH for data gNB->ulsch[i][j] = new_gNB_ulsch(MAX_LDPC_ITERATIONS, fp->N_RB_UL, 0); diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index 097c2b3ad2..4024ed1617 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -60,10 +60,12 @@ int nr_phy_init_RU(RU_t *ru) { for (i=0; inb_tx; i++) { // Allocate 10 subframes of I/Q TX signal data (time) if not - ru->common.txdata[i] = (int32_t*)malloc16_clear( fp->samples_per_frame*sizeof(int32_t) ); + ru->common.txdata[i] = (int32_t*)malloc16_clear( ru->sf_extension + (fp->samples_per_frame*sizeof(int32_t) )); + LOG_I(PHY,"[INIT] common.txdata[%d] = %p (%lu bytes,sf_extension %d)\n",i,ru->common.txdata[i], + (ru->sf_extension + fp->samples_per_frame)*sizeof(int32_t),ru->sf_extension); + ru->common.txdata[i] = &ru->common.txdata[i][ru->sf_extension]; - LOG_I(PHY,"[INIT] common.txdata[%d] = %p (%lu bytes)\n",i,ru->common.txdata[i], - fp->samples_per_frame*sizeof(int32_t)); + LOG_I(PHY,"[INIT] common.txdata[%d] = %p \n",i,ru->common.txdata[i]); } for (i=0;inb_rx;i++) { @@ -100,8 +102,8 @@ int nr_phy_init_RU(RU_t *ru) { // allocate FFT output buffers (RX) ru->common.rxdataF = (int32_t**)malloc16(ru->nb_rx*sizeof(int32_t*) ); for (i=0; inb_rx; i++) { - // allocate 2 subframes of I/Q signal data (frequency) - ru->common.rxdataF[i] = (int32_t*)malloc16_clear(sizeof(int32_t)*(2*fp->samples_per_subframe_wCP) ); + // allocate 4 slots of I/Q signal data (frequency) + ru->common.rxdataF[i] = (int32_t*)malloc16_clear(sizeof(int32_t)*(4*fp->symbols_per_slot*fp->ofdm_symbol_size) ); LOG_I(PHY,"rxdataF[%d] %p for RU %d\n",i,ru->common.rxdataF[i],ru->idx); } @@ -176,7 +178,11 @@ void nr_phy_free_RU(RU_t *ru) free_and_zero(ru->frame_parms); if (ru->if_south <= REMOTE_IF5) { // this means REMOTE_IF5 or LOCAL_RF, so free memory for time-domain signals - for (i = 0; i < ru->nb_tx; i++) free_and_zero(ru->common.txdata[i]); + int32_t *ptr; + for (i = 0; i < ru->nb_tx; i++) { + ptr=&ru->common.txdata[i][-ru->sf_extension]; + free_and_zero(ptr); + } for (i = 0; i < ru->nb_rx; i++) free_and_zero(ru->common.rxdata[i]); free_and_zero(ru->common.txdata); free_and_zero(ru->common.rxdata); diff --git a/openair1/PHY/INIT/nr_parms.c b/openair1/PHY/INIT/nr_parms.c index 98e3c5a1a3..0920da667d 100644 --- a/openair1/PHY/INIT/nr_parms.c +++ b/openair1/PHY/INIT/nr_parms.c @@ -22,7 +22,6 @@ #include "phy_init.h" #include "common/utils/nr/nr_common.h" #include "common/utils/LOG/log.h" -#include "LAYER2/NR_MAC_gNB/mac_proto.h" /// Subcarrier spacings in Hz indexed by numerology index uint32_t nr_subcarrier_spacing[MAX_NUM_SUBCARRIER_SPACING] = {15e3, 30e3, 60e3, 120e3, 240e3}; @@ -102,7 +101,7 @@ void set_scs_parameters (NR_DL_FRAME_PARMS *fp, int mu, int N_RB_DL) if (fp->nr_band == 5 || fp->nr_band == 66) fp->ssb_type = nr_ssb_type_B; else{ - if (fp->nr_band == 41 || ( fp->nr_band > 76 && fp->nr_band < 80) ) + if (fp->nr_band == 41 || fp->nr_band == 38 || ( fp->nr_band > 76 && fp->nr_band < 80) ) fp->ssb_type = nr_ssb_type_C; else AssertFatal(1==0,"NR Operating Band n%d not available for SS block SCS with mu=%d\n", fp->nr_band, mu); @@ -141,6 +140,8 @@ void set_scs_parameters (NR_DL_FRAME_PARMS *fp, int mu, int N_RB_DL) fp->first_carrier_offset = fp->ofdm_symbol_size - (N_RB_DL * 12 / 2); fp->nb_prefix_samples = fp->ofdm_symbol_size / 128 * 9; fp->nb_prefix_samples0 = fp->ofdm_symbol_size / 128 * (9 + (1 << mu)); + LOG_I(PHY,"Init: N_RB_DL %d, first_carrier_offset %d, nb_prefix_samples %d,nb_prefix_samples0 %d\n", + N_RB_DL,fp->first_carrier_offset,fp->nb_prefix_samples,fp->nb_prefix_samples0); } uint32_t get_samples_per_slot(int slot, NR_DL_FRAME_PARMS* fp) diff --git a/openair1/PHY/INIT/phy_init.h b/openair1/PHY/INIT/phy_init.h index 85101a3080..dd9232de83 100644 --- a/openair1/PHY/INIT/phy_init.h +++ b/openair1/PHY/INIT/phy_init.h @@ -409,6 +409,7 @@ void init_nr_transport(PHY_VARS_gNB *gNB); void init_dfts(void); void fill_subframe_mask(PHY_VARS_eNB *eNB); +void init_DLSCH_struct(PHY_VARS_gNB *gNB, processingData_L1tx_t *msg); /** @} */ #endif diff --git a/openair1/PHY/LTE_TRANSPORT/if5_tools.c b/openair1/PHY/LTE_TRANSPORT/if5_tools.c index e2bec337aa..86723d0fed 100644 --- a/openair1/PHY/LTE_TRANSPORT/if5_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/if5_tools.c @@ -31,15 +31,14 @@ */ #include +#include "PHY/defs_eNB.h" +#include "PHY/defs_gNB.h" #include #include "PHY/defs_RU.h" #include "PHY/TOOLS/alaw_lut.h" //#include "targets/ARCH/ETHERNET/USERSPACE/LIB/if_defs.h" #include "targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h" #include "common/utils/LOG/vcd_signal_dumper.h" -//#define DEBUG_DL_MOBIPASS -//#define DEBUG_UL_MOBIPASS -#define SUBFRAME_SKIP_NUM_MOBIPASS 8 const uint8_t lin2alaw_if5[65536] = {213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, @@ -1050,18 +1049,12 @@ static inline int64_t clock_difftime_ns(struct timespec start, struct timespec e return temp_ns; } -void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int subframe, uint8_t *seqno, uint16_t packet_type) { +void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int tti, uint8_t *seqno, uint16_t packet_type) { LTE_DL_FRAME_PARMS *fp=ru->frame_parms; int32_t *txp[fp->nb_antennas_tx], *rxp[fp->nb_antennas_rx]; int32_t *tx_buffer=NULL; -#ifdef DEBUG_DL_MOBIPASS - int8_t dummy_buffer[fp->samples_per_tti*2]; -#endif - void *alaw_buffer = ru->ifbuffer.tx[subframe&1]; - uint16_t *data_block = NULL; - uint16_t *j = NULL; - uint16_t packet_id=0, i=0, element_id=0; + uint16_t packet_id=0, i=0; uint32_t spp_eth = (uint32_t) ru->ifdevice.openair0_cfg->samples_per_packet; uint32_t spsf = (uint32_t) ru->ifdevice.openair0_cfg->samples_per_frame/10; @@ -1072,6 +1065,12 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int subframe, uint8_t if (eth->compression == ALAW_COMPRESS) { AssertFatal(1==0,"IF5 compression needs reworking\n"); /* + void *alaw_buffer = ru->ifbuffer.tx[subframe&1]; + int element_id=0; + + uint16_t *data_block = NULL; + uint16_t *j = NULL; + if (eth->flags == ETH_RAW_MODE) { data_block = (uint16_t*)(alaw_buffer + APP_HEADER_SIZE_BYTES + MAC_HEADER_SIZE_BYTES); } else { @@ -1105,10 +1104,22 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int subframe, uint8_t */ } else if (eth->compression == NO_COMPRESS) { + NR_DL_FRAME_PARMS *nrfp = ru->nr_frame_parms; + + int offset,siglen; + if (nrfp) { + offset = nrfp->get_samples_slot_timestamp(tti,nrfp,0); + siglen = nrfp->get_samples_per_slot(tti,nrfp); + } + else { + offset = tti*fp->samples_per_subframe; + siglen = spsf; + } + for (i=0; i < ru->nb_tx; i++) - txp[i] = (int32_t*)&ru->common.txdata[i][subframe*fp->samples_per_tti]; + txp[i] = (int32_t*)&ru->common.txdata[i][offset]; - for (packet_id=0; packet_id < spsf / spp_eth; packet_id++) { + for (packet_id=0; packet_id < siglen / spp_eth; packet_id++) { for (int aid=0; aidnb_tx;aid++) { //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF5_PKT_ID, packet_id ); //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 1 ); @@ -1119,9 +1130,9 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int subframe, uint8_t spp_eth, aid, 0); - LOG_D(HW,"SF %d : packet %d, TS %llu\n",subframe,packet_id,(unsigned long long)(proc_timestamp+packet_id*spp_eth)); + LOG_D(HW,"TTI %d : packet %d, TS %llu\n",tti,packet_id,(unsigned long long)(proc_timestamp-ru->ts_offset+packet_id*spp_eth)); clock_gettime( CLOCK_MONOTONIC, &end_comp); - LOG_D(HW,"[SF %d] IF_Write_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_comp, end_comp)); + LOG_D(HW,"[TTI %d] IF_Write_Time: %"PRId64"\n",tti,clock_difftime_ns(start_comp, end_comp)); //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 0 ); txp[aid] += spp_eth; @@ -1130,7 +1141,8 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int subframe, uint8_t } } else if (packet_type == IF5_RRH_GW_UL) { if (eth->compression == ALAW_COMPRESS) { - if (eth->flags == ETH_RAW_MODE) { + AssertFatal(1==0,"ALAW IF5 requires work\n"); + /* if (eth->flags == ETH_RAW_MODE) { data_block = (uint16_t*)(alaw_buffer + APP_HEADER_SIZE_BYTES + MAC_HEADER_SIZE_BYTES); } else { data_block = (uint16_t*)(alaw_buffer + APP_HEADER_SIZE_BYTES); @@ -1160,9 +1172,10 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int subframe, uint8_t LOG_D(HW,"[SF %d] IF_Write_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_comp, end_comp)); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 0 ); } +*/ } else if (eth->compression == NO_COMPRESS) { for (i=0; i < fp->nb_antennas_rx; i++) - rxp[i] = (void*)&ru->common.rxdata[i][subframe*fp->samples_per_tti]; + rxp[i] = (void*)&ru->common.rxdata[i][tti*fp->samples_per_tti]; for (packet_id=0; packet_id < spsf / spp_eth; packet_id++) { VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF5_PKT_ID, packet_id ); @@ -1175,153 +1188,28 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int subframe, uint8_t fp->nb_antennas_rx, 0); clock_gettime( CLOCK_MONOTONIC, &end_comp); - LOG_D(HW,"[SF %d] IF_Write_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_comp, end_comp)); + LOG_D(HW,"[SF %d] IF_Write_Time: %"PRId64"\n",tti,clock_difftime_ns(start_comp, end_comp)); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 0 ); for (i=0; i < fp->nb_antennas_rx; i++) rxp[i] += spp_eth; } } - } else if (packet_type == IF5_MOBIPASS) { - /* the only difference between mobipass standalone and the other one - * is the timestamp in trx_write_func, but let's duplicate anyway - * (plus we don't call malloc for the standalone case) - */ - if (ru->if_timing == synch_to_mobipass_standalone) { - uint16_t db_fulllength = PAYLOAD_MOBIPASS_NUM_SAMPLES; - - __m128i *data_block=NULL, *data_block_head=NULL; - __m128i *txp128; - __m128i t0, t1; - - unsigned char _tx_buffer[MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t)]; - tx_buffer=(int32_t *)_tx_buffer; - - IF5_mobipass_header_t *header = (IF5_mobipass_header_t *)((uint8_t *)tx_buffer + MAC_HEADER_SIZE_BYTES); - data_block_head = (__m128i *)((uint8_t *)tx_buffer + MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t); - - header->flags = 0; - header->fifo_status = 0; - header->seqno = *seqno; - header->ack = 0; - header->word0 = 0; - - txp[0] = (void*)&ru->common.txdata[0][subframe*ru->frame_parms->samples_per_tti]; - txp128 = (__m128i *) txp[0]; - - for (packet_id=0; packet_idsamples_per_tti/db_fulllength; packet_id++) { - header->time_stamp = htonl((uint32_t)(proc_timestamp + packet_id*db_fulllength)); - data_block = data_block_head; - - for (i=0; i>2; i+=2) { - t0 = _mm_srai_epi16(*txp128++, 4); - t1 = _mm_srai_epi16(*txp128++, 4); - _mm_storeu_si128(data_block++, _mm_packs_epi16(t0, t1)); - } - - // Write the packet to the fronthaul - if ((ru->ifdevice.trx_write_func(&ru->ifdevice, - proc_timestamp + packet_id*db_fulllength, - (void**)&tx_buffer, - db_fulllength, - 1, - IF5_MOBIPASS)) < 0) { - perror("ETHERNET write for IF5_MOBIPASS\n"); - } - header->seqno += 1; - } - *seqno = header->seqno; - tx_buffer = NULL; - } else { - uint16_t db_fulllength = PAYLOAD_MOBIPASS_NUM_SAMPLES; - - __m128i *data_block=NULL, *data_block_head=NULL; - - __m128i *txp128; - __m128i t0, t1; - - // tx_buffer = memalign(16, MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t)); - tx_buffer = malloc(MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t)); - IF5_mobipass_header_t *header = (IF5_mobipass_header_t *)((uint8_t *)tx_buffer + MAC_HEADER_SIZE_BYTES); - data_block_head = (__m128i *)((uint8_t *)tx_buffer + MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t); - - header->flags = 0; - header->fifo_status = 0; - header->seqno = *seqno; - header->ack = 0; - header->word0 = 0; - - txp[0] = (void*)&ru->common.txdata[0][subframe*ru->frame_parms->samples_per_tti]; - txp128 = (__m128i *) txp[0]; - - for (packet_id=0; packet_idsamples_per_tti/db_fulllength; packet_id++) { - header->time_stamp = htonl((uint32_t)(proc_timestamp + packet_id*db_fulllength)); - data_block = data_block_head; - - for (i=0; i>2; i+=2) { - t0 = _mm_srai_epi16(*txp128++, 4); - t1 = _mm_srai_epi16(*txp128++, 4); -// *data_block++ = _mm_packs_epi16(t0, t1); - _mm_storeu_si128(data_block++, _mm_packs_epi16(t0, t1)); - } - - // Write the packet to the fronthaul - if ((ru->ifdevice.trx_write_func(&ru->ifdevice, - packet_id, - (void**)&tx_buffer, - db_fulllength, - 1, - IF5_MOBIPASS)) < 0) { - perror("ETHERNET write for IF5_MOBIPASS\n"); - } - -#ifdef DEBUG_DL_MOBIPASS - if ((subframe==0)&&(dummy_cnt == 100)) { - memcpy((void*)&dummy_buffer[packet_id*db_fulllength*2],(void*)data_block_head,db_fulllength*2); - } -#endif - header->seqno += 1; - } - *seqno = header->seqno; - -#ifdef DEBUG_DL_MOBIPASS - uint8_t txe; - txe = dB_fixed(signal_energy(txp[0],fp->samples_per_tti)); - if (txe > 0){ - LOG_D(PHY,"[Mobipass] frame:%d, subframe:%d, energy %d\n", (proc_timestamp/(10*fp->samples_per_tti))&1023,subframe, txe); - } -#endif - } } else { AssertFatal(1==0, "send_IF5 - Unknown packet_type %x", packet_type); } free(tx_buffer); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 0 ); -#ifdef DEBUG_DL_MOBIPASS - if(subframe==0) { - if (dummy_cnt==100) { - LOG_M("txsigmb.m","txs",(void*)dummy_buffer, fp->samples_per_tti,1, 5); - exit(-1); - } else { - dummy_cnt++; - } - } -#endif return; } - -void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16_t packet_type) { +void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int tti, uint16_t packet_type) { LTE_DL_FRAME_PARMS *fp=ru->frame_parms; int32_t *txp[ru->nb_tx], *rxp[ru->nb_rx]; uint16_t packet_id=0, i=0; -#ifdef DEBUG_UL_MOBIPASS - //int8_t dummy_buffer_rx[fp->samples_per_tti*2]; - uint8_t rxe; -#endif int32_t spp_eth = (int32_t) ru->ifdevice.openair0_cfg->samples_per_packet; @@ -1375,6 +1263,7 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16 } */ } else if (eth->compression == NO_COMPRESS) { + int subframe = tti; for (i=0; i < fp->nb_antennas_tx; i++) txp[i] = (void*)&ru->common.txdata[i][subframe*fp->samples_per_tti]; @@ -1433,14 +1322,25 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16 } */ } else if (eth->compression == NO_COMPRESS) { - int16_t temp_rx[spp_eth*2] __attribute__((aligned(32))); + int16_t temp_rx[spp_eth*2] __attribute__((aligned(32))); + NR_DL_FRAME_PARMS *nrfp = ru->nr_frame_parms; + + int offset,siglen; + if (nrfp) { + offset = nrfp->get_samples_slot_timestamp(tti,nrfp,0); + siglen = nrfp->get_samples_per_slot(tti,nrfp); + } + else { + offset = tti*fp->samples_per_subframe; + siglen = spsf; + } for (i=0; i < ru->nb_rx; i++) - rxp[i] = &ru->common.rxdata[i][subframe*fp->samples_per_tti]; + rxp[i] = &ru->common.rxdata[i][offset]; int aid; int firstTS=1; openair0_timestamp oldTS=0; - for (packet_id=0; packet_id < ru->nb_rx*spsf / spp_eth; packet_id++) { + for (packet_id=0; packet_id < ru->nb_rx*siglen / spp_eth; packet_id++) { //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF5_PKT_ID, packet_id ); //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF0, 1 ); clock_gettime( CLOCK_MONOTONIC, &if_time); @@ -1453,7 +1353,8 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16 clock_gettime( CLOCK_MONOTONIC, &if_time); timeout[packet_id] = if_time.tv_nsec; timestamp[packet_id] /= (30720/spsf); - LOG_D(PHY,"subframe %d: Received packet %d: aid %d, TS %llu, oldTS %llu, diff %lld, \n",subframe,packet_id,aid,(unsigned long long)timestamp[packet_id],(unsigned long long)oldTS,(unsigned long long)(timestamp[packet_id]-timestamp[0])); + LOG_D(PHY,"TTI %d: Received packet %d: aid %d, TS %llu, oldTS %llu, diff %lld, \n",tti,packet_id,aid,(unsigned long long)timestamp[packet_id],(unsigned long long)oldTS,(unsigned long long)(timestamp[packet_id]-timestamp[0])); + if (aid==0) { if (firstTS==1) firstTS=0; else if (oldTS + 256 != timestamp[packet_id]) { @@ -1474,7 +1375,7 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16 (void*)temp_rx, spp_eth<<2); clock_gettime( CLOCK_MONOTONIC, &end_decomp); - LOG_D(HW,"[SF %d] IF_Read_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_decomp, end_decomp)); + LOG_D(HW,"[TTI %d] IF_Read_Time: %"PRId64"\n",tti,clock_difftime_ns(start_decomp, end_decomp)); //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF0, 0 ); } diff --git a/openair1/PHY/MODULATION/slot_fep_nr.c b/openair1/PHY/MODULATION/slot_fep_nr.c index f3c8c108dc..eb26dfc02b 100644 --- a/openair1/PHY/MODULATION/slot_fep_nr.c +++ b/openair1/PHY/MODULATION/slot_fep_nr.c @@ -109,11 +109,11 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, // use OFDM symbol from within 1/8th of the CP to avoid ISI rx_offset -= (nb_prefix_samples / frame_parms->ofdm_offset_divisor); -#ifdef DEBUG_FEP +//#ifdef DEBUG_FEP // if (ue->frame <100) - printf("slot_fep: slot %d, symbol %d, nb_prefix_samples %u, nb_prefix_samples0 %u, rx_offset %u\n", - Ns, symbol, nb_prefix_samples, nb_prefix_samples0, rx_offset); -#endif + LOG_D(PHY,"slot_fep: slot %d, symbol %d, nb_prefix_samples %u, nb_prefix_samples0 %u, rx_offset %u energy %d\n", + Ns, symbol, nb_prefix_samples, nb_prefix_samples0, rx_offset, dB_fixed(signal_energy(&common_vars->rxdata[0][rx_offset],frame_parms->ofdm_symbol_size))); + //#endif for (unsigned char aa=0; aanb_antennas_rx; aa++) { memset(&common_vars->common_vars_rx_data_per_thread[proc->thread_id].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],0,frame_parms->ofdm_symbol_size*sizeof(int32_t)); @@ -129,18 +129,14 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, rxdata_ptr = (int16_t *)tmp_dft_in; } -#if UE_TIMING_TRACE start_meas(&ue->rx_dft_stats); -#endif dft(dftsize, rxdata_ptr, (int16_t *)&common_vars->common_vars_rx_data_per_thread[proc->thread_id].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol], 1); -#if UE_TIMING_TRACE stop_meas(&ue->rx_dft_stats); -#endif int symb_offset = (Ns%frame_parms->slots_per_subframe)*frame_parms->symbols_per_slot; int32_t rot2 = ((uint32_t*)frame_parms->symbol_rotation[0])[symbol+symb_offset]; @@ -249,18 +245,14 @@ int nr_slot_fep_init_sync(PHY_VARS_NR_UE *ue, } -#if UE_TIMING_TRACE start_meas(&ue->rx_dft_stats); -#endif dft(dftsize, rxdata_ptr, (int16_t *)&common_vars->common_vars_rx_data_per_thread[proc->thread_id].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol], 1); -#if UE_TIMING_TRACE stop_meas(&ue->rx_dft_stats); -#endif int symb_offset = (Ns%frame_parms->slots_per_subframe)*frame_parms->symbols_per_slot; int32_t rot2 = ((uint32_t*)frame_parms->symbol_rotation[0])[symbol + symb_offset]; @@ -355,23 +347,24 @@ void apply_nr_rotation_ul(NR_DL_FRAME_PARMS *frame_parms, int symb_offset = (slot%frame_parms->slots_per_subframe)*frame_parms->symbols_per_slot; + int soffset = (slot&3)*frame_parms->symbols_per_slot*frame_parms->ofdm_symbol_size; for (int symbol=first_symbol;symbolsymbol_rotation[1])[symbol + symb_offset]; ((int16_t*)&rot2)[1]=-((int16_t*)&rot2)[1]; LOG_D(PHY,"slot %d, symb_offset %d rotating by %d.%d\n",slot,symb_offset,((int16_t*)&rot2)[0],((int16_t*)&rot2)[1]); - rotate_cpx_vector((int16_t *)&rxdataF[frame_parms->ofdm_symbol_size*symbol], + rotate_cpx_vector((int16_t *)&rxdataF[soffset+(frame_parms->ofdm_symbol_size*symbol)], (int16_t*)&rot2, - (int16_t *)&rxdataF[frame_parms->ofdm_symbol_size*symbol], + (int16_t *)&rxdataF[soffset+(frame_parms->ofdm_symbol_size*symbol)], length, 15); int16_t *shift_rot = frame_parms->timeshift_symbol_rotation; - multadd_cpx_vector((int16_t *)&rxdataF[frame_parms->ofdm_symbol_size*symbol], + multadd_cpx_vector((int16_t *)&rxdataF[soffset+(frame_parms->ofdm_symbol_size*symbol)], shift_rot, - (int16_t *)&rxdataF[frame_parms->ofdm_symbol_size*symbol], + (int16_t *)&rxdataF[soffset+(frame_parms->ofdm_symbol_size*symbol)], 1, length, 15); diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index 57470cf988..cfb5a2e56e 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -73,8 +73,9 @@ void dump_nr_I0_stats(FILE *fd,PHY_VARS_gNB *gNB) { int min_I0=1000,max_I0=0; int amin=0,amax=0; + fprintf(fd,"Blacklisted PRBs %d/%d\n",gNB->num_ulprbbl,gNB->frame_parms.N_RB_UL); for (int i=0; iframe_parms.N_RB_UL; i++) { - if (i==(gNB->frame_parms.N_RB_UL>>1) - 1) i+=2; + if (gNB->ulprbbl[i] > 0) continue; if (gNB->measurements.n0_subband_power_tot_dB[i]measurements.n0_subband_power_tot_dB[i]; amin=i;} @@ -82,64 +83,88 @@ void dump_nr_I0_stats(FILE *fd,PHY_VARS_gNB *gNB) { } for (int i=0; iframe_parms.N_RB_UL; i++) { - fprintf(fd,"%2d.",gNB->measurements.n0_subband_power_tot_dB[i]-gNB->measurements.n0_subband_power_avg_dB); + if (gNB->ulprbbl[i] ==0) fprintf(fd,"%2d.",gNB->measurements.n0_subband_power_tot_dB[i]-gNB->measurements.n0_subband_power_avg_dB); + else fprintf(fd," X."); if (i%25 == 24) fprintf(fd,"\n"); } - - fprintf(fd,"\nmax_I0 %d (rb %d), min_I0 %d (rb %d), avg I0 %d\n", max_I0, amax, min_I0, amin, gNB->measurements.n0_subband_power_avg_dB); - - fprintf(fd,"PRACH I0 = %d.%d dB\n",gNB->measurements.prach_I0/10,gNB->measurements.prach_I0%10); + fprintf(fd,"\n"); + fprintf(fd,"max_IO = %d (%d), min_I0 = %d (%d), avg_I0 = %d dB",max_I0,amax,min_I0,amin,gNB->measurements.n0_subband_power_avg_dB); + if (gNB->frame_parms.nb_antennas_rx>1) { + fprintf(fd,"("); + for (int aarx=0;aarxframe_parms.nb_antennas_rx;aarx++) + fprintf(fd,"%d.",gNB->measurements.n0_subband_power_avg_perANT_dB[aarx]); + fprintf(fd,")"); + } + fprintf(fd,"\nPRACH I0 = %d.%d dB\n",gNB->measurements.prach_I0/10,gNB->measurements.prach_I0%10); } -void gNB_I0_measurements(PHY_VARS_gNB *gNB,int first_symb,int num_symb) { +void gNB_I0_measurements(PHY_VARS_gNB *gNB,int slot, int first_symb,int num_symb) { NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; NR_gNB_COMMON *common_vars = &gNB->common_vars; PHY_MEASUREMENTS_gNB *measurements = &gNB->measurements; - uint32_t *rb_mask = gNB->rb_mask_ul; - int rb, offset, offset0, nb_rb, len; + int rb, offset, offset0, nb_symb[275], len; int32_t *ul_ch; - int32_t n0_power_tot; - int64_t n0_power_tot2; - nb_rb = 0; - n0_power_tot2=0; - for (rb=0; rbN_RB_UL; rb++) { - n0_power_tot=0; - offset0 = (frame_parms->first_carrier_offset + (rb*12))%frame_parms->ofdm_symbol_size; - if ((rb_mask[rb>>5]&(1<<(rb&31))) == 0) { // check that rb was not used in this subframe - nb_rb++; - for (int aarx=0; aarxnb_antennas_rx; aarx++) { - measurements->n0_subband_power[aarx][rb]=0; - for (int s=first_symb;s<(first_symb+num_symb);s++) { + LOG_D(PHY,"slot %d Doing I0 for first_symb %d, num_symb %d\n",slot,first_symb,num_symb); + for (int s=first_symb;s<(first_symb+num_symb);s++) { + for (rb=0; rbN_RB_UL; rb++) { - offset = offset0 + (s*frame_parms->ofdm_symbol_size); - ul_ch = &common_vars->rxdataF[aarx][offset]; - len = 12; - if (((frame_parms->N_RB_UL&1) == 1) && - (rb==(frame_parms->N_RB_UL>>1))) { - len=6; - } - AssertFatal(ul_ch, "RX signal buffer (freq) problem\n"); - measurements->n0_subband_power[aarx][rb] += signal_energy_nodc(ul_ch,len); - } // symbol - measurements->n0_subband_power[aarx][rb]/=num_symb; - measurements->n0_subband_power_dB[aarx][rb] = dB_fixed(measurements->n0_subband_power[aarx][rb]); - n0_power_tot += measurements->n0_subband_power[aarx][rb]; - } //antenna - n0_power_tot/=frame_parms->nb_antennas_rx; - n0_power_tot2 += n0_power_tot; - measurements->n0_subband_power_tot_dB[rb] = dB_fixed(n0_power_tot); + if (s==first_symb) { + nb_symb[rb]=0; + for (int aarx=0; aarxnb_antennas_rx;aarx++) + measurements->n0_subband_power[aarx][rb]=0; + } + offset0 = (slot&3)*(frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size) + (frame_parms->first_carrier_offset + (rb*12))%frame_parms->ofdm_symbol_size; + if ((gNB->rb_mask_ul[s][rb>>5]&(1<<(rb&31))) == 0) { // check that rb was not used in this subframe + nb_symb[rb]++; + for (int aarx=0; aarxnb_antennas_rx; aarx++) { + offset = offset0 + (s*frame_parms->ofdm_symbol_size); + ul_ch = &common_vars->rxdataF[aarx][offset]; + len = 12; + if (((frame_parms->N_RB_UL&1) == 1) && + (rb==(frame_parms->N_RB_UL>>1))) { + len=6; + } + AssertFatal(ul_ch, "RX signal buffer (freq) problem\n"); + measurements->n0_subband_power[aarx][rb] += signal_energy_nodc(ul_ch,len); + } //antenna + } + } //rb + } // symb + int nb_rb=0; + int32_t n0_subband_tot=0; + int32_t n0_subband_tot_perPRB=0; + int32_t n0_subband_tot_perANT[1+frame_parms->nb_antennas_rx]; + + for (int rb = 0 ; rbN_RB_UL;rb++) { + n0_subband_tot_perPRB=0; + if (nb_symb[rb] > 0) { + for (int aarx=0;aarxnb_antennas_rx;aarx++) { + measurements->n0_subband_power[aarx][rb]/=nb_symb[rb]; + measurements->n0_subband_power_dB[aarx][rb] = dB_fixed(measurements->n0_subband_power[aarx][rb]); + n0_subband_tot_perPRB+=measurements->n0_subband_power[aarx][rb]; + if (rb==0) n0_subband_tot_perANT[aarx]=measurements->n0_subband_power[aarx][rb]; + else n0_subband_tot_perANT[aarx]+=measurements->n0_subband_power[aarx][rb]; + } + n0_subband_tot_perPRB/=frame_parms->nb_antennas_rx; + measurements->n0_subband_power_tot_dB[rb] = dB_fixed(n0_subband_tot_perPRB); measurements->n0_subband_power_tot_dBm[rb] = measurements->n0_subband_power_tot_dB[rb] - gNB->rx_total_gain_dB - dB_fixed(frame_parms->N_RB_UL); + LOG_D(PHY,"n0_subband_power_tot_dB[%d] => %d, over %d symbols\n",rb,measurements->n0_subband_power_tot_dB[rb],nb_symb[rb]); + n0_subband_tot += n0_subband_tot_perPRB; + nb_rb++; } - } //rb - - if (nb_rb>0) measurements->n0_subband_power_avg_dB = dB_fixed(n0_power_tot2/nb_rb); - + } + if (nb_rb>0) { + measurements->n0_subband_power_avg_dB = dB_fixed(n0_subband_tot/nb_rb); + for (int aarx=0;aarxnb_antennas_rx;aarx++) { + measurements->n0_subband_power_avg_perANT_dB[aarx] = dB_fixed(n0_subband_tot_perANT[aarx]/nb_rb); + } + } } @@ -179,6 +204,7 @@ void nr_gnb_measurements(PHY_VARS_gNB *gNB, uint8_t ulsch_id, unsigned char harq rx_power[ulsch_id][aarx] += meas->rx_spatial_power[ulsch_id][aatx][aarx]; } + LOG_D(PHY, "[ULSCH ID %d] RX power in antenna %d = %d\n", ulsch_id, aarx, rx_power[ulsch_id][aarx]); rx_power_tot[ulsch_id] += rx_power[ulsch_id][aarx]; @@ -190,12 +216,13 @@ void nr_gnb_measurements(PHY_VARS_gNB *gNB, uint8_t ulsch_id, unsigned char harq meas->wideband_cqi_tot[ulsch_id] = dB_fixed2(rx_power_tot[ulsch_id], meas->n0_power_tot); meas->rx_rssi_dBm[ulsch_id] = rx_power_avg_dB[ulsch_id] + 30 - 10 * log10(pow(2, 30)) - (rx_gain - rx_gain_offset) - dB_fixed(fp->ofdm_symbol_size); - LOG_D(PHY, "[ULSCH %d] RSSI %d dBm/RE, RSSI (digital) %d dB (N_RB_UL %d), WBand CQI tot %d dB, N0 Power tot %d\n", + LOG_D(PHY, "[ULSCH %d] RSSI %d dBm/RE, RSSI (digital) %d dB (N_RB_UL %d), WBand CQI tot %d dB, N0 Power tot %d, RX Power tot %d\n", ulsch_id, meas->rx_rssi_dBm[ulsch_id], rx_power_avg_dB[ulsch_id], N_RB_UL, meas->wideband_cqi_tot[ulsch_id], - meas->n0_power_tot); + meas->n0_power_tot, + rx_power_tot[ulsch_id]); } diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 960ad82696..1f164748bf 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -68,7 +68,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, uint8_t nushift; int **ul_ch_estimates = gNB->pusch_vars[ul_id]->ul_ch_estimates; int **rxdataF = gNB->common_vars.rxdataF; - + int soffset = (Ns&3)*gNB->frame_parms.symbols_per_slot*gNB->frame_parms.ofdm_symbol_size; nushift = (p>>1)&1; gNB->frame_parms.nushift = nushift; @@ -81,16 +81,14 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, uint16_t nb_rb_pusch = pusch_pdu->rb_size; -#ifdef DEBUG_CH - LOG_I(PHY, "In %s: ch_offset %d, symbol_offset %d OFDM size %d, Ns = %d, k = %d symbol %d\n", + LOG_D(PHY, "In %s: ch_offset %d, soffset %d, symbol_offset %d OFDM size %d, Ns = %d, k = %d symbol %d\n", __FUNCTION__, - ch_offset, + ch_offset, soffset, symbol_offset, gNB->frame_parms.ofdm_symbol_size, Ns, k, symbol); -#endif switch (nushift) { case 0: @@ -174,7 +172,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, re_offset = k; /* Initializing the Resource element offset for each Rx antenna */ pil = (int16_t *)&pilot[0]; - rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k+nushift)]; + rxF = (int16_t *)&rxdataF[aarx][(soffset+symbol_offset+k+nushift)]; ul_ch = (int16_t *)&ul_ch_estimates[p*gNB->frame_parms.nb_antennas_rx+aarx][ch_offset]; re_offset = k; @@ -216,7 +214,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, 8); pil += 2; re_offset = (re_offset+2) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; + rxF = (int16_t *)&rxdataF[aarx][(soffset+symbol_offset+nushift+re_offset)]; //for (int i= 0; i<8; i++) //printf("ul_ch addr %p %d\n", ul_ch+i, *(ul_ch+i)); @@ -247,7 +245,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, 8); pil += 2; re_offset = (re_offset+2) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; + rxF = (int16_t *)&rxdataF[aarx][(soffset+symbol_offset+nushift+re_offset)]; //printf("ul_ch addr %p\n",ul_ch); ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); @@ -281,8 +279,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, pil += 2; re_offset = (re_offset+2) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; - ul_ch += 8; + rxF = (int16_t *)&rxdataF[aarx][(soffset+symbol_offset+nushift+re_offset)]; + ul_ch+=8; for (pilot_cnt=3; pilot_cnt<(6*nb_rb_pusch-3); pilot_cnt += 2) { @@ -299,7 +297,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, 8); pil += 2; re_offset = (re_offset+2) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; + rxF = (int16_t *)&rxdataF[aarx][(soffset+symbol_offset+nushift+re_offset)]; //printf("ul_ch addr %p\n",ul_ch); ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); @@ -319,9 +317,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, pil += 2; re_offset = (re_offset+2) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; - ul_ch += 8; - + rxF = (int16_t *)&rxdataF[aarx][soffset+(symbol_offset+nushift+re_offset)]; + ul_ch+=8; } // Treat first 2 pilots specially (right edge) @@ -341,7 +338,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, pil += 2; re_offset = (re_offset+2) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; + rxF = (int16_t *)&rxdataF[aarx][soffset+(symbol_offset+nushift+re_offset)]; ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); @@ -357,8 +354,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, pil += 2; re_offset = (re_offset+2) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; - ul_ch += 8; + rxF = (int16_t *)&rxdataF[aarx][soffset+(symbol_offset+nushift+re_offset)]; + ul_ch+=8; ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); @@ -383,7 +380,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, ul_ch += (idxDC-4); ul_ch = memset(ul_ch, 0, sizeof(int16_t)*10); re_offset = (re_offset+idxDC/2-2) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; + rxF = (int16_t *)&rxdataF[aarx][soffset+(symbol_offset+nushift+re_offset)]; ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); @@ -414,7 +411,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, pil += 4; re_offset = (re_offset+4) % gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; + rxF = (int16_t *)&rxdataF[aarx][soffset+(symbol_offset+nushift+re_offset)]; ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); @@ -438,7 +435,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, LOG_D(PHY,"PUSCH estimation DMRS type 2, Freq-domain interpolation"); // Treat first DMRS specially (left edge) - rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; + rxF = (int16_t *)&rxdataF[aarx][soffset+(symbol_offset+nushift+re_offset)]; ul_ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); ul_ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); @@ -450,7 +447,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, for (re_cnt = 1; re_cnt < (nb_rb_pusch*NR_NB_SC_PER_RB) - 5; re_cnt += 6){ - rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; + rxF = (int16_t *)&rxdataF[aarx][soffset+(symbol_offset+nushift+re_offset)]; ch_l[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); ch_l[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); @@ -468,7 +465,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, re_offset = (re_offset+5)%gNB->frame_parms.ofdm_symbol_size; - rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; + rxF = (int16_t *)&rxdataF[aarx][soffset+symbol_offset+nushift+re_offset]; ch_r[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); ch_r[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); @@ -496,7 +493,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, // Treat last pilot specially (right edge) - rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+nushift+re_offset)]; + rxF = (int16_t *)&rxdataF[aarx][soffset+(symbol_offset+nushift+re_offset)]; ch_l[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15); ch_l[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15); diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index c8e02fd13d..fd3403236e 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -49,7 +49,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, void dump_nr_I0_stats(FILE *fd,PHY_VARS_gNB *gNB); -void gNB_I0_measurements(PHY_VARS_gNB *gNB,int first_symb,int num_symb); +void gNB_I0_measurements(PHY_VARS_gNB *gNB,int slot,int first_symb,int num_symb); void nr_gnb_measurements(PHY_VARS_gNB *gNB, uint8_t ulsch_id, unsigned char harq_pid, unsigned char symbol, uint8_t nrOfLayers); diff --git a/openair1/PHY/NR_REFSIG/nr_gold.c b/openair1/PHY/NR_REFSIG/nr_gold.c index 11e28a3046..7930839832 100644 --- a/openair1/PHY/NR_REFSIG/nr_gold.c +++ b/openair1/PHY/NR_REFSIG/nr_gold.c @@ -66,7 +66,7 @@ void nr_init_pdcch_dmrs(PHY_VARS_gNB* gNB, uint32_t Nid) reset = 1; x2 = ((1<<17) * (fp->symbols_per_slot*slot+symb+1) * ((Nid<<1)+1) + (Nid<<1)); - + LOG_D(PHY,"PDCCH DMRS slot %d, symb %d, Nid %d, x2 %x\n",slot,symb,Nid,x2); for (uint32_t n=0; nsymbols_per_slot; symb++) { reset = 1; x2 = ((1<<17) * (fp->symbols_per_slot*slot+symb+1) * ((N_n_scid[n_scid]<<1)+1) +((N_n_scid[n_scid]<<1)+n_scid)); - LOG_D(PHY,"DMRS slot %d, symb %d x2 %x\n",slot,symb,x2); + LOG_D(PHY,"PDSCH DMRS slot %d, symb %d x2 %x, N_n_scid %d,n_scid %d\n",slot,symb,x2,N_n_scid[n_scid],n_scid); for (uint32_t n=0; nFreqDomainResource,&n_rb,&rb_offset); @@ -102,7 +103,9 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, // DMRS length is per OFDM symbol uint32_t dmrs_length = n_rb*6; //2(QPSK)*3(per RB)*6(REG per CCE) uint32_t encoded_length = dci_pdu->AggregationLevel*108; //2(QPSK)*9(per RB)*6(REG per CCE) - LOG_D(PHY, "DMRS length per symbol %d\t DCI encoded length %d (precoder_granularity %d,reg_mapping %d)\n", dmrs_length, encoded_length,pdcch_pdu_rel15->precoderGranularity,pdcch_pdu_rel15->CceRegMappingType); + LOG_D(PHY, "DL_DCI : rb_offset %d, nb_rb %d, DMRS length per symbol %d\t DCI encoded length %d (precoder_granularity %d,reg_mapping %d),Scrambling_Id %d,ScramblingRNTI %x,PayloadSizeBits %d\n", + rb_offset, n_rb,dmrs_length, encoded_length,pdcch_pdu_rel15->precoderGranularity,pdcch_pdu_rel15->CceRegMappingType, + dci_pdu->ScramblingId,dci_pdu->ScramblingRNTI,dci_pdu->PayloadSizeBits); dmrs_length += rb_offset*6; // To accommodate more DMRS symbols in case of rb offset /// DMRS QPSK modulation @@ -111,11 +114,11 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, nr_modulation(gold_pdcch_dmrs[symb], dmrs_length, DMRS_MOD_ORDER, mod_dmrs[symb]); //Qm = 2 as DMRS is QPSK modulated #ifdef DEBUG_PDCCH_DMRS - + if(dci_pdu->RNTI!=0xFFFF) { for (int i=0; i>1; i++) - printf("symb %d i %d gold seq 0x%08x mod_dmrs %d %d\n", symb, i, - gold_pdcch_dmrs[symb][i>>5], mod_dmrs[symb][i<<1], mod_dmrs[symb][(i<<1)+1] ); - + printf("symb %d i %d %p gold seq 0x%08x mod_dmrs %d %d\n", symb, i, + &gold_pdcch_dmrs[symb][i>>5],gold_pdcch_dmrs[symb][i>>5], mod_dmrs[symb][i<<1], mod_dmrs[symb][(i<<1)+1] ); + } #endif } @@ -132,8 +135,8 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, dci_pdu->AggregationLevel, 0,NULL); polar_encoder_fast((uint64_t*)dci_pdu->Payload, (void*)encoder_output, n_RNTI,1,currentPtr); -#ifdef DEBUG_CHANNEL_CODING - printf("polar rnti %x,length %d, L %d\n",n_RNTI, dci_pdu->PayloadSizeBits,pdcch_pdu_rel15->dci_pdu.AggregationLevel[d]); +#if DEBUG_CHANNEL_CODING + printf("polar rnti %x,length %d, L %d\n",n_RNTI, dci_pdu->PayloadSizeBits,dci_pdu->AggregationLevel); printf("DCI PDU: [0]->0x%lx \t [1]->0x%lx\n", ((uint64_t*)dci_pdu->Payload)[0], ((uint64_t*)dci_pdu->Payload)[1]); printf("Encoded Payload (length:%d dwords):\n", encoded_length>>5); @@ -211,7 +214,7 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, (amp * mod_dmrs[l][(dmrs_idx << 1) + 1]) >> 15; #ifdef DEBUG_PDCCH_DMRS - printf("PDCCH DMRS: l %d position %d => (%d,%d)\n",l,k,((int16_t *)txdataF)[(l*frame_parms->ofdm_symbol_size + k)<<1], + LOG_D(PHY,"PDCCH DMRS %d: l %d position %d => (%d,%d)\n",dmrs_idx,l,k,((int16_t *)txdataF)[(l*frame_parms->ofdm_symbol_size + k)<<1], ((int16_t *)txdataF)[((l*frame_parms->ofdm_symbol_size + k)<<1)+1]); #endif @@ -223,7 +226,7 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, ((int16_t *) txdataF)[((l * frame_parms->ofdm_symbol_size + k) << 1) + 1] = (amp * mod_dci[(dci_idx << 1) + 1]) >> 15; #ifdef DEBUG_DCI - printf("PDCCH: l %d position %d => (%d,%d)\n",l,k,((int16_t *)txdataF)[(l*frame_parms->ofdm_symbol_size + k)<<1], + LOG_D(PHY,"PDCCH: l %d position %d => (%d,%d)\n",l,k,((int16_t *)txdataF)[(l*frame_parms->ofdm_symbol_size + k)<<1], ((int16_t *)txdataF)[((l*frame_parms->ofdm_symbol_size + k)<<1)+1]); #endif diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.h b/openair1/PHY/NR_TRANSPORT/nr_dci.h index e3b53f9cf9..07baaf2728 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.h +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.h @@ -59,6 +59,4 @@ void nr_fill_ul_dci(PHY_VARS_gNB *gNB, void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint8_t m,nfapi_nr_dl_tti_pdcch_pdu_rel15_t *); -void get_coreset_rballoc(uint8_t *FreqDomainResource,int *n_rb,int *rb_offset); - #endif //__PHY_NR_TRANSPORT_DCI__H diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c b/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c index c562dfaa41..1675045443 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c @@ -31,6 +31,7 @@ */ #include "nr_dci.h" +#include "common/utils/nr/nr_common.h" //#define DEBUG_FILL_DCI @@ -153,7 +154,7 @@ void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint8_t m, nfapi_nr_dl_tti_pdcch_pdu_r C = N_reg/(bsize*R); } - LOG_D(PHY, "CCE list generation for candidate %d: bundle size %d ilv size %d CceIndex %d\n", m, bsize, R, pdcch_pdu_rel15->dci_pdu[d].CceIndex); + if (pdcch_pdu_rel15->dci_pdu[d].RNTI != 0xFFFF) LOG_D(PHY, "CCE list generation for candidate %d: bundle size %d ilv size %d CceIndex %d\n", m, bsize, R, pdcch_pdu_rel15->dci_pdu[d].CceIndex); for (uint8_t cce_idx=0; cce_idxcce_list[d][cce_idx]; cce->cce_idx = pdcch_pdu_rel15->dci_pdu[d].CceIndex + cce_idx; @@ -202,107 +203,3 @@ void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint8_t m, nfapi_nr_dl_tti_pdcch_pdu_r ret |= ((field>>i)&1)<<(size-i-1); return ret; }*/ -int16_t find_nr_pdcch(int frame,int slot, PHY_VARS_gNB *gNB,find_type_t type) { - - uint16_t i; - int16_t first_free_index=-1; - - AssertFatal(gNB!=NULL,"gNB is null\n"); - for (i=0; ipdcch_pdu[i].frame,gNB->pdcch_pdu[i].slot,first_free_index); - if ((gNB->pdcch_pdu[i].frame == frame) && - (gNB->pdcch_pdu[i].slot==slot)) return i; - else if ( gNB->pdcch_pdu[i].frame==-1 && first_free_index==-1) first_free_index=i; - } - if (type == SEARCH_EXIST) return -1; - - return first_free_index; -} - - -void nr_fill_dci(PHY_VARS_gNB *gNB, - int frame, - int slot, - nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu) { - - nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &pdcch_pdu->pdcch_pdu_rel15; - NR_gNB_DLSCH_t *dlsch; - - int pdcch_id = find_nr_pdcch(frame,slot,gNB,SEARCH_EXIST_OR_FREE); - AssertFatal(pdcch_id>=0 && pdcch_idpdcch_pdu[pdcch_id].pdcch_pdu,(void*)pdcch_pdu,sizeof(*pdcch_pdu)); - gNB->pdcch_pdu[pdcch_id].frame = frame; - gNB->pdcch_pdu[pdcch_id].slot = slot; - - for (int i=0;inumDlDci;i++) { - - //uint64_t *dci_pdu = (uint64_t*)pdcch_pdu_rel15->dci_pdu[i].Payload; - - int dlsch_id = find_nr_dlsch(pdcch_pdu_rel15->dci_pdu[i].RNTI,gNB,SEARCH_EXIST_OR_FREE); - if( (dlsch_id<0) || (dlsch_id>=gNB->number_of_nr_dlsch_max) ){ - LOG_E(PHY,"illegal dlsch_id found!!! rnti %04x dlsch_id %d\n",(unsigned int)pdcch_pdu_rel15->dci_pdu[i].RNTI,dlsch_id); - return; - } - - dlsch = gNB->dlsch[dlsch_id][0]; - int harq_pid = 0; - - dlsch->slot_tx[slot] = 1; - dlsch->harq_ids[frame % 2][slot] = 0; - AssertFatal(harq_pid < 8 && harq_pid >= 0, - "illegal harq_pid %d\n",harq_pid); - - dlsch->harq_mask |= (1<rnti = pdcch_pdu_rel15->dci_pdu[i].RNTI; - - // nr_fill_cce_list(gNB,0); - } - -} - - -int16_t find_nr_ul_dci(int frame,int slot, PHY_VARS_gNB *gNB,find_type_t type) { - - uint16_t i; - int16_t first_free_index=-1; - - AssertFatal(gNB!=NULL,"gNB is null\n"); - for (i=0; iul_pdcch_pdu[i].frame,gNB->ul_pdcch_pdu[i].slot,first_free_index); - if ((gNB->ul_pdcch_pdu[i].frame == frame) && - (gNB->ul_pdcch_pdu[i].slot==slot)) return i; - else if (gNB->ul_pdcch_pdu[i].frame==-1 && first_free_index==-1) first_free_index=i; - } - if (type == SEARCH_EXIST) return -1; - - return first_free_index; -} - - -void nr_fill_ul_dci(PHY_VARS_gNB *gNB, - int frame, - int slot, - nfapi_nr_ul_dci_request_pdus_t *pdcch_pdu) { - - nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; - - int pdcch_id = find_nr_ul_dci(frame,slot,gNB,SEARCH_EXIST_OR_FREE); - AssertFatal(pdcch_id>=0 && pdcch_idul_pdcch_pdu[pdcch_id].pdcch_pdu,(void*)pdcch_pdu,sizeof(*pdcch_pdu)); - gNB->ul_pdcch_pdu[pdcch_id].frame = frame; - gNB->ul_pdcch_pdu[pdcch_id].slot = slot; - - for (int i=0;inumDlDci;i++) { - - //uint64_t *dci_pdu = (uint64_t*)pdcch_pdu_rel15->dci_pdu[i].Payload; - - // if there's no DL DCI then generate CCE list - // nr_fill_cce_list(gNB,0); - /* - LOG_D(PHY, "DCI PDU: [0]->0x%lx \t [1]->0x%lx \n",dci_pdu[0], dci_pdu[1]); - LOG_D(PHY, "DCI type %d payload (size %d) generated on candidate %d\n", dci_alloc->pdcch_params.dci_format, dci_alloc->size, cand_idx); - */ - - } - -} diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci_tools_common.c b/openair1/PHY/NR_TRANSPORT/nr_dci_tools_common.c deleted file mode 100644 index d26a52f157..0000000000 --- a/openair1/PHY/NR_TRANSPORT/nr_dci_tools_common.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file PHY/NR_TRANSPORT/nr_dci_tools_common.c - * \brief - * \author - * \date 2018 - * \version 0.1 - * \company Eurecom - * \email: - * \note - * \warning - */ - -#include "nr_dci.h" - -//#define DEBUG_FILL_DCI - -#include "nr_dlsch.h" - - -void get_coreset_rballoc(uint8_t *FreqDomainResource,int *n_rb,int *rb_offset) { - - uint8_t count=0, start=0, start_set=0; - - uint64_t bitmap = (((uint64_t)FreqDomainResource[0])<<37)| - (((uint64_t)FreqDomainResource[1])<<29)| - (((uint64_t)FreqDomainResource[2])<<21)| - (((uint64_t)FreqDomainResource[3])<<13)| - (((uint64_t)FreqDomainResource[4])<<5)| - (((uint64_t)FreqDomainResource[5])>>3); - - for (int i=0; i<45; i++) - if ((bitmap>>(44-i))&1) { - count++; - if (!start_set) { - start = i; - start_set = 1; - } - } - *rb_offset = 6*start; - *n_rb = 6*count; -} - diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index ce056b5aa5..d75f97aa53 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -37,7 +37,7 @@ #include "PHY/NR_REFSIG/dmrs_nr.h" #include "PHY/NR_REFSIG/ptrs_nr.h" #include "common/utils/LOG/vcd_signal_dumper.h" -#include "LAYER2/NR_MAC_gNB/mac_proto.h" +#include "common/utils/nr/nr_common.h" //#define DEBUG_DLSCH //#define DEBUG_DLSCH_MAPPING @@ -111,10 +111,11 @@ void nr_pdsch_codeword_scrambling_optim(uint8_t *in, } -uint8_t nr_generate_pdsch(PHY_VARS_gNB *gNB, +uint8_t nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot) { + PHY_VARS_gNB *gNB = msgTx->gNB; NR_gNB_DLSCH_t *dlsch; uint32_t ***pdsch_dmrs = gNB->nr_gold_pdsch_dmrs[slot]; int32_t** txdataF = gNB->common_vars.txdataF; @@ -132,9 +133,8 @@ uint8_t nr_generate_pdsch(PHY_VARS_gNB *gNB, time_stats_t *dlsch_interleaving_stats=&gNB->dlsch_interleaving_stats; time_stats_t *dlsch_segmentation_stats=&gNB->dlsch_segmentation_stats; - for (int dlsch_id=0;dlsch_idnumber_of_nr_dlsch_max;dlsch_id++) { - dlsch = gNB->dlsch[dlsch_id][0]; - if (dlsch->slot_tx[slot] == 0) continue; + for (int dlsch_id=0; dlsch_idnum_pdsch_slot; dlsch_id++) { + dlsch = msgTx->dlsch[dlsch_id][0]; NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; @@ -527,15 +527,17 @@ uint8_t nr_generate_pdsch(PHY_VARS_gNB *gNB, return 0; } -void dump_pdsch_stats(PHY_VARS_gNB *gNB) { +void dump_pdsch_stats(FILE *fd,PHY_VARS_gNB *gNB) { for (int i=0;idlsch_stats[i].rnti > 0) - LOG_D(PHY,"DLSCH RNTI %x: current_Qm %d, current_RI %d, total_bytes TX %d\n", + if (gNB->dlsch_stats[i].rnti > 0 && gNB->dlsch_stats[i].frame != gNB->dlsch_stats[i].dump_frame) { + gNB->dlsch_stats[i].dump_frame = gNB->dlsch_stats[i].frame; + fprintf(fd,"DLSCH RNTI %x: current_Qm %d, current_RI %d, total_bytes TX %d\n", gNB->dlsch_stats[i].rnti, gNB->dlsch_stats[i].current_Qm, gNB->dlsch_stats[i].current_RI, gNB->dlsch_stats[i].total_bytes_tx); + } } diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.h b/openair1/PHY/NR_TRANSPORT/nr_dlsch.h index 6af8f28eac..4b6ecfe412 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.h +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.h @@ -63,13 +63,11 @@ void nr_pdsch_codeword_scrambling(uint8_t *in, uint32_t n_RNTI, uint32_t* out); -void nr_fill_dlsch(PHY_VARS_gNB *gNB, - int frame, - int slot, +void nr_fill_dlsch(processingData_L1tx_t *msgTx, nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu, unsigned char *sdu); -uint8_t nr_generate_pdsch(PHY_VARS_gNB *gNB, +uint8_t nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot); void free_gNB_dlsch(NR_gNB_DLSCH_t **dlschptr, uint16_t N_RB); @@ -98,7 +96,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, void init_dlsch_tpool(uint8_t nun_dlsch_threads); void nr_emulate_dlsch_payload(uint8_t* payload, uint16_t size); -void dump_pdsch_stats(PHY_VARS_gNB *gNB); +void dump_pdsch_stats(FILE *fd,PHY_VARS_gNB *gNB); void clear_pdsch_stats(PHY_VARS_gNB *gNB); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index 9956e14701..acb59b0e40 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -39,10 +39,10 @@ #include "PHY/NR_TRANSPORT/nr_transport_proto.h" #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" #include "PHY/NR_TRANSPORT/nr_dlsch.h" -#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" #include "SCHED_NR/sched_nr.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "common/utils/LOG/log.h" +#include "common/utils/nr/nr_common.h" #include #include diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c index 543002827d..3ba13d2f44 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c @@ -254,48 +254,16 @@ void nr_emulate_dlsch_payload(uint8_t* pdu, uint16_t size) { *(pdu+i) = (uint8_t)rand(); } -int16_t find_nr_dlsch(uint16_t rnti, PHY_VARS_gNB *gNB,find_type_t type) { - - uint16_t i; - int16_t first_free_index=-1; - - AssertFatal(gNB!=NULL,"gNB is null\n"); - for (i=0; inumber_of_nr_dlsch_max; i++) { - AssertFatal(gNB->dlsch[i]!=NULL,"gNB->dlsch[%d] is null\n",i); - AssertFatal(gNB->dlsch[i][0]!=NULL,"gNB->dlsch[%d][0] is null\n",i); - LOG_D(PHY,"searching for rnti %x : dlsch_index %d=> harq_mask %x, rnti %x, first_free_index %d\n", rnti,i, - gNB->dlsch[i][0]->harq_mask,gNB->dlsch[i][0]->rnti,first_free_index); - if ((gNB->dlsch[i][0]->harq_mask >0) && - (gNB->dlsch[i][0]->rnti==rnti)) return i; - else if ((gNB->dlsch[i][0]->harq_mask == 0) && (first_free_index==-1)) first_free_index=i; - } - if (type == SEARCH_EXIST) return -1; - if (first_free_index != -1) - gNB->dlsch[first_free_index][0]->rnti = 0; - return first_free_index; - -} - - -void nr_fill_dlsch(PHY_VARS_gNB *gNB, - int frame, - int slot, +void nr_fill_dlsch(processingData_L1tx_t *msgTx, nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu, uint8_t *sdu) { - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &pdsch_pdu->pdsch_pdu_rel15; - - int dlsch_id = find_nr_dlsch(rel15->rnti,gNB,SEARCH_EXIST); - AssertFatal( (dlsch_id>=0) && (dlsch_idnumber_of_nr_dlsch_max), - "illegal or no dlsch_id found!!! rnti %04x dlsch_id %d\n",rel15->rnti,dlsch_id); - NR_gNB_DLSCH_t *dlsch = gNB->dlsch[dlsch_id][0]; + NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[msgTx->num_pdsch_slot][0]; NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; /// DLSCH struct memcpy((void*)&harq->pdsch_pdu, (void*)pdsch_pdu, sizeof(nfapi_nr_dl_tti_pdsch_pdu)); - gNB->num_pdsch_rnti[slot]++; + msgTx->num_pdsch_slot++; AssertFatal(sdu!=NULL,"sdu is null\n"); harq->pdu = sdu; - - } diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach_common.c b/openair1/PHY/NR_TRANSPORT/nr_prach_common.c index a95c519d43..84118e8267 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach_common.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach_common.c @@ -37,7 +37,6 @@ #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" #include "common/utils/LOG/log.h" #include "common/utils/LOG/vcd_signal_dumper.h" -#include "openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h" #include "T.h" diff --git a/openair1/PHY/NR_TRANSPORT/nr_tbs_tools.c b/openair1/PHY/NR_TRANSPORT/nr_tbs_tools.c index e535286084..aa51f23cb6 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_tbs_tools.c +++ b/openair1/PHY/NR_TRANSPORT/nr_tbs_tools.c @@ -46,11 +46,11 @@ uint32_t nr_get_E(uint32_t G, uint8_t C, uint8_t Qm, uint8_t Nl, uint8_t r) { AssertFatal(Nl>0,"Nl is 0\n"); AssertFatal(Qm>0,"Qm is 0\n"); - LOG_D(PHY,"nr_get_E : (G %d, C %d, Qm %d, Nl %d, r %d)\n",G, C, Qm, Nl, r); if (r <= Cprime - ((G/(Nl*Qm))%Cprime) - 1) E = Nl*Qm*(G/(Nl*Qm*Cprime)); else E = Nl*Qm*((G/(Nl*Qm*Cprime))+1); + LOG_D(PHY,"nr_get_E : (G %d, C %d, Qm %d, Nl %d, r %d), E %d\n",G, C, Qm, Nl, r, E); return E; } diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 54188d22c0..4fed3a468f 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -35,7 +35,6 @@ #include "PHY/defs_nr_common.h" #include "PHY/defs_gNB.h" -#include "LAYER2/NR_MAC_gNB/mac_proto.h" #define NR_PBCH_PDU_BITS 24 @@ -140,6 +139,7 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, */ void nr_ulsch_extract_rbs_single(int32_t **rxdataF, NR_gNB_PUSCH *pusch_vars, + int slot, unsigned char symbol, uint8_t is_dmrs_symbol, nfapi_nr_pusch_pdu_t *pusch_pdu, @@ -314,6 +314,7 @@ int nr_find_pucch(uint16_t rnti, void init_prach_list(PHY_VARS_gNB *gNB); void init_prach_ru_list(RU_t *ru); void free_nr_ru_prach_entry(RU_t *ru, int prach_id); +uint8_t get_nr_prach_duration(uint8_t prach_format); void nr_generate_csi_rs(PHY_VARS_gNB *gNB, int16_t amp, diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c index 53ff90404b..4278338dbc 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c @@ -137,27 +137,24 @@ void nr_ulsch_unscrambling_optim(int16_t* llr, #endif } -#define STATSTRLEN 16384 void dump_pusch_stats(FILE *fd,PHY_VARS_gNB *gNB) { - char output[16384]; - int stroff=0; - for (int i=0;inumber_of_nr_ulsch_max;i++) { - if (gNB->ulsch_stats[i].rnti>0) { + + if (gNB->ulsch_stats[i].rnti>0 && gNB->ulsch_stats[i].frame != gNB->ulsch_stats[i].dump_frame) { + gNB->ulsch_stats[i].dump_frame = gNB->ulsch_stats[i].frame; for (int aa=0;aaframe_parms.nb_antennas_rx;aa++) - if (aa==0) stroff+=sprintf(output+stroff,"ULSCH RNTI %4x: ulsch_power[%d] %d,%d ulsch_noise_power[%d] %d.%d\n", - gNB->ulsch_stats[i].rnti, + if (aa==0) fprintf(fd,"ULSCH RNTI %4x, %d.%d: ulsch_power[%d] %d,%d ulsch_noise_power[%d] %d.%d, sync_pos %d\n", + gNB->ulsch_stats[i].rnti,gNB->ulsch_stats[i].frame,gNB->ulsch_stats[i].dump_frame, aa,gNB->ulsch_stats[i].power[aa]/10,gNB->ulsch_stats[i].power[aa]%10, - aa,gNB->ulsch_stats[i].noise_power[aa]/10,gNB->ulsch_stats[i].noise_power[aa]%10); - else stroff+=sprintf(output+stroff," ulsch_power[%d] %d.%d, ulsch_noise_power[%d] %d.%d\n", + aa,gNB->ulsch_stats[i].noise_power[aa]/10,gNB->ulsch_stats[i].noise_power[aa]%10, + gNB->ulsch_stats[i].sync_pos); + else fprintf(fd," ulsch_power[%d] %d.%d, ulsch_noise_power[%d] %d.%d\n", aa,gNB->ulsch_stats[i].power[aa]/10,gNB->ulsch_stats[i].power[aa]%10, aa,gNB->ulsch_stats[i].noise_power[aa]/10,gNB->ulsch_stats[i].noise_power[aa]%10); - AssertFatal(stroff<(STATSTRLEN-1000),"Increase STATSTRLEN\n"); - - stroff+=sprintf(output+stroff," round_trials %d(%1.1e):%d(%1.1e):%d(%1.1e):%d, DTX %d, current_Qm %d, current_RI %d, total_bytes RX/SCHED %d/%d\n", + fprintf(fd," round_trials %d(%1.1e):%d(%1.1e):%d(%1.1e):%d, DTX %d, current_Qm %d, current_RI %d, total_bytes RX/SCHED %d/%d\n", gNB->ulsch_stats[i].round_trials[0], (double)gNB->ulsch_stats[i].round_trials[1]/gNB->ulsch_stats[i].round_trials[0], gNB->ulsch_stats[i].round_trials[1], @@ -165,14 +162,13 @@ void dump_pusch_stats(FILE *fd,PHY_VARS_gNB *gNB) { gNB->ulsch_stats[i].round_trials[2], (double)gNB->ulsch_stats[i].round_trials[3]/gNB->ulsch_stats[i].round_trials[0], gNB->ulsch_stats[i].round_trials[3], - gNB->ulsch_stats[i].DTX, + gNB->ulsch_stats[i].DTX, gNB->ulsch_stats[i].current_Qm, gNB->ulsch_stats[i].current_RI, gNB->ulsch_stats[i].total_bytes_rx, gNB->ulsch_stats[i].total_bytes_tx); } } - fprintf(fd,"%s",output); } void clear_pusch_stats(PHY_VARS_gNB *gNB) { diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c index 7f51c3e488..5286fe8780 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c @@ -178,8 +178,6 @@ void clean_gNB_ulsch(NR_gNB_ULSCH_t *ulsch) ulsch->harq_processes[i]->rar_alloc=0; ulsch->harq_processes[i]->status=NR_SCH_IDLE; ulsch->harq_processes[i]->subframe_scheduling_flag=0; - ulsch->harq_processes[i]->phich_active=0; - ulsch->harq_processes[i]->phich_ACK=0; ulsch->harq_processes[i]->previous_first_rb=0; ulsch->harq_processes[i]->handled=0; ulsch->harq_processes[i]->delta_TF=0; @@ -266,8 +264,8 @@ void nr_processULSegment(void* arg) { int max_ldpc_iterations = p_decoderParms->numMaxIter; int8_t llrProcBuf[OAI_UL_LDPC_MAX_NUM_LLR] __attribute__ ((aligned(32))); - int16_t z [68*384]; - int8_t l [68*384]; + int16_t z [68*384 + 16] __attribute__ ((aligned(16))); + int8_t l [68*384 + 16] __attribute__ ((aligned(16))); __m128i *pv = (__m128i*)&z; __m128i *pl = (__m128i*)&l; @@ -328,7 +326,7 @@ void nr_processULSegment(void* arg) { ulsch_harq->e[r], ulsch_harq->C, rv_index, - (ulsch_harq->round==0)?1:0, + ulsch_harq->new_rx, E, ulsch_harq->F, Kr-ulsch_harq->F-2*(p_decoderParms->Z))==-1) { @@ -389,9 +387,10 @@ void nr_processULSegment(void* arg) { if (check_crc((uint8_t*)llrProcBuf,length_dec,ulsch_harq->F,crc_type)) { #ifdef PRINT_CRC_CHECK - LOG_I(PHY, "Segment %d CRC OK\n",r); + LOG_I(PHY, "Segment %d CRC OK, iterations %d/%d\n",r,no_iteration_ldpc,max_ldpc_iterations); #endif rdata->decodeIterations = no_iteration_ldpc; + if (rdata->decodeIterations > p_decoderParms->numMaxIter) rdata->decodeIterations--; } else { #ifdef PRINT_CRC_CHECK LOG_I(PHY, "CRC NOK\n"); @@ -466,9 +465,22 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, harq_process->TBS = pusch_pdu->pusch_data.tb_size; harq_process->round = nr_rv_round_map[pusch_pdu->pusch_data.rv_index]; + harq_process->new_rx = false; // flag to indicate if this is a new reception for this harq (initialized to false) + if (harq_process->round == 0) { + harq_process->new_rx = true; + harq_process->ndi = pusch_pdu->pusch_data.new_data_indicator; + } + + // this happens if there was a DTX in round 0 + if (harq_process->ndi != pusch_pdu->pusch_data.new_data_indicator) { + harq_process->new_rx = true; + harq_process->ndi = pusch_pdu->pusch_data.new_data_indicator; + LOG_E(PHY,"Missed ULSCH detection. NDI toggled but rv %d does not correspond to first reception\n",pusch_pdu->pusch_data.rv_index); + } + A = (harq_process->TBS)<<3; - LOG_D(PHY,"ULSCH Decoding, harq_pid %d TBS %d G %d mcs %d Nl %d nb_rb %d, Qm %d, n_layers %d\n",harq_pid,A,G, mcs, n_layers, nb_rb, Qm, n_layers); + LOG_D(PHY,"ULSCH Decoding, harq_pid %d TBS %d G %d mcs %d Nl %d nb_rb %d, Qm %d, n_layers %d, Coderate %d\n",harq_pid,A,G, mcs, n_layers, nb_rb, Qm, n_layers, R); if (R<1024) Coderate = (float) R /(float) 1024; @@ -514,13 +526,14 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, } } if (stats) { + stats->frame = frame; stats->rnti = ulsch->rnti; stats->round_trials[harq_process->round]++; for (int aarx=0;aarxnb_antennas_rx;aarx++) { stats->power[aarx]=dB_fixed_x10(pusch->ulsch_power[aarx]); stats->noise_power[aarx]=dB_fixed_x10(pusch->ulsch_noise_power[aarx]); } - if (harq_process->round == 0) { + if (harq_process->new_rx == 0) { stats->current_Qm = Qm; stats->current_RI = n_layers; stats->total_bytes_tx += harq_process->TBS; diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 0531a8b98f..28dd5ab219 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -304,6 +304,7 @@ void nr_idft(int32_t *z, uint32_t Msc_PUSCH) void nr_ulsch_extract_rbs_single(int32_t **rxdataF, NR_gNB_PUSCH *pusch_vars, + int slot, unsigned char symbol, uint8_t is_dmrs_symbol, nfapi_nr_pusch_pdu_t *pusch_pdu, @@ -320,7 +321,7 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF, int16_t *rxF,*rxF_ext; int *ul_ch0,*ul_ch0_ext; uint8_t delta = 0; - + int soffset = (slot&3)*frame_parms->symbols_per_slot*frame_parms->ofdm_symbol_size; #ifdef DEBUG_RB_EXT printf("--------------------symbol = %d-----------------------\n", symbol); @@ -339,7 +340,7 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF, for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { - rxF = (int16_t *)&rxdataF[aarx][symbol * frame_parms->ofdm_symbol_size]; + rxF = (int16_t *)&rxdataF[aarx][soffset+(symbol * frame_parms->ofdm_symbol_size)]; rxF_ext = (int16_t *)&pusch_vars->rxdataF_ext[aarx][symbol * nb_re_pusch2]; // [hna] rxdataF_ext isn't contiguous in order to solve an alignment problem ib llr computation in case of mod_order = 4, 6 ul_ch0 = &pusch_vars->ul_ch_estimates[aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available @@ -581,22 +582,29 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, unsigned short nb_rb, unsigned char output_shift) { +#ifdef __AVX2__ + int off = ((nb_rb&1) == 1)? 4:0; +#else + int off = 0; +#endif #ifdef DEBUG_CH_COMP int16_t *rxF, *ul_ch; int prnt_idx; - rxF = (int16_t *)&rxdataF_ext[0][symbol*(off+(nb_rb*12))]; - ul_ch = (int16_t *)&ul_ch_estimates_ext[0][symbol*(off+(nb_rb*1))2]; + for (int ant=0; antnb_antennas_rx; ant++) { + rxF = (int16_t *)&rxdataF_ext[ant][symbol*(off+(nb_rb*12))]; + ul_ch = (int16_t *)&ul_ch_estimates_ext[ant][symbol*(off+(nb_rb*12))]; - printf("--------------------symbol = %d, mod_order = %d, output_shift = %d-----------------------\n", symbol, mod_order, output_shift); - printf("----------------Before compensation------------------\n"); + printf("--------------------symbol = %d, mod_order = %d, output_shift = %d-----------------------\n", symbol, mod_order, output_shift); + printf("----------------Before compensation------------------\n"); - for (prnt_idx=0;prnt_idx<12*nb_rb*2;prnt_idx+=2){ + for (prnt_idx=0;prnt_idx<12*5*2;prnt_idx+=2){ - printf("rxF[%d] = (%d,%d)\n", prnt_idx>>1, rxF[prnt_idx],rxF[prnt_idx+1]); - printf("ul_ch[%d] = (%d,%d)\n", prnt_idx>>1, ul_ch[prnt_idx],ul_ch[prnt_idx+1]); + printf("rxF[%d] = (%d,%d)\n", prnt_idx>>1, rxF[prnt_idx],rxF[prnt_idx+1]); + printf("ul_ch[%d] = (%d,%d)\n", prnt_idx>>1, ul_ch[prnt_idx],ul_ch[prnt_idx+1]); + } } #endif @@ -606,25 +614,21 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, int print_idx; - ch_mag = (int16_t *)&ul_ch_mag[0][symbol*(off+(nb_rb*12))]; + for (int ant=0; antnb_antennas_rx; ant++) { + ch_mag = (int16_t *)&ul_ch_mag[ant][symbol*(off+(nb_rb*12))]; - printf("--------------------symbol = %d, mod_order = %d-----------------------\n", symbol, mod_order); - printf("----------------Before computation------------------\n"); + printf("--------------------symbol = %d, mod_order = %d-----------------------\n", symbol, mod_order); + printf("----------------Before computation------------------\n"); - for (print_idx=0;print_idx<50;print_idx++){ + for (print_idx=0;print_idx<5;print_idx++){ - printf("ch_mag[%d] = %d\n", print_idx, ch_mag[print_idx]); + printf("ch_mag[%d] = %d\n", print_idx, ch_mag[print_idx]); + } } #endif -#ifdef __AVX2__ - int off = ((nb_rb&1) == 1)? 4:0; -#else - int off = 0; -#endif - #if defined(__i386) || defined(__x86_64__) unsigned short rb; @@ -1067,14 +1071,16 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, #ifdef DEBUG_CH_COMP - rxF = (int16_t *)&rxdataF_comp[0][(symbol*(off+(nb_rb*12)))]; + for (int ant=0; antnb_antennas_rx; ant++) { + rxF = (int16_t *)&rxdataF_comp[ant][(symbol*(off+(nb_rb*12)))]; - printf("----------------After compansation------------------\n"); + printf("----------------After compansation------------------\n"); - for (prnt_idx=0;prnt_idx<12*nb_rb*2;prnt_idx+=2){ + for (prnt_idx=0;prnt_idx<12*5*2;prnt_idx+=2){ - printf("rxF[%d] = (%d,%d)\n", prnt_idx>>1, rxF[prnt_idx],rxF[prnt_idx+1]); + printf("rxF[%d] = (%d,%d)\n", prnt_idx>>1, rxF[prnt_idx],rxF[prnt_idx+1]); + } } #endif @@ -1082,14 +1088,16 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext, #ifdef DEBUG_CH_MAG - ch_mag = (int16_t *)&ul_ch_mag[0][(symbol*(off+(nb_rb*12)))]; + for (int ant=0; antnb_antennas_rx; ant++) { + ch_mag = (int16_t *)&ul_ch_mag[ant][(symbol*(off+(nb_rb*12)))]; - printf("----------------After computation------------------\n"); + printf("----------------After computation------------------\n"); - for (print_idx=0;print_idx<12*nb_rb*2;print_idx+=2){ + for (print_idx=0;print_idx<12*5*2;print_idx+=2){ - printf("ch_mag[%d] = (%d,%d)\n", print_idx>>1, ch_mag[print_idx],ch_mag[print_idx+1]); + printf("ch_mag[%d] = (%d,%d)\n", print_idx>>1, ch_mag[print_idx],ch_mag[print_idx+1]); + } } #endif @@ -1124,13 +1132,13 @@ void nr_ulsch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, rxdataF_comp128[aa] = (__m128i *)&rxdataF_comp[aa][(symbol*(nb_re + off))]; ul_ch_mag128[aa] = (__m128i *)&ul_ch_mag[aa][(symbol*(nb_re + off))]; ul_ch_mag128b[aa] = (__m128i *)&ul_ch_magb[aa][(symbol*(nb_re + off))]; - + } + for (int aa=1;aanb_antennas_rx;aa++) { // MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation) for (i=0; ipusch_vars[ulsch_id]->cl_done = 0; bwp_start_subcarrier = ((rel15_ul->rb_start + rel15_ul->bwp_start)*NR_NB_SC_PER_RB + frame_parms->first_carrier_offset) % frame_parms->ofdm_symbol_size; - LOG_D(PHY,"bwp_start_subcarrier %d, rb_start %d, first_carrier_offset %d\n", bwp_start_subcarrier, rel15_ul->rb_start, frame_parms->first_carrier_offset); - LOG_D(PHY,"ul_dmrs_symb_pos %x\n",rel15_ul->ul_dmrs_symb_pos); + LOG_D(PHY,"pusch %d.%d : bwp_start_subcarrier %d, rb_start %d, first_carrier_offset %d\n", frame,slot,bwp_start_subcarrier, rel15_ul->rb_start, frame_parms->first_carrier_offset); + LOG_D(PHY,"pusch %d.%d : ul_dmrs_symb_pos %x\n",frame,slot,rel15_ul->ul_dmrs_symb_pos); //---------------------------------------------------------- //--------------------- Channel estimation --------------------- @@ -1257,6 +1265,7 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, start_meas(&gNB->ulsch_rbs_extraction_stats); nr_ulsch_extract_rbs_single(gNB->common_vars.rxdataF, gNB->pusch_vars[ulsch_id], + slot, symbol, dmrs_symbol_flag, rel15_ul, @@ -1289,7 +1298,7 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, for (aarx=0;aarxnb_antennas_rx;aarx++) avgs = cmax(avgs,avg[aatx*frame_parms->nb_antennas_rx+aarx]); - gNB->pusch_vars[ulsch_id]->log2_maxh = (log2_approx(avgs)/2)+3; + gNB->pusch_vars[ulsch_id]->log2_maxh = (log2_approx(avgs)/2)+2; gNB->pusch_vars[ulsch_id]->cl_done = 1; } @@ -1297,6 +1306,7 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, //--------------------- Channel Compensation --------------- //---------------------------------------------------------- start_meas(&gNB->ulsch_channel_compensation_stats); + LOG_D(PHY,"Doing channel compensations log2_maxh %d, avgs %d (%d,%d)\n",gNB->pusch_vars[ulsch_id]->log2_maxh,avgs,avg[0],avg[1]); nr_ulsch_channel_compensation(gNB->pusch_vars[ulsch_id]->rxdataF_ext, gNB->pusch_vars[ulsch_id]->ul_ch_estimates_ext, gNB->pusch_vars[ulsch_id]->ul_ch_mag0, @@ -1315,8 +1325,8 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, start_meas(&gNB->ulsch_mrc_stats); nr_ulsch_detection_mrc(frame_parms, gNB->pusch_vars[ulsch_id]->rxdataF_comp, - gNB->pusch_vars[ulsch_id]->ul_ch_mag, - gNB->pusch_vars[ulsch_id]->ul_ch_magb, + gNB->pusch_vars[ulsch_id]->ul_ch_mag0, + gNB->pusch_vars[ulsch_id]->ul_ch_magb0, symbol, rel15_ul->rb_size); stop_meas(&gNB->ulsch_mrc_stats); diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index e3b87ff233..cdc6825d4c 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -170,7 +170,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, int32_t **rxdataF = gNB->common_vars.rxdataF; NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; - + int soffset=(slot&3)*frame_parms->symbols_per_slot*frame_parms->ofdm_symbol_size; int nr_sequences; const uint8_t *mcs; @@ -206,7 +206,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, nr_sequences=8>>(1-pucch_pdu->sr_flag); } - LOG_D(PHY,"pucch0: nr_symbols %d, start_symbol %d, prb_start %d, second_hop_prb %d, group_hop_flag %d, sequence_hop_flag %d, O_ACK %d, O_SR %d, mcs %d\n",pucch_pdu->nr_of_symbols,pucch_pdu->start_symbol_index,pucch_pdu->prb_start,pucch_pdu->second_hop_prb,pucch_pdu->group_hop_flag,pucch_pdu->sequence_hop_flag,pucch_pdu->bit_len_harq,pucch_pdu->sr_flag,mcs[0]); + LOG_D(PHY,"pucch0: nr_symbols %d, start_symbol %d, prb_start %d, second_hop_prb %d, group_hop_flag %d, sequence_hop_flag %d, O_ACK %d, O_SR %d, mcs %d initial_cyclic_shift %d\n",pucch_pdu->nr_of_symbols,pucch_pdu->start_symbol_index,pucch_pdu->prb_start,pucch_pdu->second_hop_prb,pucch_pdu->group_hop_flag,pucch_pdu->sequence_hop_flag,pucch_pdu->bit_len_harq,pucch_pdu->sr_flag,mcs[0],pucch_pdu->initial_cyclic_shift); int cs_ind = get_pucch0_cs_lut_index(gNB,pucch_pdu); /* @@ -238,7 +238,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, // x_n contains the sequence r_u_v_alpha_delta(n) - int n,i,l; + int n,i; int prb_offset[2] = {pucch_pdu->bwp_start+pucch_pdu->prb_start, pucch_pdu->bwp_start+pucch_pdu->prb_start}; nr_group_sequence_hopping(pucch_GroupHopping,pucch_pdu->hopping_id,0,slot,&u[0],&v[0]); // calculating u and v value first hop @@ -251,6 +251,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, prb_offset[1] = pucch_pdu->bwp_start+pucch_pdu->second_hop_prb; } + AssertFatal(pucch_pdu->nr_of_symbols < 3,"nr_of_symbols %d not allowed\n",pucch_pdu->nr_of_symbols); uint32_t re_offset[2]={0,0}; uint8_t l2; @@ -261,106 +262,143 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, x_re[1] = table_5_2_2_2_2_Re[u[1]]; x_im[1] = table_5_2_2_2_2_Im[u[1]]; - int16_t xr[2][24] __attribute__((aligned(32))); - int64_t xrtmag=0; + int16_t xr[1+frame_parms->nb_antennas_rx][1+pucch_pdu->nr_of_symbols][24] __attribute__((aligned(32))); + int64_t xrtmag=0,xrtmag_next=0; uint8_t maxpos=0; uint8_t index=0; - memset((void*)xr[0],0,24*sizeof(int16_t)); - memset((void*)xr[1],0,24*sizeof(int16_t)); + for (int l=0; lnr_of_symbols; l++) { + for (int aarx=0;aarxnb_antennas_rx;aarx++) { + memset((void*)xr[aarx][l],0,24*sizeof(int16_t)); + } + } int n2; - for (l=0; lnr_of_symbols; l++) { + for (int l=0; lnr_of_symbols; l++) { l2 = l+pucch_pdu->start_symbol_index; re_offset[l] = (12*prb_offset[l]) + frame_parms->first_carrier_offset; if (re_offset[l]>= frame_parms->ofdm_symbol_size) re_offset[l]-=frame_parms->ofdm_symbol_size; AssertFatal(re_offset[l]+12 < frame_parms->ofdm_symbol_size,"pucch straddles DC carrier, handle this!\n"); - - int16_t *r=(int16_t*)&rxdataF[0][(l2*frame_parms->ofdm_symbol_size)+re_offset[l]]; - n2=0; - for (n=0;n<12;n++,n2+=2) { - xr[l][n2] =(int16_t)(((int32_t)x_re[l][n]*r[n2]+(int32_t)x_im[l][n]*r[n2+1])>>15); - xr[l][n2+1]=(int16_t)(((int32_t)x_re[l][n]*r[n2+1]-(int32_t)x_im[l][n]*r[n2])>>15); + int16_t *r; + for (int aa=0;aanb_antennas_rx;aa++) { + r=(int16_t*)&rxdataF[aa][soffset+(l2*frame_parms->ofdm_symbol_size)+re_offset[l]]; + n2=0; + for (n=0;n<12;n++,n2+=2) { + xr[aa][l][n2] +=(int16_t)(((int32_t)x_re[l][n]*r[n2]+(int32_t)x_im[l][n]*r[n2+1])>>15); + xr[aa][l][n2+1]+=(int16_t)(((int32_t)x_re[l][n]*r[n2+1]-(int32_t)x_im[l][n]*r[n2])>>15); #ifdef DEBUG_NR_PUCCH_RX - printf("x (%d,%d), r%d.%d (%d,%d), xr (%d,%d)\n", - x_re[l][n],x_im[l][n],l2,re_offset[l],r[n2],r[n2+1],xr[l][n2],xr[l][n2+1]); + printf("x (%d,%d), r%d.%d (%d,%d), xr (%d,%d)\n", + x_re[l][n],x_im[l][n],l2,re_offset[l],r[n2],r[n2+1],xr[aa][l][n2],xr[aa][l][n2+1]); #endif + } } } - int32_t corr_re[2]; - int32_t corr_im[2]; - + int32_t corr_re[1+frame_parms->nb_antennas_rx][2]; + int32_t corr_im[1+frame_parms->nb_antennas_rx][2]; + //int32_t no_corr = 0; int seq_index; int64_t temp; - int64_t av_corr=0; for(i=0;inr_of_symbols;l++) { - corr_re[l]=0; - corr_im[l]=0; + + for (int l=0;lnr_of_symbols;l++) { seq_index = (pucch_pdu->initial_cyclic_shift+ mcs[i]+ gNB->pucch0_lut.lut[cs_ind][slot][l+pucch_pdu->start_symbol_index])%12; #ifdef DEBUG_NR_PUCCH_RX printf("PUCCH symbol %d seq %d, seq_index %d, mcs %d\n",l,i,seq_index,mcs[i]); #endif - n2=0; - for (n=0;n<12;n++,n2+=2) { - corr_re[l]+=(xr[l][n2]*idft12_re[seq_index][n]+xr[l][n2+1]*idft12_im[seq_index][n])>>15; - corr_im[l]+=(xr[l][n2]*idft12_im[seq_index][n]-xr[l][n2+1]*idft12_re[seq_index][n])>>15; + for (int aa=0;aanb_antennas_rx;aa++) { + corr_re[aa][l]=0; + corr_im[aa][l]=0; + + n2=0; + for (n=0;n<12;n++,n2+=2) { + corr_re[aa][l]+=(xr[aa][l][n2]*idft12_re[seq_index][n]+xr[aa][l][n2+1]*idft12_im[seq_index][n])>>15; + corr_im[aa][l]+=(xr[aa][l][n2]*idft12_im[seq_index][n]-xr[aa][l][n2+1]*idft12_re[seq_index][n])>>15; + } } } - -#ifdef DEBUG_NR_PUCCH_RX - LOG_I(PHY,"PUCCH IDFT = (%d,%d)=>%f\n",corr_re[0],corr_im[0],10*log10((double)corr_re[0]*corr_re[0] + (double)corr_im[0]*corr_im[0])); - if (l>1) LOG_I(PHY,"PUCCH 2nd symbol IDFT[%d/%d] = (%d,%d)=>%f\n",mcs[i],seq_index,corr_re[1],corr_im[1],10*log10((double)corr_re[1]*corr_re[1] + (double)corr_im[1]*corr_im[1])); -#endif - if (pucch_pdu->freq_hop_flag == 0 && l==1) // non-coherent correlation - temp=(int64_t)corr_re[0]*corr_re[0] + (int64_t)corr_im[0]*corr_im[0]; - else if (pucch_pdu->freq_hop_flag == 0 && l==2) { - int64_t corr_re2 = (int64_t)corr_re[0]+corr_re[1]; - int64_t corr_im2 = (int64_t)corr_im[0]+corr_im[1]; - // coherent combining of 2 symbols and then complex modulus for single-frequency case - temp=corr_re2*corr_re2 + corr_im2*corr_im2; - } - else if (pucch_pdu->freq_hop_flag == 1) + LOG_D(PHY,"PUCCH IDFT[%d/%d] = (%d,%d)=>%f\n", + mcs[i],seq_index,corr_re[0][0],corr_im[0][0], + 10*log10((double)corr_re[0][0]*corr_re[0][0] + (double)corr_im[0][0]*corr_im[0][0])); + if (pucch_pdu->nr_of_symbols==2) + LOG_D(PHY,"PUCCH 2nd symbol IDFT[%d/%d] = (%d,%d)=>%f\n", + mcs[i],seq_index,corr_re[0][1],corr_im[0][1], + 10*log10((double)corr_re[0][1]*corr_re[0][1] + (double)corr_im[0][1]*corr_im[0][1])); + if (pucch_pdu->freq_hop_flag == 0) { + if (pucch_pdu->nr_of_symbols==1) {// non-coherent correlation + temp=0; + for (int aa=0;aanb_antennas_rx;aa++) + temp+=(int64_t)corr_re[aa][0]*corr_re[aa][0] + (int64_t)corr_im[aa][0]*corr_im[aa][0]; + } else { + int64_t corr_re2=0; + int64_t corr_im2=0; + temp=0; + for (int aa=0;aanb_antennas_rx;aa++) { + corr_re2 = (int64_t)corr_re[aa][0]+corr_re[aa][1]; + corr_im2 = (int64_t)corr_im[aa][0]+corr_im[aa][1]; + // coherent combining of 2 symbols and then complex modulus for single-frequency case + temp+=corr_re2*corr_re2 + corr_im2*corr_im2; + } + } + } else if (pucch_pdu->freq_hop_flag == 1) { // full non-coherent combining of 2 symbols for frequency-hopping case - temp = (int64_t)corr_re[0]*corr_re[0] + (int64_t)corr_im[0]*corr_im[0] + (int64_t)corr_re[1]*corr_re[1] + (int64_t)corr_im[1]*corr_im[1]; + temp=0; + for (int aa=0;aanb_antennas_rx;aa++) + temp += (int64_t)corr_re[aa][0]*corr_re[aa][0] + (int64_t)corr_im[aa][0]*corr_im[aa][0] + (int64_t)corr_re[aa][1]*corr_re[aa][1] + (int64_t)corr_im[aa][1]*corr_im[aa][1]; + } else AssertFatal(1==0,"shouldn't happen\n"); - av_corr+=temp; if (temp>xrtmag) { + xrtmag_next = xrtmag; xrtmag=temp; + LOG_D(PHY,"Sequence %d xrtmag %ld xrtmag_next %ld\n", i, xrtmag, xrtmag_next); maxpos=i; - uci_stats->current_pucch0_stat0 = dB_fixed64((int64_t)corr_re[0]*corr_re[0] + (int64_t)corr_im[0]*corr_im[0]); - if (l==2) uci_stats->current_pucch0_stat1 = dB_fixed64((int64_t)corr_re[1]*corr_re[1] + (int64_t)corr_im[1]*corr_im[1]); + uci_stats->current_pucch0_stat0 = 0; + int64_t temp2=0,temp3=0;; + for (int aa=0;aanb_antennas_rx;aa++) { + temp2 += ((int64_t)corr_re[aa][0]*corr_re[aa][0] + (int64_t)corr_im[aa][0]*corr_im[aa][0]); + if (pucch_pdu->nr_of_symbols==2) + temp3 += ((int64_t)corr_re[aa][1]*corr_re[aa][1] + (int64_t)corr_im[aa][1]*corr_im[aa][1]); + } + uci_stats->current_pucch0_stat0= dB_fixed64(temp2); + if ( pucch_pdu->nr_of_symbols==2) + uci_stats->current_pucch0_stat1= dB_fixed64(temp3); } + else if (temp>xrtmag_next) + xrtmag_next = temp; } - av_corr/=nr_sequences/l; - - uint8_t xrtmag_dB = dB_fixed64(xrtmag); - + int xrtmag_dBtimes10 = 10*(int)dB_fixed64(xrtmag/(12*pucch_pdu->nr_of_symbols)); + int xrtmag_next_dBtimes10 = 10*(int)dB_fixed64(xrtmag_next/(12*pucch_pdu->nr_of_symbols)); #ifdef DEBUG_NR_PUCCH_RX printf("PUCCH 0 : maxpos %d\n",maxpos); #endif index=maxpos; - + uci_stats->pucch0_n00 = gNB->measurements.n0_subband_power_tot_dB[prb_offset[0]]; + uci_stats->pucch0_n01 = gNB->measurements.n0_subband_power_tot_dB[prb_offset[1]]; + LOG_D(PHY,"n00[%d] = %d, n01[%d] = %d\n",prb_offset[0],uci_stats->pucch0_n00,prb_offset[1],uci_stats->pucch0_n01); // estimate CQI for MAC (from antenna port 0 only) int max_n0 = uci_stats->pucch0_n00>uci_stats->pucch0_n01 ? uci_stats->pucch0_n00:uci_stats->pucch0_n01; - int SNRtimes10 = dB_fixed_times10(signal_energy_nodc(&rxdataF[0][pucch_pdu->start_symbol_index*frame_parms->ofdm_symbol_size+re_offset[0]],12)) - (10*max_n0); + int SNRtimes10,sigenergy=0; + for (int aa=0;aanb_antennas_rx;aa++) + sigenergy += signal_energy_nodc(&rxdataF[aa][soffset+ + (pucch_pdu->start_symbol_index*frame_parms->ofdm_symbol_size)+ + re_offset[0]],12); + SNRtimes10 = xrtmag_dBtimes10-(10*max_n0); int cqi; if (SNRtimes10 < -640) cqi=0; else if (SNRtimes10 > 635) cqi=255; else cqi=(640+SNRtimes10)/5; - uci_stats->pucch0_thres = gNB->pucch0_thres + (10*max_n0); + uci_stats->pucch0_thres = gNB->pucch0_thres; /* + (10*max_n0);*/ bool no_conf=false; if (nr_sequences>1) { - if (10*xrtmag_dB < uci_stats->pucch0_thres) + if (xrtmag_dBtimes10 < (50+xrtmag_next_dBtimes10) || SNRtimes10 < uci_stats->pucch0_thres) no_conf=true; } gNB->bad_pucch += no_conf; @@ -370,16 +408,14 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_pdu->rnti = pucch_pdu->rnti; uci_pdu->ul_cqi = cqi; uci_pdu->timing_advance = 0xffff; // currently not valid - uci_pdu->rssi = 1280 - (10*dB_fixed(32767*32767)-dB_fixed_times10(signal_energy_nodc(&rxdataF[0][pucch_pdu->start_symbol_index*frame_parms->ofdm_symbol_size+re_offset[0]],12))); + uci_pdu->rssi = 1280 - (10*dB_fixed(32767*32767))-dB_fixed_times10(sigenergy); - uci_stats->pucch0_n00 = gNB->measurements.n0_subband_power_tot_dB[prb_offset[0]]; - uci_stats->pucch0_n01 = gNB->measurements.n0_subband_power_tot_dB[prb_offset[1]]; if (pucch_pdu->bit_len_harq==0) { uci_pdu->harq = NULL; uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr)); uci_pdu->sr->sr_confidence_level = no_conf ? 1 : 0; uci_stats->pucch0_sr_trials++; - if (xrtmag_dB>(gNB->measurements.n0_power_tot_dB)) { + if (xrtmag_dBtimes10>(10*gNB->measurements.n0_power_tot_dB)) { uci_pdu->sr->sr_indication = 1; uci_stats->pucch0_positive_SR++; } else { @@ -392,8 +428,8 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_pdu->harq->harq_confidence_level = no_conf ? 1 : 0; uci_pdu->harq->harq_list = (nfapi_nr_harq_t*)malloc(1); uci_pdu->harq->harq_list[0].harq_value = index&0x01; - LOG_D(PHY, "Slot %d HARQ value %d with confidence level (0 is good, 1 is bad) %d xrt_mag %d n0 %d pucch0_thres %d\n", - slot,uci_pdu->harq->harq_list[0].harq_value,uci_pdu->harq->harq_confidence_level,xrtmag_dB,max_n0,uci_stats->pucch0_thres); + LOG_D(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ value %d with confidence level (0 is good, 1 is bad) %d xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d, energy %f, sync_pos %d\n", + frame,slot,uci_pdu->harq->harq_list[0].harq_value,uci_pdu->harq->harq_confidence_level,xrtmag_dBtimes10,xrtmag_next_dBtimes10,max_n0,uci_stats->pucch0_n00,uci_stats->pucch0_n01,uci_stats->pucch0_thres,cqi,SNRtimes10,10*log10((double)sigenergy),gNB->ulsch_stats[0].sync_pos); if (pucch_pdu->sr_flag == 1) { uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr)); uci_pdu->sr->sr_indication = (index>1) ? 1 : 0; @@ -409,8 +445,8 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_pdu->harq->harq_list = (nfapi_nr_harq_t*)malloc(2); uci_pdu->harq->harq_list[1].harq_value = index&0x01; uci_pdu->harq->harq_list[0].harq_value = (index>>1)&0x01; - LOG_D(PHY, "Slot %d HARQ values %d and %d with confidence level (0 is good, 1 is bad) %d, xrt_mag %d\n", - slot,uci_pdu->harq->harq_list[1].harq_value,uci_pdu->harq->harq_list[0].harq_value,uci_pdu->harq->harq_confidence_level,xrtmag_dB); + LOG_D(PHY, "[DLSCH/PDSCH/PUCCH] %d.%d HARQ values %d and %d with confidence level (0 is good, 1 is bad) %d, xrt_mag %d xrt_mag_next %d n0 %d (%d,%d) pucch0_thres %d, cqi %d, SNRtimes10 %d,sync_pos %d\n", + frame,slot,uci_pdu->harq->harq_list[1].harq_value,uci_pdu->harq->harq_list[0].harq_value,uci_pdu->harq->harq_confidence_level,xrtmag_dBtimes10,xrtmag_next_dBtimes10,max_n0,uci_stats->pucch0_n00,uci_stats->pucch0_n01,uci_stats->pucch0_thres,cqi,SNRtimes10,gNB->ulsch_stats[0].sync_pos); if (pucch_pdu->sr_flag == 1) { uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr)); uci_pdu->sr->sr_indication = (index>3) ? 1 : 0; @@ -445,6 +481,7 @@ void nr_decode_pucch1( int32_t **rxdataF, * Implement TS 38.211 Subclause 6.3.2.4.1 Sequence modulation * */ + int soffset = (nr_tti_tx&3)*frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size; // complex-valued symbol d_re, d_im containing complex-valued symbol d(0): int16_t d_re=0, d_im=0,d1_re=0,d1_im=0; #ifdef DEBUG_NR_PUCCH_RX @@ -539,23 +576,23 @@ void nr_decode_pucch1( int32_t **rxdataF, } if (l%2 == 1) { // mapping PUCCH according to TS38.211 subclause 6.4.1.3.1 - z_re_rx[i+n] = ((int16_t *)&rxdataF[0][re_offset])[0]; - z_im_rx[i+n] = ((int16_t *)&rxdataF[0][re_offset])[1]; + z_re_rx[i+n] = ((int16_t *)&rxdataF[0][soffset+re_offset])[0]; + z_im_rx[i+n] = ((int16_t *)&rxdataF[0][soffset+re_offset])[1]; #ifdef DEBUG_NR_PUCCH_RX printf("\t [nr_generate_pucch1] mapping PUCCH to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \tz_pucch[%d]=txptr(%u)=(x_n(l=%d,n=%d)=(%d,%d))\n", amp,frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,i+n,re_offset, - l,n,((int16_t *)&rxdataF[0][re_offset])[0],((int16_t *)&rxdataF[0][re_offset])[1]); + l,n,((int16_t *)&rxdataF[0][soffset+re_offset])[0],((int16_t *)&rxdataF[0][soffset+re_offset])[1]); #endif } if (l%2 == 0) { // mapping DM-RS signal according to TS38.211 subclause 6.4.1.3.1 - z_dmrs_re_rx[i+n] = ((int16_t *)&rxdataF[0][re_offset])[0]; - z_dmrs_im_rx[i+n] = ((int16_t *)&rxdataF[0][re_offset])[1]; + z_dmrs_re_rx[i+n] = ((int16_t *)&rxdataF[0][soffset+re_offset])[0]; + z_dmrs_im_rx[i+n] = ((int16_t *)&rxdataF[0][soffset+re_offset])[1]; // printf("%d\t%d\t%d\n",l,z_dmrs_re_rx[i+n],z_dmrs_im_rx[i+n]); #ifdef DEBUG_NR_PUCCH_RX printf("\t [nr_generate_pucch1] mapping DM-RS to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \tz_dm-rs[%d]=txptr(%u)=(x_n(l=%d,n=%d)=(%d,%d))\n", amp,frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,i+n,re_offset, - l,n,((int16_t *)&rxdataF[0][re_offset])[0],((int16_t *)&rxdataF[0][re_offset])[1]); + l,n,((int16_t *)&rxdataF[0][soffset+re_offset])[0],((int16_t *)&rxdataF[0][soffset+re_offset])[1]); #endif // printf("l=%d\ti=%d\tre_offset=%d\treceived dmrs re=%d\tim=%d\n",l,i,re_offset,z_dmrs_re_rx[i+n],z_dmrs_im_rx[i+n]); } @@ -1081,85 +1118,109 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, //extract pucch and dmrs first int l2=pucch_pdu->start_symbol_index; - int re_offset = (12*pucch_pdu->prb_start) + (12*pucch_pdu->bwp_start) + frame_parms->first_carrier_offset; - if (re_offset>= frame_parms->ofdm_symbol_size) - re_offset-=frame_parms->ofdm_symbol_size; - + int re_offset[2]; + re_offset[0] = 12*(pucch_pdu->prb_start+pucch_pdu->bwp_start) + frame_parms->first_carrier_offset; + int soffset=(slot&3)*frame_parms->symbols_per_slot*frame_parms->ofdm_symbol_size; + + if (re_offset[0]>= frame_parms->ofdm_symbol_size) + re_offset[0]-=frame_parms->ofdm_symbol_size; + if (pucch_pdu->freq_hop_flag == 0) re_offset[1] = re_offset[0]; + else { + re_offset[1] = 12*(pucch_pdu->second_hop_prb+pucch_pdu->bwp_start) + frame_parms->first_carrier_offset; + if (re_offset[1]>= frame_parms->ofdm_symbol_size) + re_offset[1]-=frame_parms->ofdm_symbol_size; + } AssertFatal(pucch_pdu->prb_size*pucch_pdu->nr_of_symbols > 1,"number of PRB*SYMB (%d,%d)< 2", pucch_pdu->prb_size,pucch_pdu->nr_of_symbols); int Prx = gNB->gNB_config.carrier_config.num_rx_ant.value; int Prx2 = (Prx==1)?2:Prx; // use 2 for Nb antennas in case of single antenna to allow the following allocations - int16_t r_re_ext[Prx2][8*pucch_pdu->nr_of_symbols*pucch_pdu->prb_size] __attribute__((aligned(32))); - int16_t r_im_ext[Prx2][8*pucch_pdu->nr_of_symbols*pucch_pdu->prb_size] __attribute__((aligned(32))); - int16_t r_re_ext2[Prx2][8*pucch_pdu->nr_of_symbols*pucch_pdu->prb_size] __attribute__((aligned(32))); - int16_t r_im_ext2[Prx2][8*pucch_pdu->nr_of_symbols*pucch_pdu->prb_size] __attribute__((aligned(32))); - int16_t rd_re_ext[Prx2][4*pucch_pdu->nr_of_symbols*pucch_pdu->prb_size] __attribute__((aligned(32))); - int16_t rd_im_ext[Prx2][4*pucch_pdu->nr_of_symbols*pucch_pdu->prb_size] __attribute__((aligned(32))); + int prb_size_ext = pucch_pdu->prb_size+(pucch_pdu->prb_size&1); + int16_t r_re_ext[Prx2][2][8*prb_size_ext] __attribute__((aligned(32))); + int16_t r_im_ext[Prx2][2][8*prb_size_ext] __attribute__((aligned(32))); + int16_t r_re_ext2[Prx2][2][8*prb_size_ext] __attribute__((aligned(32))); + int16_t r_im_ext2[Prx2][2][8*prb_size_ext] __attribute__((aligned(32))); + int16_t rd_re_ext[Prx2][2][4*prb_size_ext] __attribute__((aligned(32))); + int16_t rd_im_ext[Prx2][2][4*prb_size_ext] __attribute__((aligned(32))); int16_t *r_re_ext_p,*r_im_ext_p,*rd_re_ext_p,*rd_im_ext_p; int nb_re_pucch = 12*pucch_pdu->prb_size; - int16_t rp[Prx2][nb_re_pucch*2],*tmp_rp; + int16_t rp[Prx2][2][nb_re_pucch*2],*tmp_rp; __m64 dmrs_re,dmrs_im; for (int aa=0;aaofdm_symbol_size]); + for (int symb=0;symbnr_of_symbols;symb++) { + tmp_rp = ((int16_t *)&rxdataF[aa][soffset + (l2+symb)*frame_parms->ofdm_symbol_size]); - if (re_offset + nb_re_pucch < frame_parms->ofdm_symbol_size) { - memcpy1((void*)rp[aa],(void*)&tmp_rp[re_offset*2],nb_re_pucch*sizeof(int32_t)); - } - else { - int neg_length = frame_parms->ofdm_symbol_size-re_offset; - int pos_length = nb_re_pucch-neg_length; - memcpy1((void*)rp[aa],(void*)&tmp_rp[re_offset*2],neg_length*sizeof(int32_t)); - memcpy1((void*)&rp[aa][neg_length*2],(void*)tmp_rp,pos_length*sizeof(int32_t)); + if (re_offset[symb] + nb_re_pucch < frame_parms->ofdm_symbol_size) { + memcpy1((void*)rp[aa][symb],(void*)&tmp_rp[re_offset[symb]*2],nb_re_pucch*sizeof(int32_t)); + } + else { + int neg_length = frame_parms->ofdm_symbol_size-re_offset[symb]; + int pos_length = nb_re_pucch-neg_length; + memcpy1((void*)rp[aa][symb],(void*)&tmp_rp[re_offset[symb]*2],neg_length*sizeof(int32_t)); + memcpy1((void*)&rp[aa][symb][neg_length*2],(void*)tmp_rp,pos_length*sizeof(int32_t)); + } } } - #ifdef DEBUG_NR_PUCCH_RX printf("Decoding pucch2 for %d symbols, %d PRB\n",pucch_pdu->nr_of_symbols,pucch_pdu->prb_size); #endif int nc_group_size=1; // 2 PRB - int ngroup = pucch_pdu->prb_size/nc_group_size/2; - int32_t corr32_re[ngroup][Prx2],corr32_im[ngroup][Prx2]; - for (int aa=0;aanr_of_symbols == 1) { - AssertFatal((pucch_pdu->prb_size&1) == 0,"prb_size %d is not a multiple of 2\n",pucch_pdu->prb_size); - // 24 PRBs contains 48x16-bit, so 6x8x16-bit + // AssertFatal((pucch_pdu->prb_size&1) == 0,"prb_size %d is not a multiple of 2\n",pucch_pdu->prb_size); + if ((pucch_pdu->prb_size&1) > 0) { // if the number of PRBs is odd + for (int symb=0; symbnr_of_symbols;symb++) { + for (int aa=0;aaprb_size],0,8*pucch_pdu->prb_size*sizeof(int16_t)); + memset(&r_im_ext[aa][symb][8*pucch_pdu->prb_size],0,8*pucch_pdu->prb_size*sizeof(int16_t)); + memset(&rd_re_ext[aa][symb][4*pucch_pdu->prb_size],0,8*pucch_pdu->prb_size*sizeof(int16_t)); + memset(&rd_im_ext[aa][symb][4*pucch_pdu->prb_size],0,8*pucch_pdu->prb_size*sizeof(int16_t)); + } + } + } + for (int symb=0; symbnr_of_symbols;symb++) { + // 24 REs contains 48x16-bit, so 6x8x16-bit for (int prb=0;prbprb_size;prb+=2) { for (int aa=0;aa (%d,%d)\n",aa,prb+(i>>2),i,rd_re_ext_p[i],rd_im_ext_p[i]); - for (int i=0;i<16;i++) printf("Ant %d PRB %d data[%d] -> (%d,%d)\n",aa,prb+(i>>3),i,r_re_ext_p[i],r_im_ext_p[i]); + for (int i=0;i<8;i++) printf("Ant %d PRB %d dmrs[%d] -> (%d,%d)\n",aa,prb+(i>>2),i,rd_re_ext_p[i],rd_im_ext_p[i]); + for (int i=0;i<16;i++) printf("Ant %d PRB %d data[%d] -> (%d,%d)\n",aa,prb+(i>>3),i,r_re_ext_p[i],r_im_ext_p[i]); #endif } // aa } // prb - // first compute DMRS component + uint32_t x1, x2, s=0; - x2 = (((1<<17)*((14*slot) + (pucch_pdu->start_symbol_index) + 1)*((2*pucch_pdu->dmrs_scrambling_id) + 1)) + (2*pucch_pdu->dmrs_scrambling_id))%(1U<<31); // c_init calculation according to TS38.211 subclause + x2 = (((1<<17)*((14*slot) + (pucch_pdu->start_symbol_index+symb) + 1)*((2*pucch_pdu->dmrs_scrambling_id) + 1)) + (2*pucch_pdu->dmrs_scrambling_id))%(1U<<31); // c_init calculation according to TS38.211 subclause #ifdef DEBUG_NR_PUCCH_RX - printf("slot %d, start_symbol_index %d, dmrs_scrambling_id %d\n", - slot,pucch_pdu->start_symbol_index,pucch_pdu->dmrs_scrambling_id); + printf("slot %d, start_symbol_index %d, symbol %d, dmrs_scrambling_id %d\n", + slot,pucch_pdu->start_symbol_index,symb,pucch_pdu->dmrs_scrambling_id); #endif int reset = 1; for (int i=0; i<=(pucch_pdu->prb_start>>2); i++) { @@ -1174,77 +1235,74 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, dmrs_im = byte2m64_im[((uint8_t*)&s)[(group&1)<<1]]; #ifdef DEBUG_NR_PUCCH_RX printf("Group %d: s %x x2 %x ((%d,%d),(%d,%d),(%d,%d),(%d,%d))\n", - group, - ((uint16_t*)&s)[0],x2, - ((int16_t*)&dmrs_re)[0],((int16_t*)&dmrs_im)[0], - ((int16_t*)&dmrs_re)[1],((int16_t*)&dmrs_im)[1], - ((int16_t*)&dmrs_re)[2],((int16_t*)&dmrs_im)[2], - ((int16_t*)&dmrs_re)[3],((int16_t*)&dmrs_im)[3]); + group, + ((uint16_t*)&s)[0],x2, + ((int16_t*)&dmrs_re)[0],((int16_t*)&dmrs_im)[0], + ((int16_t*)&dmrs_re)[1],((int16_t*)&dmrs_im)[1], + ((int16_t*)&dmrs_re)[2],((int16_t*)&dmrs_im)[2], + ((int16_t*)&dmrs_re)[3],((int16_t*)&dmrs_im)[3]); #endif for (int aa=0;aa>=5; - corr32_im[group][aa]>>=5; + corr32_re[symb][group][aa]+=(rd_re_ext_p[4]*((int16_t*)&dmrs_re)[0] + rd_im_ext_p[4]*((int16_t*)&dmrs_im)[0]); + corr32_im[symb][group][aa]+=(-rd_re_ext_p[4]*((int16_t*)&dmrs_im)[0] + rd_im_ext_p[4]*((int16_t*)&dmrs_re)[0]); + corr32_re[symb][group][aa]+=(rd_re_ext_p[5]*((int16_t*)&dmrs_re)[1] + rd_im_ext_p[5]*((int16_t*)&dmrs_im)[1]); + corr32_im[symb][group][aa]+=(-rd_re_ext_p[5]*((int16_t*)&dmrs_im)[1] + rd_im_ext_p[5]*((int16_t*)&dmrs_re)[1]); + corr32_re[symb][group][aa]+=(rd_re_ext_p[6]*((int16_t*)&dmrs_re)[2] + rd_im_ext_p[6]*((int16_t*)&dmrs_im)[2]); + corr32_im[symb][group][aa]+=(-rd_re_ext_p[6]*((int16_t*)&dmrs_im)[2] + rd_im_ext_p[6]*((int16_t*)&dmrs_re)[2]); + corr32_re[symb][group][aa]+=(rd_re_ext_p[7]*((int16_t*)&dmrs_re)[3] + rd_im_ext_p[7]*((int16_t*)&dmrs_im)[3]); + corr32_im[symb][group][aa]+=(-rd_re_ext_p[7]*((int16_t*)&dmrs_im)[3] + rd_im_ext_p[7]*((int16_t*)&dmrs_re)[3]); + /* corr32_re[group][aa]>>=5; + corr32_im[group][aa]>>=5;*/ #ifdef DEBUG_NR_PUCCH_RX - printf("Group %d: corr32 (%d,%d)\n",group,corr32_re[group][aa],corr32_im[group][aa]); + printf("Group %d: corr32 (%d,%d)\n",group,corr32_re[symb][group][aa],corr32_im[symb][group][aa]); #endif } //aa - + if ((group&1) == 1) s = lte_gold_generic(&x1, &x2, 0); } // group - } - else { // 2 symbol case - AssertFatal(1==0, "Fill in 2 symbol PUCCH2 case\n"); - } + } // symb uint32_t x1, x2, s=0; // unscrambling @@ -1253,112 +1311,114 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, #ifdef DEBUG_NR_PUCCH_RX printf("x2 %x, s %x\n",x2,s); #endif - __m64 c_re0,c_im0,c_re1,c_im1,c_re2,c_im2,c_re3,c_im3; - re_offset=0; - for (int prb=0;prbprb_size;prb+=2,re_offset+=16) { - c_re0 = byte2m64_re[((uint8_t*)&s)[0]]; - c_im0 = byte2m64_im[((uint8_t*)&s)[0]]; - c_re1 = byte2m64_re[((uint8_t*)&s)[1]]; - c_im1 = byte2m64_im[((uint8_t*)&s)[1]]; - c_re2 = byte2m64_re[((uint8_t*)&s)[2]]; - c_im2 = byte2m64_im[((uint8_t*)&s)[2]]; - c_re3 = byte2m64_re[((uint8_t*)&s)[3]]; - c_im3 = byte2m64_im[((uint8_t*)&s)[3]]; + for (int symb=0;symbnr_of_symbols;symb++) { + __m64 c_re0,c_im0,c_re1,c_im1,c_re2,c_im2,c_re3,c_im3; + int re_off=0; + for (int prb=0;prbbit_len_harq+pucch_pdu->sr_flag+pucch_pdu->bit_len_csi_part1+pucch_pdu->bit_len_csi_part2; AssertFatal(nb_bit > 2 && nb_bit< 65,"illegal length (%d : %d,%d,%d,%d)\n",nb_bit,pucch_pdu->bit_len_harq,pucch_pdu->sr_flag,pucch_pdu->bit_len_csi_part1,pucch_pdu->bit_len_csi_part2); @@ -1366,15 +1426,17 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, uint8_t corr_dB; int decoderState=2; if (nb_bit < 12) { // short blocklength case - __m256i *rp_re[Prx2]; - __m256i *rp2_re[Prx2]; - __m256i *rp_im[Prx2]; - __m256i *rp2_im[Prx2]; + __m256i *rp_re[Prx2][2]; + __m256i *rp2_re[Prx2][2]; + __m256i *rp_im[Prx2][2]; + __m256i *rp2_im[Prx2][2]; for (int aa=0;aanr_of_symbols;symb++) { + rp_re[aa][symb] = (__m256i*)r_re_ext[aa][symb]; + rp_im[aa][symb] = (__m256i*)r_im_ext[aa][symb]; + rp2_re[aa][symb] = (__m256i*)r_re_ext2[aa][symb]; + rp2_im[aa][symb] = (__m256i*)r_im_ext2[aa][symb]; + } } __m256i prod_re[Prx2],prod_im[Prx2]; uint64_t corr=0; @@ -1393,76 +1455,91 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, #endif uint64_t corr_tmp = 0; - for (int group=0;groupnr_of_symbols;symb++) { + for (int group=0;group (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",aa, - ((int16_t*)&prod_re[aa])[0],((int16_t*)&prod_re[aa])[1],((int16_t*)&prod_re[aa])[2],((int16_t*)&prod_re[aa])[3], - ((int16_t*)&prod_re[aa])[4],((int16_t*)&prod_re[aa])[5],((int16_t*)&prod_re[aa])[6],((int16_t*)&prod_re[aa])[7], - ((int16_t*)&prod_re[aa])[8],((int16_t*)&prod_re[aa])[9],((int16_t*)&prod_re[aa])[10],((int16_t*)&prod_re[aa])[11], - ((int16_t*)&prod_re[aa])[12],((int16_t*)&prod_re[aa])[13],((int16_t*)&prod_re[aa])[14],((int16_t*)&prod_re[aa])[15]); - printf("prod_im[%d] => (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",aa, - ((int16_t*)&prod_im[aa])[0],((int16_t*)&prod_im[aa])[1],((int16_t*)&prod_im[aa])[2],((int16_t*)&prod_im[aa])[3], - ((int16_t*)&prod_im[aa])[4],((int16_t*)&prod_im[aa])[5],((int16_t*)&prod_im[aa])[6],((int16_t*)&prod_im[aa])[7], - ((int16_t*)&prod_im[aa])[8],((int16_t*)&prod_im[aa])[9],((int16_t*)&prod_im[aa])[10],((int16_t*)&prod_im[aa])[11], - ((int16_t*)&prod_im[aa])[12],((int16_t*)&prod_im[aa])[13],((int16_t*)&prod_im[aa])[14],((int16_t*)&prod_im[aa])[15]); - + printf("prod_re[%d] => (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)\n",aa, + ((int16_t*)&prod_re[aa])[0],((int16_t*)&prod_re[aa])[1],((int16_t*)&prod_re[aa])[2],((int16_t*)&prod_re[aa])[3], + ((int16_t*)&prod_re[aa])[4],((int16_t*)&prod_re[aa])[5],((int16_t*)&prod_re[aa])[6],((int16_t*)&prod_re[aa])[7], + ((int16_t*)&prod_re[aa])[8],((int16_t*)&prod_re[aa])[9],((int16_t*)&prod_re[aa])[10],((int16_t*)&prod_re[aa])[11], + ((int16_t*)&prod_re[aa])[12],((int16_t*)&prod_re[aa])[13],((int16_t*)&prod_re[aa])[14],((int16_t*)&prod_re[aa])[15]); + printf("prod_im[%d] => (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)\n",aa, + ((int16_t*)&prod_im[aa])[0],((int16_t*)&prod_im[aa])[1],((int16_t*)&prod_im[aa])[2],((int16_t*)&prod_im[aa])[3], + ((int16_t*)&prod_im[aa])[4],((int16_t*)&prod_im[aa])[5],((int16_t*)&prod_im[aa])[6],((int16_t*)&prod_im[aa])[7], + ((int16_t*)&prod_im[aa])[8],((int16_t*)&prod_im[aa])[9],((int16_t*)&prod_im[aa])[10],((int16_t*)&prod_im[aa])[11], + ((int16_t*)&prod_im[aa])[12],((int16_t*)&prod_im[aa])[13],((int16_t*)&prod_im[aa])[14],((int16_t*)&prod_im[aa])[15]); + #endif - prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1 - prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]); - prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1+2+3 - prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]); - prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1+2+3+4+5+6+7 - prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]); - prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1+2+3+4+5+6+7+8+9+10+11+12+13+14+15 - prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]); - } - int64_t corr_re=0,corr_im=0; + prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1 + prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]); + prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1+2+3 + prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]); + prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1+2+3+4+5+6+7 + prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]); + prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1+2+3+4+5+6+7+8+9+10+11+12+13+14+15 + prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]); + } + int64_t corr_re=0,corr_im=0; - for (int aa=0;aa corr) { - corr = corr_tmp; - cw_ML=cw; + corr = corr_tmp; + cw_ML=cw; } } // cw loop corr_dB = dB_fixed64((uint64_t)corr); +#ifdef DEBUG_NR_PUCCH_RX + printf("cw_ML %d, metric %d dB\n",cw_ML,corr_dB); +#endif LOG_D(PHY,"cw_ML %d, metric %d dB\n",cw_ML,corr_dB); decodedPayload[0]=(uint64_t)cw_ML; } else { // polar coded case t_nrPolar_params *currentPtr = nr_polar_params(2,nb_bit,pucch_pdu->prb_size,1,&gNB->uci_polarParams); - __m64 *rp_re[Prx2]; - __m64 *rp2_re[Prx2]; - __m64 *rp_im[Prx2]; - __m64 *rp2_im[Prx2]; - __m128i llrs[pucch_pdu->prb_size*2]; + __m64 *rp_re[Prx2][2]; + __m64 *rp2_re[Prx2][2]; + __m64 *rp_im[Prx2][2]; + __m64 *rp2_im[Prx2][2]; + __m128i llrs[pucch_pdu->prb_size*2*pucch_pdu->nr_of_symbols]; for (int aa=0;aanr_of_symbols;symb++) { + rp_re[aa][symb] = (__m64*)r_re_ext[aa][symb]; + rp_im[aa][symb] = (__m64*)r_im_ext[aa][symb]; + rp2_re[aa][symb] = (__m64*)r_re_ext2[aa][symb]; + rp2_im[aa][symb] = (__m64*)r_im_ext2[aa][symb]; + } } __m64 prod_re[Prx2],prod_im[Prx2]; @@ -1482,35 +1559,35 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, int32_t corr_re,corr_im,corr_tmp; __m128i corr16,llr_num,llr_den; uint64_t corr = 0; + for (int symb=0;symbnr_of_symbols;symb++) { + for (int half_prb=0;half_prb<(2*pucch_pdu->prb_size);half_prb++) { + llr_num=_mm_set1_epi16(0);llr_den=_mm_set1_epi16(0); + for (int cw=0;cw<256;cw++) { + corr_tmp=0; + for (int aa=0;aa>4],rp_im[aa][symb][half_prb])),5); + prod_im[aa] = _mm_srai_pi16(_mm_subs_pi16(_mm_mullo_pi16(pucch2_polar_4bit[cw&15],rp2_im[aa][symb][half_prb]), + _mm_mullo_pi16(pucch2_polar_4bit[cw>>4],rp2_re[aa][symb][half_prb])),5); + prod_re[aa] = _mm_hadds_pi16(prod_re[aa],prod_re[aa]);// 0+1 + prod_im[aa] = _mm_hadds_pi16(prod_im[aa],prod_im[aa]); + prod_re[aa] = _mm_hadds_pi16(prod_re[aa],prod_re[aa]);// 0+1+2+3 + prod_im[aa] = _mm_hadds_pi16(prod_im[aa],prod_im[aa]); - for (int half_prb=0;half_prb<(2*pucch_pdu->prb_size);half_prb++) { - llr_num=_mm_set1_epi16(0);llr_den=_mm_set1_epi16(0); - for (int cw=0;cw<256;cw++) { - corr_tmp=0; - for (int aa=0;aa>4],rp_im[aa][half_prb])),5); - prod_im[aa] = _mm_srai_pi16(_mm_subs_pi16(_mm_mullo_pi16(pucch2_polar_4bit[cw&15],rp2_im[aa][half_prb]), - _mm_mullo_pi16(pucch2_polar_4bit[cw>>4],rp2_re[aa][half_prb])),5); - prod_re[aa] = _mm_hadds_pi16(prod_re[aa],prod_re[aa]);// 0+1 - prod_im[aa] = _mm_hadds_pi16(prod_im[aa],prod_im[aa]); - prod_re[aa] = _mm_hadds_pi16(prod_re[aa],prod_re[aa]);// 0+1+2+3 - prod_im[aa] = _mm_hadds_pi16(prod_im[aa],prod_im[aa]); - - // this is for UL CQI measurement - if (cw==0) corr += ((int64_t)corr32_re[half_prb>>2][aa]*corr32_re[half_prb>>2][aa])+ - ((int64_t)corr32_im[half_prb>>2][aa]*corr32_im[half_prb>>2][aa]); + // this is for UL CQI measurement + if (cw==0) corr += ((int64_t)corr32_re[symb][half_prb>>2][aa]*corr32_re[symb][half_prb>>2][aa])+ + ((int64_t)corr32_im[symb][half_prb>>2][aa]*corr32_im[symb][half_prb>>2][aa]); - corr_re = ( corr32_re[half_prb>>2][aa]/(2*nc_group_size*4/2)+((int16_t*)(&prod_re[aa]))[0]); - corr_im = ( corr32_im[half_prb>>2][aa]/(2*nc_group_size*4/2)+((int16_t*)(&prod_im[aa]))[0]); - corr_tmp += corr_re*corr_re + corr_im*corr_im; - - LOG_D(PHY,"pucch2 half_prb %d cw %d (%d,%d) aa %d: (%d,%d,%d,%d,%d,%d,%d,%d)x(%d,%d,%d,%d,%d,%d,%d,%d) (%d,%d)+(%d,%d) = (%d,%d) => %d\n", - half_prb,cw,cw&15,cw>>4,aa, - ((int16_t*)&pucch2_polar_4bit[cw&15])[0],((int16_t*)&pucch2_polar_4bit[cw>>4])[0], - ((int16_t*)&pucch2_polar_4bit[cw&15])[1],((int16_t*)&pucch2_polar_4bit[cw>>4])[1], - ((int16_t*)&pucch2_polar_4bit[cw&15])[2],((int16_t*)&pucch2_polar_4bit[cw>>4])[2], + corr_re = ( corr32_re[symb][half_prb>>2][aa]/(2*nc_group_size*4/2)+((int16_t*)(&prod_re[aa]))[0]); + corr_im = ( corr32_im[symb][half_prb>>2][aa]/(2*nc_group_size*4/2)+((int16_t*)(&prod_im[aa]))[0]); + corr_tmp += corr_re*corr_re + corr_im*corr_im; + /* + LOG_D(PHY,"pucch2 half_prb %d cw %d (%d,%d) aa %d: (%d,%d,%d,%d,%d,%d,%d,%d)x(%d,%d,%d,%d,%d,%d,%d,%d) (%d,%d)+(%d,%d) = (%d,%d) => %d\n", + half_prb,cw,cw&15,cw>>4,aa, + ((int16_t*)&pucch2_polar_4bit[cw&15])[0],((int16_t*)&pucch2_polar_4bit[cw>>4])[0], + ((int16_t*)&pucch2_polar_4bit[cw&15])[1],((int16_t*)&pucch2_polar_4bit[cw>>4])[1], + ((int16_t*)&pucch2_polar_4bit[cw&15])[2],((int16_t*)&pucch2_polar_4bit[cw>>4])[2], ((int16_t*)&pucch2_polar_4bit[cw&15])[3],((int16_t*)&pucch2_polar_4bit[cw>>4])[3], ((int16_t*)&rp_re[aa][half_prb])[0],((int16_t*)&rp_im[aa][half_prb])[0], ((int16_t*)&rp_re[aa][half_prb])[1],((int16_t*)&rp_im[aa][half_prb])[1], @@ -1522,7 +1599,7 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, corr_re, corr_im, corr_tmp); - +*/ } corr16 = _mm_set1_epi16((int16_t)(corr_tmp>>8)); @@ -1562,18 +1639,19 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, } // compute llrs - llrs[half_prb] = _mm_subs_epi16(llr_num,llr_den); - LOG_D(PHY,"llrs[%d] : (%d,%d,%d,%d,%d,%d,%d,%d)\n", - half_prb, - ((int16_t*)&llrs[half_prb])[0], - ((int16_t*)&llrs[half_prb])[1], - ((int16_t*)&llrs[half_prb])[2], - ((int16_t*)&llrs[half_prb])[3], - ((int16_t*)&llrs[half_prb])[4], - ((int16_t*)&llrs[half_prb])[5], - ((int16_t*)&llrs[half_prb])[6], - ((int16_t*)&llrs[half_prb])[7]); - } // half_prb + llrs[half_prb + (symb*2*pucch_pdu->prb_size)] = _mm_subs_epi16(llr_num,llr_den); + LOG_D(PHY,"llrs[%d] : (%d,%d,%d,%d,%d,%d,%d,%d)\n", + half_prb, + ((int16_t*)&llrs[half_prb])[0], + ((int16_t*)&llrs[half_prb])[1], + ((int16_t*)&llrs[half_prb])[2], + ((int16_t*)&llrs[half_prb])[3], + ((int16_t*)&llrs[half_prb])[4], + ((int16_t*)&llrs[half_prb])[5], + ((int16_t*)&llrs[half_prb])[6], + ((int16_t*)&llrs[half_prb])[7]); + } // half_prb + } // symb // run polar decoder on llrs decoderState = polar_decoder_int16((int16_t*)llrs, decodedPayload, 0, currentPtr); LOG_D(PHY,"UCI decoderState %d, payload[0] %llu\n",decoderState,(unsigned long long)decodedPayload[0]); @@ -1582,9 +1660,10 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, LOG_D(PHY,"metric %d dB\n",corr_dB); } - re_offset = (12*pucch_pdu->prb_start) + (12*pucch_pdu->bwp_start) + frame_parms->first_carrier_offset; - // estimate CQI for MAC (from antenna port 0 only) - int SNRtimes10 = dB_fixed_times10(signal_energy_nodc(&rxdataF[0][(l2*frame_parms->ofdm_symbol_size)+re_offset],12*pucch_pdu->prb_size)) - (10*gNB->measurements.n0_power_tot_dB); + // estimate CQI for MAC (from antenna port 0 only) + int SNRtimes10 = dB_fixed_times10(signal_energy_nodc(&rxdataF[0][soffset+(l2*frame_parms->ofdm_symbol_size)+re_offset[0]], + 12*pucch_pdu->prb_size)) - + (10*gNB->measurements.n0_power_tot_dB); int cqi,bit_left; if (SNRtimes10 < -640) cqi=0; else if (SNRtimes10 > 635) cqi=255; @@ -1597,7 +1676,7 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, uci_pdu->pucch_format=0; uci_pdu->ul_cqi=cqi; uci_pdu->timing_advance=0xffff; // currently not valid - uci_pdu->rssi=1280 - (10*dB_fixed(32767*32767)-dB_fixed_times10(signal_energy_nodc(&rxdataF[0][(l2*frame_parms->ofdm_symbol_size)+re_offset],12*pucch_pdu->prb_size))); + uci_pdu->rssi=1280 - (10*dB_fixed(32767*32767)-dB_fixed_times10(signal_energy_nodc(&rxdataF[0][soffset+(l2*frame_parms->ofdm_symbol_size)+re_offset[0]],12*pucch_pdu->prb_size))); if (pucch_pdu->bit_len_harq>0) { int harq_bytes=pucch_pdu->bit_len_harq>>3; if ((pucch_pdu->bit_len_harq&7) > 0) harq_bytes++; diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c index 44f1844ae9..7f6f0e8ef9 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c @@ -36,7 +36,6 @@ #include "PHY/phy_extern_nr_ue.h" #include "common/utils/LOG/log.h" #include "PHY/sse_intrin.h" -#include "openair2/LAYER2/NR_MAC_UE/mac_proto.h" //#define k1 1000 #define k1 ((long long int) 1000) diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c index aa8588f106..3afe27310f 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c @@ -36,16 +36,14 @@ #include #endif -#include -#include -#include "executables/softmodem-common.h" +#include "executables/softmodem-common.h" #include "nr_transport_proto_ue.h" #include "PHY/CODING/nrPolar_tools/nr_polar_dci_defs.h" #include "PHY/phy_extern_nr_ue.h" #include "PHY/CODING/coding_extern.h" #include "PHY/sse_intrin.h" -#include "PHY/NR_TRANSPORT/nr_dci.h" +#include "common/utils/nr/nr_common.h" #include "assertions.h" #include "T.h" @@ -148,7 +146,7 @@ void nr_pdcch_demapping_deinterleaving(uint32_t *llr, } - int f_bundle_j_list[NR_MAX_PDCCH_AGG_LEVEL] = {}; + int f_bundle_j_list[(2*NR_MAX_PDCCH_AGG_LEVEL) - 1] = {}; for (int reg = 0; reg < coreset_nbr_rb; reg++) { if ((reg % reg_bundle_size_L) == 0) { @@ -170,12 +168,14 @@ void nr_pdcch_demapping_deinterleaving(uint32_t *llr, // Get cce_list indices by reg_idx in ascending order int f_bundle_j_list_id = 0; - int f_bundle_j_list_ord[NR_MAX_PDCCH_AGG_LEVEL] = {}; + int f_bundle_j_list_ord[(2*NR_MAX_PDCCH_AGG_LEVEL)-1] = {}; for (int c_id = 0; c_id < number_of_candidates; c_id++ ) { f_bundle_j_list_id = CCE[c_id]; for (int p = 0; p < NR_MAX_PDCCH_AGG_LEVEL; p++) { for (int p2 = CCE[c_id]; p2 < CCE[c_id] + L[c_id]; p2++) { + AssertFatal(p2<2*NR_MAX_PDCCH_AGG_LEVEL,"number_of_candidates %d : p2 %d, CCE[%d] %d, L[%d] %d\n",number_of_candidates,p2,c_id,CCE[c_id],c_id,L[c_id]); if (f_bundle_j_list[p2] == p) { + AssertFatal(f_bundle_j_list_id < 2*NR_MAX_PDCCH_AGG_LEVEL,"f_bundle_j_list_id %d\n",f_bundle_j_list_id); f_bundle_j_list_ord[f_bundle_j_list_id] = p; f_bundle_j_list_id++; break; @@ -413,7 +413,6 @@ void nr_pdcch_extract_rbs_single(int32_t **rxdataF, * we have to point the pointer at (1+c_rb-N_RB_DL/2) in rxdataF */ - LOG_DDD("n_BWP_start=%d, coreset_nbr_rb=%d\n",n_BWP_start,coreset_nbr_rb); int c_rb_by6; c_rb = 0; for (int rb=0;rb>2; rb++) { - //printf("rb %d\n",rb); #if defined(__x86_64__) || defined(__i386__) // multiply by conjugated channel mmtmpP0 = _mm_madd_epi16(dl_ch128[0],rxdataF128[0]); - // print_ints("re",&mmtmpP0); + //print_ints("re",&mmtmpP0); // mmtmpP0 contains real part of 4 consecutive outputs (32-bit) mmtmpP1 = _mm_shufflelo_epi16(dl_ch128[0],_MM_SHUFFLE(2,3,0,1)); mmtmpP1 = _mm_shufflehi_epi16(mmtmpP1,_MM_SHUFFLE(2,3,0,1)); mmtmpP1 = _mm_sign_epi16(mmtmpP1,*(__m128i *)&conjugate[0]); - // print_ints("im",&mmtmpP1); + //print_ints("im",&mmtmpP1); mmtmpP1 = _mm_madd_epi16(mmtmpP1,rxdataF128[0]); // mmtmpP1 contains imag part of 4 consecutive outputs (32-bit) mmtmpP0 = _mm_srai_epi32(mmtmpP0,output_shift); @@ -599,12 +597,12 @@ void nr_pdcch_channel_compensation(int32_t **rxdataF_ext, // print_ints("im(shift)",&mmtmpP1); mmtmpP2 = _mm_unpacklo_epi32(mmtmpP0,mmtmpP1); mmtmpP3 = _mm_unpackhi_epi32(mmtmpP0,mmtmpP1); - // print_ints("c0",&mmtmpP2); - // print_ints("c1",&mmtmpP3); + //print_ints("c0",&mmtmpP2); + //print_ints("c1",&mmtmpP3); rxdataF_comp128[0] = _mm_packs_epi32(mmtmpP2,mmtmpP3); - //print_shorts("rx:",rxdataF128); - //print_shorts("ch:",dl_ch128); - //print_shorts("pack:",rxdataF_comp128); +// print_shorts("rx:",(int16_t*)rxdataF128); +// print_shorts("ch:",(int16_t*)dl_ch128); +// print_shorts("pack:",(int16_t*)rxdataF_comp128); // multiply by conjugated channel mmtmpP0 = _mm_madd_epi16(dl_ch128[1],rxdataF128[1]); // mmtmpP0 contains real part of 4 consecutive outputs (32-bit) @@ -800,7 +798,7 @@ int32_t nr_rx_pdcch(PHY_VARS_NR_UE *ue, #endif } - LOG_D(PHY,"we enter nr_pdcch_demapping_deinterleaving()\n"); + LOG_D(PHY,"we enter nr_pdcch_demapping_deinterleaving(), number of candidates %d\n",rel15->number_of_candidates); nr_pdcch_demapping_deinterleaving((uint32_t *) pdcch_vars->llr, (uint32_t *) pdcch_vars->e_rx, rel15->coreset.duration, @@ -933,11 +931,22 @@ uint8_t nr_dci_decoding_procedure(PHY_VARS_NR_UE *ue, // Loop over possible DCI lengths for (int k = 0; k < rel15->num_dci_options; k++) { + // skip this candidate if we've already found one with the + // same rnti and format at a different aggregation level + int dci_found=0; + for (int ind=0;ind < dci_ind->number_of_dcis ; ind++) { + if (rel15->rnti== dci_ind->dci_list[ind].rnti && + rel15->dci_format_options[k]==dci_ind->dci_list[ind].dci_format) { + dci_found=1; + break; + } + } + if (dci_found==1) continue; int dci_length = rel15->dci_length_options[k]; uint64_t dci_estimation[2]= {0}; const t_nrPolar_params *currentPtrDCI = nr_polar_params(NR_POLAR_DCI_MESSAGE_TYPE, dci_length, L, 1, &ue->polarList); - LOG_D(PHY, "Trying DCI candidate %d of %d number of candidates, CCE %d (%d), L %d\n", j, rel15->number_of_candidates, CCEind, CCEind*9*6*2, L); + LOG_D(PHY, "Trying DCI candidate %d of %d number of candidates, CCE %d (%d), L %d, length %d, format %s\n", j, rel15->number_of_candidates, CCEind, CCEind*9*6*2, L, dci_length,nr_dci_format_string[rel15->dci_format_options[k]]); nr_pdcch_unscrambling(&pdcch_vars->e_rx[CCEind*108], rel15->coreset.scrambling_rnti, L*108, rel15->coreset.pdcch_dmrs_scrambling_id, tmp_e); diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_tools_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_tools_nr.c index fa09093306..8a4cafc6d7 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/dci_tools_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/dci_tools_nr.c @@ -45,11 +45,6 @@ //#define DEBUG_HARQ -//#include "LAYER2/MAC/extern.h" -//#include "LAYER2/MAC/defs.h" -//#include "../openair2/LAYER2/MAC/extern.h" -//#include "../openair2/LAYER2/MAC/defs.h" - //#define DEBUG_DCI #define NR_PDCCH_DCI_TOOLS //#define NR_PDCCH_DCI_TOOLS_DEBUG diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c index 95b04435eb..975d7077a0 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c @@ -43,7 +43,7 @@ #include "SIMULATION/TOOLS/sim.h" #include "executables/nr-uesoftmodem.h" #include "PHY/CODING/nrLDPC_extern.h" -#include "LAYER2/NR_MAC_gNB/mac_proto.h" +#include "common/utils/nr/nr_common.h" //#define ENABLE_PHY_PAYLOAD_DEBUG 1 @@ -236,11 +236,10 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, uint8_t harq_pid, uint8_t is_crnti, uint8_t llr8_flag) { -#if UE_TIMING_TRACE time_stats_t *dlsch_rate_unmatching_stats=&phy_vars_ue->dlsch_rate_unmatching_stats; time_stats_t *dlsch_turbo_decoding_stats=&phy_vars_ue->dlsch_turbo_decoding_stats; time_stats_t *dlsch_deinterleaving_stats=&phy_vars_ue->dlsch_deinterleaving_stats; -#endif + uint32_t A,E; uint32_t G; uint32_t ret,offset; @@ -328,8 +327,8 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, harq_process->G = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, dmrs_length, harq_process->Qm,harq_process->Nl); G = harq_process->G; - LOG_D(PHY,"DLSCH Decoding, harq_pid %d TBS %d (%d) G %d nb_re_dmrs %d length dmrs %d mcs %d Nl %d nb_symb_sch %d nb_rb %d\n", - harq_pid,A,A/8,G, nb_re_dmrs, dmrs_length, harq_process->mcs, harq_process->Nl, nb_symb_sch,nb_rb); + LOG_D(PHY,"%d.%d DLSCH Decoding, harq_pid %d TBS %d (%d) G %d nb_re_dmrs %d length dmrs %d mcs %d Nl %d nb_symb_sch %d nb_rb %d\n", + frame,nr_slot_rx,harq_pid,A,A/8,G, nb_re_dmrs, dmrs_length, harq_process->mcs, harq_process->Nl, nb_symb_sch,nb_rb); if ((harq_process->R)<1024) Coderate = (float) (harq_process->R) /(float) 1024; @@ -411,21 +410,15 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, for (r=0; rC; r++) { //printf("start rx segment %d\n",r); E = nr_get_E(G, harq_process->C, harq_process->Qm, harq_process->Nl, r); -#if UE_TIMING_TRACE start_meas(dlsch_deinterleaving_stats); -#endif VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DEINTERLEAVING, VCD_FUNCTION_IN); nr_deinterleaving_ldpc(E, harq_process->Qm, harq_process->w[r], // [hna] w is e dlsch_llr+r_offset); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DEINTERLEAVING, VCD_FUNCTION_OUT); -#if UE_TIMING_TRACE stop_meas(dlsch_deinterleaving_stats); -#endif -#if UE_TIMING_TRACE start_meas(dlsch_rate_unmatching_stats); -#endif LOG_D(PHY,"HARQ_PID %d Rate Matching Segment %d (coded bits %d,E %d, F %d,unpunctured/repeated bits %d, TBS %d, mod_order %d, nb_rb %d, Nl %d, rv %d, round %d)...\n", harq_pid,r, G,E,harq_process->F, Kr*3, @@ -454,16 +447,12 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, E, harq_process->F, Kr-harq_process->F-2*(p_decParams->Z))==-1) { - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_RATE_MATCHING, VCD_FUNCTION_OUT); -#if UE_TIMING_TRACE - stop_meas(dlsch_rate_unmatching_stats); -#endif - LOG_E(PHY,"dlsch_decoding.c: Problem in rate_matching\n"); - return(dlsch->max_ldpc_iterations + 1); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_RATE_MATCHING, VCD_FUNCTION_OUT); + stop_meas(dlsch_rate_unmatching_stats); + LOG_E(PHY,"dlsch_decoding.c: Problem in rate_matching\n"); + return(dlsch->max_ldpc_iterations + 1); } else { -#if UE_TIMING_TRACE - stop_meas(dlsch_rate_unmatching_stats); -#endif + stop_meas(dlsch_rate_unmatching_stats); } r_offset += E; @@ -492,9 +481,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, } if (err_flag == 0) { -#if UE_TIMING_TRACE start_meas(dlsch_turbo_decoding_stats); -#endif //set first 2*Z_c bits to zeros memset(&z[0],0,2*harq_process->Z*sizeof(int16_t)); //set Filler bits @@ -510,6 +497,8 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_LDPC, VCD_FUNCTION_IN); + p_decParams->block_length=length_dec; + nrLDPC_initcall(p_decParams, (int8_t*)&pl[0], llrProcBuf); no_iteration_ldpc = nrLDPC_decoder(p_decParams, (int8_t *)&pl[0], llrProcBuf, @@ -545,13 +534,10 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD)) { for (int k=0; k>3; k++) LOG_D(PHY,"output decoder [%d] = 0x%02x \n", k, harq_process->c[r][k]); - LOG_D(PHY,"no_iterations_ldpc %d (ret %u)\n",no_iteration_ldpc,ret); } -#if UE_TIMING_TRACE stop_meas(dlsch_turbo_decoding_stats); -#endif } if ((err_flag == 0) && (ret>=(1+dlsch->max_ldpc_iterations))) {// a Code segment is in error so break; @@ -645,11 +631,10 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, uint8_t harq_pid, uint8_t is_crnti, uint8_t llr8_flag) { -#if UE_TIMING_TRACE + time_stats_t *dlsch_rate_unmatching_stats=&phy_vars_ue->dlsch_rate_unmatching_stats; time_stats_t *dlsch_turbo_decoding_stats=&phy_vars_ue->dlsch_turbo_decoding_stats; time_stats_t *dlsch_deinterleaving_stats=&phy_vars_ue->dlsch_deinterleaving_stats; -#endif uint32_t A,E; uint32_t G; uint32_t ret,offset; @@ -812,7 +797,6 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, notifiedFIFO_elt_t *res_dl; opp_enabled=1; - if (harq_process->C>1) { for (int nb_seg =1 ; nb_segC; nb_seg++) { if ( (res_dl=tryPullTpool(&nf, &pool_dl)) != NULL ) { @@ -867,9 +851,7 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, dlsch_llr+r_offset, &harq_process->w[r]); */ -#if UE_TIMING_TRACE start_meas(dlsch_deinterleaving_stats); -#endif nr_deinterleaving_ldpc(E, harq_process->Qm, harq_process->w[r], @@ -879,12 +861,8 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, for (int i =0; i<16; i++) LOG_D(PHY,"rx output deinterleaving w[%d]= %d r_offset %u\n", i,harq_process->w[r][i], r_offset); -#if UE_TIMING_TRACE stop_meas(dlsch_deinterleaving_stats); -#endif -#if UE_TIMING_TRACE start_meas(dlsch_rate_unmatching_stats); -#endif if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD)) LOG_I(PHY,"HARQ_PID %d Rate Matching Segment %d (coded bits %d,unpunctured/repeated bits %d, TBS %d, mod_order %d, nb_rb %d, Nl %d, rv %d, round %d)...\n", @@ -915,15 +893,11 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, E, harq_process->F, Kr-harq_process->F-2*(p_decParams->Z))==-1) { -#if UE_TIMING_TRACE stop_meas(dlsch_rate_unmatching_stats); -#endif LOG_E(PHY,"dlsch_decoding.c: Problem in rate_matching\n"); return(dlsch->max_ldpc_iterations); } else { -#if UE_TIMING_TRACE stop_meas(dlsch_rate_unmatching_stats); -#endif } if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD)) @@ -966,9 +940,7 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, Kr,r,harq_process->C,harq_process->nb_rb,crc_type,A,harq_process->TBS, harq_process->B,harq_process->mcs,harq_process->Qm,harq_process->rvidx,harq_process->round,dlsch->max_ldpc_iterations); */ -#if UE_TIMING_TRACE start_meas(dlsch_turbo_decoding_stats); -#endif LOG_D(PHY,"mthread AbsSubframe %d.%d Start LDPC segment %d/%d \n",frame%1024,nr_slot_rx,r,harq_process->C-1); /*for (int cnt =0; cnt < (kc-2)*p_decParams->Z; cnt++){ inv_d[cnt] = (1)*harq_process->d[r][cnt]; @@ -986,7 +958,8 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, for (i=0, j=0; j < ((kc*harq_process->Z)>>4)+1; i+=2, j++) { pl[j] = _mm_packs_epi16(pv[i],pv[i+1]); } - + p_decParams->block_length=length_dec; + nrLDPC_initcall(p_decParams, (int8_t*)&pl[0], llrProcBuf); no_iteration_ldpc = nrLDPC_decoder(p_decParams, (int8_t *)&pl[0], llrProcBuf, @@ -1037,11 +1010,10 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, for (int k=0; k<32; k++) LOG_D(PHY,"output decoder [%d] = 0x%02x \n", k, harq_process->c[r][k]); -#if UE_TIMING_TRACE stop_meas(dlsch_turbo_decoding_stats); -#endif } + if ((err_flag == 0) && (ret>=(1+dlsch->max_ldpc_iterations))) {// a Code segment is in error so break; LOG_D(PHY,"AbsSubframe %d.%d CRC failed, segment %d/%d \n",frame%1024,nr_slot_rx,r,harq_process->C-1); err_flag = 1; @@ -1135,7 +1107,6 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, } - void nr_dlsch_decoding_process(void *arg) { nr_rxtx_thread_data_t *rxtxD= (nr_rxtx_thread_data_t *)arg; UE_nr_rxtx_proc_t *proc = &rxtxD->proc; @@ -1167,11 +1138,10 @@ void nr_dlsch_decoding_process(void *arg) { proc->instance_cnt_dlsch_td=-1; //proc->nr_slot_rx = proc->sub_frame_start * frame_parms->slots_per_subframe; proc->decoder_thread_available = 1; -#if UE_TIMING_TRACE time_stats_t *dlsch_rate_unmatching_stats=&phy_vars_ue->dlsch_rate_unmatching_stats; time_stats_t *dlsch_turbo_decoding_stats=&phy_vars_ue->dlsch_turbo_decoding_stats; time_stats_t *dlsch_deinterleaving_stats=&phy_vars_ue->dlsch_deinterleaving_stats; -#endif + uint32_t A,E; uint32_t G; uint32_t ret; @@ -1200,7 +1170,8 @@ void nr_dlsch_decoding_process(void *arg) { ret = dlsch->max_ldpc_iterations; harq_process->G = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, harq_process->Qm,harq_process->Nl); G = harq_process->G; - LOG_D(PHY,"DLSCH Decoding process, harq_pid %d TBS %d G %d mcs %d Nl %d nb_symb_sch %d nb_rb %d\n",harq_pid,A,G, harq_process->mcs, harq_process->Nl, nb_symb_sch,nb_rb); + + LOG_D(PHY,"DLSCH Decoding process, harq_pid %d TBS %d G %d mcs %d Nl %d nb_symb_sch %d nb_rb %d, Coderate %d\n",harq_pid,A,G, harq_process->mcs, harq_process->Nl, nb_symb_sch,nb_rb,harq_process->R); if ((harq_process->R)<1024) Coderate = (float) (harq_process->R) /(float) 1024; @@ -1271,9 +1242,7 @@ void nr_dlsch_decoding_process(void *arg) { Kr_bytes = Kr>>3; K_bits_F = Kr-harq_process->F; E = nr_get_E(G, harq_process->C, harq_process->Qm, harq_process->Nl, r); -#if UE_TIMING_TRACE start_meas(dlsch_deinterleaving_stats); -#endif nr_deinterleaving_ldpc(E, harq_process->Qm, harq_process->w[r], @@ -1283,13 +1252,8 @@ void nr_dlsch_decoding_process(void *arg) { for (int i =0; i<16; i++) LOG_D(PHY,"rx output thread 0 deinterleaving w[%d]= %d r_offset %u\n", i,harq_process->w[r][i], r_offset); -#if UE_TIMING_TRACE stop_meas(dlsch_deinterleaving_stats); -#endif -#if UE_TIMING_TRACE start_meas(dlsch_rate_unmatching_stats); -#endif - if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD)) LOG_I(PHY,"HARQ_PID %d Rate Matching Segment %d (coded bits %d,unpunctured/repeated bits %d, TBS %d, mod_order %d, nb_rb %d, Nl %d, rv %d, round %d)...\n", harq_pid,r, G, @@ -1318,15 +1282,11 @@ void nr_dlsch_decoding_process(void *arg) { E, harq_process->F, Kr-harq_process->F-2*(p_decParams->Z))==-1) { -#if UE_TIMING_TRACE stop_meas(dlsch_rate_unmatching_stats); -#endif LOG_E(PHY,"dlsch_decoding.c: Problem in rate_matching\n"); //return(dlsch->max_ldpc_iterations); } else { -#if UE_TIMING_TRACE stop_meas(dlsch_rate_unmatching_stats); -#endif } if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD)) { @@ -1363,9 +1323,7 @@ void nr_dlsch_decoding_process(void *arg) { Kr,r,harq_process->C,harq_process->nb_rb,A,harq_process->TBS,harq_process->B,harq_process->mcs,harq_process->Qm,harq_process->rvidx,harq_process->round); } -#if UE_TIMING_TRACE start_meas(dlsch_turbo_decoding_stats); -#endif // LOG_D(PHY,"AbsSubframe %d.%d Start LDPC segment %d/%d \n",frame%1024,subframe,r,harq_process->C-1); /* for (int cnt =0; cnt < (kc-2)*p_decParams->Z; cnt++){ @@ -1385,7 +1343,8 @@ void nr_dlsch_decoding_process(void *arg) { for (i=0, j=0; j < ((kc*harq_process->Z)>>4)+1; i+=2, j++) { pl[j] = _mm_packs_epi16(pv[i],pv[i+1]); } - + p_decParams->block_length=length_dec; + nrLDPC_initcall(p_decParams, (int8_t*)&pl[0], llrProcBuf); no_iteration_ldpc = nrLDPC_decoder(p_decParams, (int8_t *)&pl[0], llrProcBuf, @@ -1411,10 +1370,7 @@ void nr_dlsch_decoding_process(void *arg) { if ( LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD)) for (int k=0; k<2; k++) LOG_D(PHY,"segment 1 output decoder [%d] = 0x%02x \n", k, harq_process->c[r][k]); - -#if UE_TIMING_TRACE stop_meas(dlsch_turbo_decoding_stats); -#endif } if ((err_flag == 0) && (ret>=(1+dlsch->max_ldpc_iterations))) {// a Code segment is in error so break; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index fb6e7bf6b5..031c08a72d 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -41,6 +41,7 @@ #include "openair1/PHY/NR_TRANSPORT/nr_dlsch.h" #include "PHY/NR_REFSIG/nr_refsig.h" #include "PHY/NR_REFSIG/dmrs_nr.h" +#include "common/utils/nr/nr_common.h" #ifndef USER_MODE #define NOCYGWIN_STATIC static @@ -163,9 +164,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, // int avg_0[2]; // int avg_1[2]; -#if UE_TIMING_TRACE uint8_t slot = 0; -#endif unsigned char aatx=0,aarx=0; @@ -331,12 +330,10 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, DevAssert(dlsch1_harq); } -#if UE_TIMING_TRACE if(symbol > ue->frame_parms.symbols_per_slot>>1) { slot = 1; } -#endif #ifdef DEBUG_HARQ printf("Demod dlsch0_harq->pmi_alloc %d\n", dlsch0_harq->pmi_alloc); @@ -346,9 +343,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, uint8_t config_type = dlsch0_harq->dmrsConfigType; if (beamforming_mode==0) {//No beamforming -#if UE_TIMING_TRACE start_meas(&ue->generic_stat_bis[proc->thread_id][slot]); -#endif if (dlsch0_harq->Nl > 1)//More than or equal 2 layers nb_rb = nr_dlsch_extract_rbs_multiple(common_vars->common_vars_rx_data_per_thread[proc->thread_id].rxdataF, pdsch_vars[gNB_id]->dl_ch_estimates, @@ -389,7 +384,6 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, len = (pilots==1)? ((config_type==NFAPI_NR_DMRS_TYPE1)?nb_rb*(12-6*dlsch0_harq->n_dmrs_cdm_groups): nb_rb*(12-4*dlsch0_harq->n_dmrs_cdm_groups)):(nb_rb*12); -#if UE_TIMING_TRACE stop_meas(&ue->generic_stat_bis[proc->thread_id][slot]); #if DISABLE_LOG_X printf("[AbsSFN %u.%d] Slot%d Symbol %d type %d: Pilot/Data extraction %5.2f \n", @@ -398,11 +392,8 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, LOG_I(PHY, "[AbsSFN %u.%d] Slot%d Symbol %d type %d: Pilot/Data extraction %5.2f \n", frame,nr_slot_rx,slot,symbol,type,ue->generic_stat_bis[proc->thread_id][slot].p_time/(cpuf*1000.0)); #endif -#endif -#if UE_TIMING_TRACE start_meas(&ue->generic_stat_bis[proc->thread_id][slot]); -#endif n_tx = dlsch0_harq->Nl; n_rx = frame_parms->nb_antennas_rx; @@ -416,18 +407,13 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, len, nb_rb_pdsch); -#if UE_TIMING_TRACE stop_meas(&ue->generic_stat_bis[proc->thread_id][slot]); #if DISABLE_LOG_X printf("[AbsSFN %u.%d] Slot%d Symbol %d: Channel Scale %5.2f \n",frame,nr_slot_rx,slot,symbol,ue->generic_stat_bis[proc->thread_id][slot].p_time/(cpuf*1000.0)); #else LOG_I(PHY, "[AbsSFN %u.%d] Slot%d Symbol %d: Channel Scale %5.2f \n",frame,nr_slot_rx,slot,symbol,ue->generic_stat_bis[proc->thread_id][slot].p_time/(cpuf*1000.0)); #endif -#endif - -#if UE_TIMING_TRACE start_meas(&ue->generic_stat_bis[proc->thread_id][slot]); -#endif if (first_symbol_flag==1) { if (beamforming_mode==0){ nr_dlsch_channel_level(pdsch_vars[gNB_id]->dl_ch_estimates_ext, @@ -482,19 +468,14 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, } #endif -#if UE_TIMING_TRACE stop_meas(&ue->generic_stat_bis[proc->thread_id][slot]); #if DISABLE_LOG_X printf("[AbsSFN %u.%d] Slot%d Symbol %d first_symbol_flag %d: Channel Level %5.2f \n",frame,nr_slot_rx,slot,symbol,first_symbol_flag,ue->generic_stat_bis[proc->thread_id][slot].p_time/(cpuf*1000.0)); #else LOG_I(PHY, "[AbsSFN %u.%d] Slot%d Symbol %d first_symbol_flag %d: Channel Level %5.2f \n",frame,nr_slot_rx,slot,symbol,first_symbol_flag,ue->generic_stat_bis[proc->thread_id][slot].p_time/(cpuf*1000.0)); #endif -#endif - -#if UE_TIMING_TRACE start_meas(&ue->generic_stat_bis[proc->thread_id][slot]); -#endif // Now channel compensation if (dlsch0_harq->mimo_moderxdataF_ext, @@ -539,18 +520,13 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, 0); } -#if UE_TIMING_TRACE stop_meas(&ue->generic_stat_bis[proc->thread_id][slot]); #if DISABLE_LOG_X printf("[AbsSFN %u.%d] Slot%d Symbol %d log2_maxh %d channel_level %d: Channel Comp %5.2f \n", frame, nr_slot_rx, slot, symbol, pdsch_vars[gNB_id]->log2_maxh, proc->channel_level, ue->generic_stat_bis[proc->thread_id][slot].p_time/(cpuf*1000.0)); #else LOG_I(PHY, "[AbsSFN %u.%d] Slot%d Symbol %d log2_maxh %d channel_level %d: Channel Comp %5.2f \n", frame, nr_slot_rx, slot, symbol, pdsch_vars[gNB_id]->log2_maxh, proc->channel_level, ue->generic_stat_bis[proc->thread_id][slot].p_time/(cpuf*1000.0)); #endif -#endif -// MRC -#if UE_TIMING_TRACE start_meas(&ue->generic_stat_bis[proc->thread_id][slot]); -#endif if (frame_parms->nb_antennas_rx > 1) { if (dlsch0_harq->mimo_modegeneric_stat_bis[proc->thread_id][slot]); #if DISABLE_LOG_X printf("[AbsSFN %u.%d] Slot%d Symbol %d: Channel Combine %5.2f \n",frame,nr_slot_rx,slot,symbol,ue->generic_stat_bis[proc->thread_id][slot].p_time/(cpuf*1000.0)); #else LOG_I(PHY, "[AbsSFN %u.%d] Slot%d Symbol %d: Channel Combine %5.2f \n",frame,nr_slot_rx,slot,symbol,ue->generic_stat_bis[proc->thread_id][slot].p_time/(cpuf*1000.0)); #endif -#endif - -#if UE_TIMING_TRACE - start_meas(&ue->generic_stat_bis[proc->thread_id][slot]); -#endif /* Store the valid DL RE's */ pdsch_vars[gNB_id]->dl_valid_re[symbol-1] = len; @@ -692,14 +662,12 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, } -#if UE_TIMING_TRACE stop_meas(&ue->generic_stat_bis[proc->thread_id][slot]); #if DISABLE_LOG_X printf("[AbsSFN %u.%d] Slot%d Symbol %d: LLR Computation %5.2f \n",frame,nr_slot_rx,slot,symbol,ue->generic_stat_bis[proc->thread_id][slot].p_time/(cpuf*1000.0)); #else LOG_I(PHY, "[AbsSFN %u.%d] Slot%d Symbol %d: LLR Computation %5.2f \n",frame,nr_slot_rx,slot,symbol,ue->generic_stat_bis[proc->thread_id][slot].p_time/(cpuf*1000.0)); #endif -#endif // Please keep it: useful for debugging #ifdef DEBUG_PDSCH_RX diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c index 7dfd765b76..ffe21b1f6d 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c @@ -38,6 +38,7 @@ #include "PHY/NR_UE_ESTIMATION/nr_estimation.h" #include "SCHED_NR_UE/defs.h" #include "common/utils/LOG/vcd_signal_dumper.h" +#include "common/utils/nr/nr_common.h" #include "common_lib.h" #include @@ -126,15 +127,11 @@ int nr_pbch_detection(UE_nr_rxtx_proc_t * proc, PHY_VARS_NR_UE *ue, int pbch_ini // initialization of structure current_ssb = create_ssb_node(l,hf); -#if UE_TIMING_TRACE start_meas(&ue->dlsch_channel_estimation_stats); -#endif // computing correlation between received DMRS symbols and transmitted sequence for current i_ssb and n_hf for(int i=pbch_initial_symbol; idlsch_channel_estimation_stats); -#endif current_ssb->metric = current_ssb->c_re*current_ssb->c_re + current_ssb->c_im*current_ssb->c_im; @@ -150,15 +147,11 @@ int nr_pbch_detection(UE_nr_rxtx_proc_t * proc, PHY_VARS_NR_UE *ue, int pbch_ini NR_UE_SSB *temp_ptr=best_ssb; while (ret!=0 && temp_ptr != NULL) { -#if UE_TIMING_TRACE start_meas(&ue->dlsch_channel_estimation_stats); -#endif // computing channel estimation for selected best ssb for(int i=pbch_initial_symbol; ii_ssb,temp_ptr->n_hf); -#if UE_TIMING_TRACE stop_meas(&ue->dlsch_channel_estimation_stats); -#endif ret = nr_rx_pbch(ue, proc, diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c index d94ae2a61e..5487d30968 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c @@ -39,7 +39,6 @@ #include "PHY/CODING/nrLDPC_extern.h" #include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h" #include "common/utils/LOG/vcd_signal_dumper.h" -#include "LAYER2/NR_MAC_gNB/mac_proto.h" #include //#define DEBUG_ULSCH_CODING diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index bcce28b390..98ebecb9c8 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -44,8 +44,6 @@ #include "PHY/TOOLS/tools_defs.h" #include "executables/nr-softmodem.h" #include "executables/softmodem-common.h" -#include "LAYER2/NR_MAC_UE/mac_proto.h" - #include "PHY/NR_REFSIG/ul_ref_seq_nr.h" #include @@ -144,7 +142,12 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, ulsch_ue->Nid_cell = Nid_cell; - get_num_re_dmrs(pusch_pdu, &nb_dmrs_re_per_rb, &number_dmrs_symbols); + for (int i = start_symbol; i < start_symbol + number_of_symbols; i++) { + if((ul_dmrs_symb_pos >> i) & 0x01) + number_dmrs_symbols += 1; + } + + nb_dmrs_re_per_rb = ((dmrs_type == pusch_dmrs_type1) ? 6:4)*cdm_grps_no_data; LOG_D(PHY,"ulsch %x : start_rb %d bwp_start %d start_sc %d start_symbol %d num_symbols %d cdmgrpsnodata %d num_dmrs %d dmrs_re_per_rb %d\n", rnti,start_rb,pusch_pdu->bwp_start,start_sc,start_symbol,number_of_symbols,cdm_grps_no_data,number_dmrs_symbols,nb_dmrs_re_per_rb); diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c index 61bca6f409..68d8735411 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c @@ -34,7 +34,6 @@ #include "PHY/defs_nr_common.h" #include "PHY/defs_nr_UE.h" //#include "PHY/extern.h" -//#include "LAYER2/MAC/extern.h" #include "PHY/NR_UE_TRANSPORT/pucch_nr.h" #include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h" #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" @@ -91,7 +90,7 @@ void nr_generate_pucch0(PHY_VARS_NR_UE *ue, // the value of u,v (delta always 0 for PUCCH) has to be calculated according to TS 38.211 Subclause 6.3.2.2.1 uint8_t u[2]={0,0},v[2]={0,0}; - LOG_D(PHY,"pucch0: nr_symbols %d, start_symbol %d, prb_start %d, second_hop_prb %d, group_hop_flag %d, sequence_hop_flag %d, mcs %d\n",pucch_pdu->nr_of_symbols,pucch_pdu->start_symbol_index,pucch_pdu->prb_start,pucch_pdu->second_hop_prb,pucch_pdu->group_hop_flag,pucch_pdu->sequence_hop_flag,pucch_pdu->mcs); + LOG_D(PHY,"pucch0: slot %d nr_symbols %d, start_symbol %d, prb_start %d, second_hop_prb %d, group_hop_flag %d, sequence_hop_flag %d, mcs %d\n",nr_slot_tx,pucch_pdu->nr_of_symbols,pucch_pdu->start_symbol_index,pucch_pdu->prb_start,pucch_pdu->second_hop_prb,pucch_pdu->group_hop_flag,pucch_pdu->sequence_hop_flag,pucch_pdu->mcs); #ifdef DEBUG_NR_PUCCH_TX diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h index dcf7fb4a37..078a95605f 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h +++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h @@ -37,7 +37,6 @@ #include "PHY/defs_nr_common.h" #include "PHY/defs_nr_UE.h" //#include "PHY/extern.h" -//#include "LAYER2/MAC/extern.h" #include "common/utils/LOG/log.h" #include "common/utils/LOG/vcd_signal_dumper.h" diff --git a/openair1/PHY/TOOLS/time_meas.c b/openair1/PHY/TOOLS/time_meas.c index 001770c876..c62fbed106 100644 --- a/openair1/PHY/TOOLS/time_meas.c +++ b/openair1/PHY/TOOLS/time_meas.c @@ -18,17 +18,27 @@ * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org */ - +#define _GNU_SOURCE #include #include "time_meas.h" #include #include - +#include +#include "assertions.h" +#ifndef PHYSIM + #include + #include "common/config/config_userapi.h" +#endif // global var for openair performance profiler int opp_enabled = 0; double cpu_freq_GHz __attribute__ ((aligned(32))); double cpu_freq_GHz __attribute__ ((aligned(32)))=0.0; +#ifndef PHYSIM +static uint32_t max_cpumeasur; +static time_stats_t **measur_table; +notifiedFIFO_t measur_fifo; +#endif double get_cpu_freq_GHz(void) { if (cpu_freq_GHz <1 ) { @@ -64,8 +74,8 @@ int cpumeas(int action) } void print_meas_now(time_stats_t *ts, - const char *name, - FILE *file_name) + const char *name, + FILE *file_name) { if (opp_enabled) { //static double cpu_freq_GHz = 3.2; @@ -80,9 +90,9 @@ void print_meas_now(time_stats_t *ts, } void print_meas(time_stats_t *ts, - const char *name, - time_stats_t *total_exec_time, - time_stats_t *sf_exec_time) + const char *name, + time_stats_t *total_exec_time, + time_stats_t *sf_exec_time) { if (opp_enabled) { static int first_time = 0; @@ -133,3 +143,112 @@ double get_time_meas_us(time_stats_t *ts) return 0; } + +#ifndef PHYSIM +/* function for the asynchronous measurment module: cpu stat are sent to a dedicated thread + * which is in charge of computing the cpu time spent in a given function/algorithm... + */ + +time_stats_t *register_meas(char *name) +{ + for (int i=0; imeas_name = strdup(name); + measur_table[i]->meas_index = i; + measur_table[i]->tpoolmsg =newNotifiedFIFO_elt(sizeof(time_stats_msg_t),0,NULL,NULL); + measur_table[i]->tstatptr = (time_stats_msg_t *)NotifiedFifoData(measur_table[i]->tpoolmsg); + return measur_table[i]; + } + } + return NULL; +} + +void free_measurtbl(void) { + for (int i=0; imeas_name); + delNotifiedFIFO_elt(measur_table[i]->tpoolmsg); + free(measur_table[i]); + } + } + //free the fifo... +} + +void run_cpumeasur(void) { + struct sched_param schedp; + pthread_setname_np(pthread_self(), "measur"); + schedp.sched_priority=0; + int rt=pthread_setschedparam(pthread_self(), SCHED_IDLE, &schedp); + AssertFatal(rt==0, "couldn't set measur thread priority: %s\n",strerror(errno)); + initNotifiedFIFO(&measur_fifo); + while(1) { + notifiedFIFO_elt_t *msg = pullNotifiedFIFO(&measur_fifo); + time_stats_msg_t *tsm = (time_stats_msg_t *)NotifiedFifoData(msg); + switch(tsm->msgid) { + case TIMESTAT_MSGID_START: + measur_table[tsm->timestat_id]->in=tsm->ts; + (measur_table[tsm->timestat_id]->trials)++; + break; + case TIMESTAT_MSGID_STOP: + /// process duration is the difference between two clock points + measur_table[tsm->timestat_id]->p_time = (tsm->ts - measur_table[tsm->timestat_id]->in); + measur_table[tsm->timestat_id]->diff += measur_table[tsm->timestat_id]->p_time; + if ( measur_table[tsm->timestat_id]->p_time > measur_table[tsm->timestat_id]->max ) + measur_table[tsm->timestat_id]->max = measur_table[tsm->timestat_id]->p_time; + break; + case TIMESTAT_MSGID_DISPLAY: + { + char aline[256]; + int start, stop; + if (tsm->displayFunc != NULL) { + if(tsm->timestat_id >= 0) { + start=tsm->timestat_id ; + stop=start+1; + } + else { + start=0; + stop=max_cpumeasur ; + } + for (int i=start ; imeas_name, measur_table[i]->trials==0?0:( (measur_table[i]->trials/measur_table[i]->diff )/ cpu_freq_GHz /1000 )); + tsm->displayFunc(aline); + } + } + } + } + break; + case TIMESTAT_MSGID_END: + free_measurtbl(); + delNotifiedFIFO_elt(msg); + pthread_exit(NULL); + break; + default: + break; + } + delNotifiedFIFO_elt(msg); + } +} + + +void init_meas(void) { + pthread_t thid; + paramdef_t cpumeasur_params[] = CPUMEASUR_PARAMS_DESC; + int numparams=sizeof(cpumeasur_params)/sizeof(paramdef_t); + int rt = config_get( cpumeasur_params,numparams,CPUMEASUR_SECTION); + AssertFatal(rt >= 0, "cpumeasur configuration couldn't be performed"); + measur_table=calloc(max_cpumeasur,sizeof( time_stats_t *)); + AssertFatal(measur_table!=NULL, "couldn't allocate %u cpu measurements entries\n",max_cpumeasur); + rt=pthread_create(&thid,NULL, (void *(*)(void *))run_cpumeasur, NULL); + AssertFatal(rt==0, "couldn't create cpu measurment thread: %s\n",strerror(errno)); +} + +void end_meas(void) { + notifiedFIFO_elt_t *nfe = newNotifiedFIFO_elt(sizeof(time_stats_msg_t),0,NULL,NULL); + time_stats_msg_t *msg = (time_stats_msg_t *)NotifiedFifoData(nfe); + msg->msgid = TIMESTAT_MSGID_END ; + pushNotifiedFIFO(&measur_fifo, nfe); +} +#endif diff --git a/openair1/PHY/TOOLS/time_meas.h b/openair1/PHY/TOOLS/time_meas.h index e2ceef8405..f78ea55530 100644 --- a/openair1/PHY/TOOLS/time_meas.h +++ b/openair1/PHY/TOOLS/time_meas.h @@ -31,31 +31,57 @@ #include #include #include +#ifndef PHYSIM + #include "common/utils/threadPool/thread-pool.h" +#endif // global var to enable openair performance profiler extern int opp_enabled; extern double cpu_freq_GHz __attribute__ ((aligned(32)));; - +// structure to store data to compute cpu measurment #if defined(__x86_64__) || defined(__i386__) -typedef struct { - long long in; - long long diff; - long long p_time; /*!< \brief absolute process duration */ - long long diff_square; /*!< \brief process duration square */ - long long max; - int trials; - int meas_flag; -} time_stats_t; + #define OAI_CPUTIME_TYPE long long #elif defined(__arm__) -typedef struct { - uint32_t in; - uint32_t diff; - uint32_t p_time; /*!< \brief absolute process duration */ - uint32_t diff_square; /*!< \brief process duration square */ - uint32_t max; - int trials; -} time_stats_t; + #define OAI_CPUTIME_TYPE uint32_t +#else + #error "building on unsupported CPU architecture" #endif +#define TIMESTAT_MSGID_START 0 /*!< \brief send time at measure starting point */ +#define TIMESTAT_MSGID_STOP 1 /*!< \brief send time at measure end point */ +#define TIMESTAT_MSGID_ENABLE 2 /*!< \brief enable measure point */ +#define TIMESTAT_MSGID_DISABLE 3 /*!< \brief disable measure point */ +#define TIMESTAT_MSGID_DISPLAY 10 /*!< \brief display measure */ +#define TIMESTAT_MSGID_END 11 /*!< \brief stops the measure threads and free assocated resources */ +typedef void(*meas_printfunc_t)(const char* format, ...); +typedef struct { + int msgid; /*!< \brief message id, as defined by TIMESTAT_MSGID_X macros */ + int timestat_id; /*!< \brief points to the time_stats_t entry in cpumeas table */ + OAI_CPUTIME_TYPE ts; /*!< \brief time stamp */ + meas_printfunc_t displayFunc; /*!< \brief function to call when DISPLAY message is received*/ +} time_stats_msg_t; + + +typedef struct { + OAI_CPUTIME_TYPE in; /*!< \brief time at measure starting point */ + OAI_CPUTIME_TYPE diff; /*!< \brief average difference between time at starting point and time at endpoint*/ + OAI_CPUTIME_TYPE p_time; /*!< \brief absolute process duration */ + OAI_CPUTIME_TYPE diff_square; /*!< \brief process duration square */ + OAI_CPUTIME_TYPE max; /*!< \brief maximum difference between time at starting point and time at endpoint*/ + int trials; /*!< \brief number of start point - end point iterations */ + int meas_flag; /*!< \brief 1: stop_meas not called (consecutive calls of start_meas) */ + char *meas_name; /*!< \brief name to use when printing the measure (not used for PHY simulators)*/ + int meas_index; /*!< \brief index of this measure in the measure array (not used for PHY simulators)*/ + int meas_enabled; /*!< \brief per measure enablement flag. send_meas tests this flag, unused today in start_meas and stop_meas*/ +#ifndef PHYSIM + notifiedFIFO_elt_t *tpoolmsg; /*!< \brief message pushed to the cpu measurment queue to report a measure START or STOP */ + time_stats_msg_t *tstatptr; /*!< \brief pointer to the time_stats_msg_t data in the tpoolmsg, stored here for perf considerations*/ +#endif +} time_stats_t; +#define MEASURE_ENABLED(X) (X->meas_enabled) + + + + static inline void start_meas(time_stats_t *ts) __attribute__((always_inline)); static inline void stop_meas(time_stats_t *ts) __attribute__((always_inline)); @@ -137,4 +163,28 @@ static inline void copy_meas(time_stats_t *dst_ts,time_stats_t *src_ts) { dst_ts->max=src_ts->max; } } + +#ifndef PHYSIM +extern notifiedFIFO_t measur_fifo; +#define CPUMEASUR_SECTION "cpumeasur" + +#define CPUMEASUR_PARAMS_DESC { \ + {"max_cpumeasur", "Max number of cpu measur entries", 0, uptr:&max_cpumeasur, defintval:100, TYPE_UINT, 0},\ + } + + void init_meas(void); + time_stats_t *register_meas(char *name); + #define START_MEAS(X) send_meas(X, TIMESTAT_MSGID_START) + #define STOP_MEAS(X) send_meas(X, TIMESTAT_MSGID_STOP) + static inline void send_meas(time_stats_t *ts, int msgid) { + if (MEASURE_ENABLED(ts) ) { + ts->tstatptr->timestat_id=ts->meas_index; + ts->tstatptr->msgid = msgid ; + ts->tstatptr->ts = rdtsc_oai(); + pushNotifiedFIFO(&measur_fifo, ts->tpoolmsg); + } + } + void end_meas(void); + +#endif //ifndef PHYSIM #endif diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index 66cb51adc6..76dd92ef5d 100644 --- a/openair1/PHY/defs_RU.h +++ b/openair1/PHY/defs_RU.h @@ -762,6 +762,7 @@ typedef struct RRU_config_s { typedef struct processingData_RU { int frame_tx; int slot_tx; + int next_slot; openair0_timestamp timestamp_tx; RU_t *ru; } processingData_RU_t; diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 778724218f..11b5112a6c 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -122,8 +122,6 @@ typedef struct { typedef struct { uint8_t active; - int frame; - int slot; nfapi_nr_dl_tti_csi_rs_pdu csirs_pdu; } NR_gNB_CSIRS_t; @@ -134,6 +132,8 @@ typedef struct { } NR_gNB_UL_PDCCH_t; typedef struct { + int frame; + int dump_frame; uint16_t rnti; int round_trials[8]; int total_bytes_tx; @@ -143,6 +143,7 @@ typedef struct { int power[NB_ANTENNAS_RX]; int noise_power[NB_ANTENNAS_RX]; int DTX; + int sync_pos; } NR_gNB_SCH_STATS_t; typedef struct { @@ -248,6 +249,8 @@ typedef struct { uint32_t slot; /// Index of current HARQ round for this DLSCH uint8_t round; + uint8_t ndi; + bool new_rx; /// Last TPC command uint8_t TPC; /// MIMO mode for this DLSCH @@ -659,31 +662,33 @@ typedef struct { //! estimated noise power (linear) unsigned int n0_power[MAX_NUM_RU_PER_gNB]; //! estimated noise power (dB) - unsigned short n0_power_dB[MAX_NUM_RU_PER_gNB]; + unsigned int n0_power_dB[MAX_NUM_RU_PER_gNB]; //! total estimated noise power (linear) unsigned int n0_power_tot; //! estimated avg noise power (dB) - unsigned short n0_power_tot_dB; + unsigned int n0_power_tot_dB; //! estimated avg noise power (dB) - short n0_power_tot_dBm; + int n0_power_tot_dBm; //! estimated avg noise power per RB per RX ant (lin) - unsigned short n0_subband_power[MAX_NUM_RU_PER_gNB][275]; + unsigned int n0_subband_power[MAX_NUM_RU_PER_gNB][275]; //! estimated avg noise power per RB per RX ant (dB) - unsigned short n0_subband_power_dB[MAX_NUM_RU_PER_gNB][275]; + unsigned int n0_subband_power_dB[MAX_NUM_RU_PER_gNB][275]; //! estimated avg subband noise power (dB) - unsigned short n0_subband_power_avg_dB; + unsigned int n0_subband_power_avg_dB; + //! estimated avg subband noise power per antenna (dB) + unsigned int n0_subband_power_avg_perANT_dB[NB_ANTENNAS_RX]; //! estimated avg noise power per RB (dB) - short n0_subband_power_tot_dB[275]; + int n0_subband_power_tot_dB[275]; //! estimated avg noise power per RB (dBm) - short n0_subband_power_tot_dBm[275]; + int n0_subband_power_tot_dBm[275]; // gNB measurements (per user) //! estimated received spatial signal power (linear) unsigned int rx_spatial_power[NUMBER_OF_NR_ULSCH_MAX][NB_ANTENNAS_TX][NB_ANTENNAS_RX]; //! estimated received spatial signal power (dB) - unsigned short rx_spatial_power_dB[NUMBER_OF_NR_ULSCH_MAX][NB_ANTENNAS_TX][NB_ANTENNAS_RX]; + unsigned int rx_spatial_power_dB[NUMBER_OF_NR_ULSCH_MAX][NB_ANTENNAS_TX][NB_ANTENNAS_RX]; //! estimated rssi (dBm) - short rx_rssi_dBm[NUMBER_OF_NR_ULSCH_MAX]; + int rx_rssi_dBm[NUMBER_OF_NR_ULSCH_MAX]; //! estimated correlation (wideband linear) between spatial channels (computed in dlsch_demodulation) int rx_correlation[NUMBER_OF_NR_ULSCH_MAX][2]; //! estimated correlation (wideband dB) between spatial channels (computed in dlsch_demodulation) @@ -759,7 +764,6 @@ typedef struct PHY_VARS_gNB_s { // nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu; // nfapi_nr_ul_dci_request_pdus_t *ul_dci_pdu; uint16_t num_pdsch_rnti[80]; - NR_gNB_SSB_t ssb[64]; NR_gNB_PBCH pbch; nr_cce_t cce_list[MAX_DCI_CORESET][NR_MAX_PDCCH_AGG_LEVEL]; NR_gNB_COMMON common_vars; @@ -767,7 +771,6 @@ typedef struct PHY_VARS_gNB_s { NR_gNB_PUSCH *pusch_vars[NUMBER_OF_NR_ULSCH_MAX]; NR_gNB_PUCCH_t *pucch[NUMBER_OF_NR_PUCCH_MAX]; NR_gNB_PDCCH_t pdcch_pdu[NUMBER_OF_NR_PDCCH_MAX]; - NR_gNB_CSIRS_t csirs_pdu[NUMBER_OF_NR_CSIRS_MAX]; NR_gNB_UL_PDCCH_t ul_pdcch_pdu[NUMBER_OF_NR_PDCCH_MAX]; NR_gNB_DLSCH_t *dlsch[NUMBER_OF_NR_DLSCH_MAX][2]; // Nusers times two spatial streams NR_gNB_ULSCH_t *ulsch[NUMBER_OF_NR_ULSCH_MAX][2]; // [Nusers times][2 codewords] @@ -804,9 +807,8 @@ typedef struct PHY_VARS_gNB_s { /// PUSCH DMRS uint32_t ****nr_gold_pusch_dmrs; - // Mask of occupied RBs - uint32_t rb_mask_ul[9]; - int ulmask_symb; + // Mask of occupied RBs, per symbol and PRB + uint32_t rb_mask_ul[14][9]; /// CSI RS sequence uint32_t ***nr_gold_csi_rs; @@ -851,10 +853,13 @@ typedef struct PHY_VARS_gNB_s { int pusch_thres; int prach_thres; uint64_t bad_pucch; + int num_ulprbbl; + int ulprbbl[275]; /* time_stats_t phy_proc; */ - time_stats_t phy_proc_tx; + time_stats_t *phy_proc_tx_0; + time_stats_t *phy_proc_tx_1; time_stats_t phy_proc_rx; time_stats_t rx_prach; /* @@ -946,4 +951,24 @@ typedef struct processingData_L1 { PHY_VARS_gNB *gNB; } processingData_L1_t; +typedef enum { + FILLED, + FILLING, + NOT_FILLED +} msgStatus_t; + +typedef struct processingData_L1tx { + int frame; + int slot; + openair0_timestamp timestamp_tx; + PHY_VARS_gNB *gNB; + nfapi_nr_dl_tti_pdcch_pdu pdcch_pdu; + nfapi_nr_ul_dci_request_pdus_t ul_pdcch_pdu; + NR_gNB_CSIRS_t csirs_pdu[NUMBER_OF_NR_CSIRS_MAX]; + NR_gNB_DLSCH_t *dlsch[NUMBER_OF_NR_DLSCH_MAX][2]; + NR_gNB_SSB_t ssb[64]; + uint16_t num_pdsch_slot; + time_stats_t phy_proc_tx; +} processingData_L1tx_t; + #endif diff --git a/openair1/PHY/impl_defs_top.h b/openair1/PHY/impl_defs_top.h index fa021ffe81..31b9899605 100644 --- a/openair1/PHY/impl_defs_top.h +++ b/openair1/PHY/impl_defs_top.h @@ -272,9 +272,14 @@ #define NB_NUMEROLOGIES_NR (5) #define TDD_CONFIG_NB_FRAMES (2) #define NR_MAX_SLOTS_PER_FRAME (160) /* number of slots per frame */ -#define NR_UE_CAPABILITY_SLOT_RX_TO_TX (6) /* FFS_NR_TODO it defines ue capability which is the number of slots */ - /* - between reception of pdsch and tarnsmission of its acknowlegment */ - /* - between reception of un uplink grant and its related transmission */ + +/* FFS_NR_TODO it defines ue capability which is the number of slots */ +/* - between reception of pdsch and tarnsmission of its acknowlegment */ +/* - between reception of un uplink grant and its related transmission */ +/* - FIXME temprarily set to 5 to avoid timing issues at OAI UE in rfsimulator */ +/* - issues caused by no rendez-vous point between TX and RX in the OAI UE */ +#define NR_UE_CAPABILITY_SLOT_RX_TO_TX (5) + #ifndef NO_RAT_NR #define DURATION_RX_TO_TX (NR_UE_CAPABILITY_SLOT_RX_TO_TX) /* for NR this will certainly depends to such UE capability which is not yet defined */ #else diff --git a/openair1/SCHED/nfapi_lte_dummy.c b/openair1/SCHED/nfapi_lte_dummy.c index 7d1e7e7684..4e82c3ecb3 100644 --- a/openair1/SCHED/nfapi_lte_dummy.c +++ b/openair1/SCHED/nfapi_lte_dummy.c @@ -13,11 +13,11 @@ void handle_nr_nfapi_ssb_pdu(PHY_VARS_gNB *gNB,int frame,int slot, nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdu){} int16_t find_nr_dlsch(uint16_t rnti, PHY_VARS_gNB *gNB,find_type_t type){return 0;} -void handle_nr_nfapi_pdsch_pdu(PHY_VARS_gNB *gNB,int frame,int slot, - nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu, +void handle_nr_nfapi_pdsch_pdu(processingData_L1tx_t *msgTx, + nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu, uint8_t *sdu){ - } -void handle_nfapi_nr_csirs_pdu(PHY_VARS_gNB *gNB, +} +void handle_nfapi_nr_csirs_pdu(processingData_L1tx_t *msgTx, int frame, int slot, nfapi_nr_dl_tti_csi_rs_pdu *csirs_pdu){ } @@ -51,4 +51,5 @@ void nr_phy_config_request(NR_PHY_Config_t *gNB){} void install_nr_schedule_handlers(NR_IF_Module_t *if_inst){} -void nr_dump_frame_parms(NR_DL_FRAME_PARMS *fp){} \ No newline at end of file +void nr_dump_frame_parms(NR_DL_FRAME_PARMS *fp){} + diff --git a/openair1/SCHED/nfapi_nr_dummy.c b/openair1/SCHED/nfapi_nr_dummy.c index 1286a4e48a..511911723f 100644 --- a/openair1/SCHED/nfapi_nr_dummy.c +++ b/openair1/SCHED/nfapi_nr_dummy.c @@ -13,11 +13,11 @@ void handle_nr_nfapi_ssb_pdu(PHY_VARS_gNB *gNB,int frame,int slot, nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdu){} int16_t find_nr_dlsch(uint16_t rnti, PHY_VARS_gNB *gNB,find_type_t type){return 0;} -void handle_nr_nfapi_pdsch_pdu(PHY_VARS_gNB *gNB,int frame,int slot, - nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu, +void handle_nr_nfapi_pdsch_pdu(processingData_L1tx_t *msgTx, + nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu, uint8_t *sdu){ - } -void handle_nfapi_nr_csirs_pdu(PHY_VARS_gNB *gNB, +} +void handle_nfapi_nr_csirs_pdu(processingData_L1tx_t *msgTx, int frame, int slot, nfapi_nr_dl_tti_csi_rs_pdu *csirs_pdu){ } @@ -53,4 +53,3 @@ void install_nr_schedule_handlers(NR_IF_Module_t *if_inst){} //void nr_dump_frame_parms(NR_DL_FRAME_PARMS *fp){} - \ No newline at end of file diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c index fa762fa5b8..8f315ba214 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ b/openair1/SCHED_NR/fapi_nr_l1.c @@ -30,6 +30,7 @@ * \warning */ #include "fapi_nr_l1.h" +#include "common/ran_context.h" #include "PHY/NR_TRANSPORT/nr_transport_proto.h" #include "PHY/NR_TRANSPORT/nr_dlsch.h" #include "PHY/NR_TRANSPORT/nr_dci.h" @@ -43,7 +44,7 @@ extern int oai_nfapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req); extern uint8_t nfapi_mode; -void handle_nr_nfapi_ssb_pdu(PHY_VARS_gNB *gNB,int frame,int slot, +void handle_nr_nfapi_ssb_pdu(processingData_L1tx_t *msgTx,int frame,int slot, nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdu) { @@ -53,11 +54,11 @@ void handle_nr_nfapi_ssb_pdu(PHY_VARS_gNB *gNB,int frame,int slot, uint8_t i_ssb = dl_tti_pdu->ssb_pdu.ssb_pdu_rel15.SsbBlockIndex; LOG_D(PHY,"%d.%d : ssb index %d pbch_pdu: %x\n",frame,slot,i_ssb,dl_tti_pdu->ssb_pdu.ssb_pdu_rel15.bchPayload); - if (gNB->ssb[i_ssb].active) + if (msgTx->ssb[i_ssb].active) AssertFatal(1==0,"SSB PDU with index %d already active\n",i_ssb); else { - gNB->ssb[i_ssb].active = true; - memcpy((void*)&gNB->ssb[i_ssb].ssb_pdu,&dl_tti_pdu->ssb_pdu,sizeof(dl_tti_pdu->ssb_pdu)); + msgTx->ssb[i_ssb].active = true; + memcpy((void*)&msgTx->ssb[i_ssb].ssb_pdu,&dl_tti_pdu->ssb_pdu,sizeof(dl_tti_pdu->ssb_pdu)); } } @@ -100,46 +101,16 @@ void handle_nr_nfapi_ssb_pdu(PHY_VARS_gNB *gNB,int frame,int slot, }*/ -void handle_nfapi_nr_pdcch_pdu(PHY_VARS_gNB *gNB, - int frame, int slot, - nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu) { - - LOG_D(PHY,"Frame %d, Slot %d: DCI processing - proc:slot_tx:%d pdcch_pdu_rel15->numDlDci:%d\n",frame,slot, slot, pdcch_pdu->pdcch_pdu_rel15.numDlDci); - - // copy dci configuration into gNB structure - // gNB->pdcch_pdu = pdcch_pdu; - - nr_fill_dci(gNB,frame,slot,pdcch_pdu); - -} - - -void handle_nfapi_nr_ul_dci_pdu(PHY_VARS_gNB *gNB, - int frame, int slot, - nfapi_nr_ul_dci_request_pdus_t *ul_dci_request_pdu) { - - LOG_D(PHY,"Frame %d, Slot %d: UL DCI processing - proc:slot_tx:%d pdcch_pdu_rel15->numDlDci:%d\n",frame,slot, slot, ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15.numDlDci); - - // copy dci configuration into gNB structure - // gNB->ul_dci_pdu = ul_dci_request_pdu; - - nr_fill_ul_dci(gNB,frame,slot,ul_dci_request_pdu); - -} - - -void handle_nfapi_nr_csirs_pdu(PHY_VARS_gNB *gNB, - int frame, int slot, +void handle_nfapi_nr_csirs_pdu(processingData_L1tx_t *msgTx, + int frame,int slot, nfapi_nr_dl_tti_csi_rs_pdu *csirs_pdu) { int found = 0; for (int id=0; idcsirs_pdu[id]; + NR_gNB_CSIRS_t *csirs = &msgTx->csirs_pdu[id]; if (csirs->active == 0) { LOG_D(PHY,"Frame %d Slot %d CSI_RS with ID %d is now active\n",frame,slot,id); - csirs->frame = frame; - csirs->slot = slot; csirs->active = 1; memcpy((void*)&csirs->csirs_pdu, (void*)csirs_pdu, sizeof(nfapi_nr_dl_tti_csi_rs_pdu)); found = 1; @@ -151,13 +122,13 @@ void handle_nfapi_nr_csirs_pdu(PHY_VARS_gNB *gNB, } -void handle_nr_nfapi_pdsch_pdu(PHY_VARS_gNB *gNB,int frame,int slot, +void handle_nr_nfapi_pdsch_pdu(processingData_L1tx_t *msgTx, nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu, uint8_t *sdu) { - nr_fill_dlsch(gNB,frame,slot,pdsch_pdu,sdu); + nr_fill_dlsch(msgTx,pdsch_pdu,sdu); } @@ -176,7 +147,11 @@ void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO){ AssertFatal(RC.gNB!=NULL,"RC.gNB is null\n"); AssertFatal(RC.gNB[Mod_id]!=NULL,"RC.gNB[%d] is null\n",Mod_id); - gNB = RC.gNB[Mod_id]; + gNB = RC.gNB[Mod_id]; + + notifiedFIFO_elt_t *res; + res = pullTpool(gNB->resp_L1_tx, gNB->threadPool); + processingData_L1tx_t *msgTx = (processingData_L1tx_t *)NotifiedFifoData(res); uint8_t number_dl_pdu = (DL_req==NULL) ? 0 : DL_req->dl_tti_request_body.nPDUs; uint8_t number_ul_dci_pdu = (UL_dci_req==NULL) ? 0 : UL_dci_req->numPdus; @@ -184,7 +159,7 @@ void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO){ uint8_t number_tx_data_pdu = (TX_req == NULL) ? 0 : TX_req->Number_of_PDUs; if (NFAPI_MODE == NFAPI_MONOLITHIC){ - if (DL_req != NULL && TX_req!=NULL) + if (DL_req != NULL && TX_req!=NULL && (number_dl_pdu > 0 || number_ul_dci_pdu > 0 || number_ul_tti_pdu > 0)) LOG_D(PHY,"NFAPI: Sched_INFO:SFN/SLOT:%04d/%d DL_req:SFN/SLO:%04d/%d:dl_pdu:%d tx_req:SFN/SLOT:%04d/%d:pdus:%d;ul_dci %d ul_tti %d\n", frame,slot, DL_req->SFN,DL_req->Slot,number_dl_pdu, @@ -192,33 +167,31 @@ void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO){ number_ul_dci_pdu,number_ul_tti_pdu); int pdcch_received=0; - gNB->num_pdsch_rnti[slot]=0; - for (int i=0; inumber_of_nr_dlsch_max; i++) { - gNB->dlsch[i][0]->rnti=0; - gNB->dlsch[i][0]->harq_mask=0; - } + msgTx->num_pdsch_slot=0; + msgTx->pdcch_pdu.pdcch_pdu_rel15.numDlDci = 0; + msgTx->ul_pdcch_pdu.pdcch_pdu.pdcch_pdu_rel15.numDlDci = 0; + msgTx->slot = slot; + msgTx->frame = frame; for (int i=0;idl_tti_request_body.dl_tti_pdu_list[i]; LOG_D(PHY,"NFAPI: dl_pdu %d : type %d\n",i,dl_tti_pdu->PDUType); switch (dl_tti_pdu->PDUType) { case NFAPI_NR_DL_TTI_SSB_PDU_TYPE: - handle_nr_nfapi_ssb_pdu(gNB,frame,slot, + handle_nr_nfapi_ssb_pdu(msgTx,frame,slot, dl_tti_pdu); break; case NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE: AssertFatal(pdcch_received == 0, "pdcch_received is not 0, we can only handle one PDCCH PDU per slot\n"); - handle_nfapi_nr_pdcch_pdu(gNB, - frame, slot, - &dl_tti_pdu->pdcch_pdu); + msgTx->pdcch_pdu = dl_tti_pdu->pdcch_pdu; + pdcch_received = 1; break; case NFAPI_NR_DL_TTI_CSI_RS_PDU_TYPE: LOG_D(PHY,"frame %d, slot %d, Got NFAPI_NR_DL_TTI_CSI_RS_PDU_TYPE for %d.%d\n",frame,slot,DL_req->SFN,DL_req->Slot); - handle_nfapi_nr_csirs_pdu(gNB, - frame, slot, + handle_nfapi_nr_csirs_pdu(msgTx,frame,slot, &dl_tti_pdu->csi_rs_pdu); break; @@ -229,16 +202,17 @@ void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO){ AssertFatal(TX_req->pdu_list[pduIndex].num_TLV == 1, "TX_req->pdu_list[%d].num_TLV %d != 1\n", pduIndex,TX_req->pdu_list[pduIndex].num_TLV); uint8_t *sdu = (uint8_t *)TX_req->pdu_list[pduIndex].TLVs[0].value.direct; - handle_nr_nfapi_pdsch_pdu(gNB,frame,slot,&dl_tti_pdu->pdsch_pdu, sdu); - break; + AssertFatal(msgTx->num_pdsch_slot < gNB->number_of_nr_dlsch_max,"Number of PDSCH PDUs %d exceeded the limit %d\n", + msgTx->num_pdsch_slot,gNB->number_of_nr_dlsch_max); + handle_nr_nfapi_pdsch_pdu(msgTx,&dl_tti_pdu->pdsch_pdu, sdu); } } + if (number_ul_dci_pdu > 0) + msgTx->ul_pdcch_pdu = UL_dci_req->ul_dci_pdu_list[number_ul_dci_pdu-1]; // copy the last pdu + + pushNotifiedFIFO(gNB->resp_L1_tx,res); - for (int i=0;iul_dci_pdu_list[i]); - } - for (int i = 0; i < number_ul_tti_pdu; i++) { switch (UL_tti_req->pdus_list[i].pdu_type) { case NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE: @@ -266,13 +240,13 @@ void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO){ if (number_ul_dci_pdu>0) oai_nfapi_ul_dci_req(UL_dci_req); - + if (number_dl_pdu>0) oai_nfapi_dl_tti_req(DL_req); if (number_tx_data_pdu>0) oai_nfapi_tx_data_req(TX_req); - } - + } + } diff --git a/openair1/SCHED_NR/fapi_nr_l1.h b/openair1/SCHED_NR/fapi_nr_l1.h index 19c98e4ec0..f598b263c3 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.h +++ b/openair1/SCHED_NR/fapi_nr_l1.h @@ -37,13 +37,13 @@ #include "nfapi_nr_interface_scf.h" // added -void handle_nr_nfapi_ssb_pdu(PHY_VARS_gNB *gNB, +void handle_nr_nfapi_ssb_pdu(processingData_L1tx_t *msgTx, int frame,int slot, nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdu); void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO); -void handle_nfapi_nr_csirs_pdu(PHY_VARS_gNB *gNB, +void handle_nfapi_nr_csirs_pdu(processingData_L1tx_t *msgTx, int frame, int slot, nfapi_nr_dl_tti_csi_rs_pdu *csirs_pdu); @@ -51,12 +51,12 @@ void handle_nfapi_nr_pdcch_pdu(PHY_VARS_gNB *gNB, int frame, int subframe, nfapi_nr_dl_tti_pdcch_pdu *dcl_dl_pdu); -void handle_nr_nfapi_pdsch_pdu(PHY_VARS_gNB *gNB,int frame,int slot, +void handle_nr_nfapi_pdsch_pdu(processingData_L1tx_t *msgTx, nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu, uint8_t *sdu); -void nr_fill_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int UE_id, uint8_t harq_pid, uint8_t crc_flag); +void nr_fill_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int UE_id, uint8_t harq_pid, uint8_t crc_flag,int dtx_flag); //added void handle_nfapi_nr_ul_dci_pdu(PHY_VARS_gNB *gNB, diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index cc51ce7fe3..1ea8dbdf3c 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -49,6 +49,59 @@ extern uint8_t nfapi_mode; +uint8_t get_nr_prach_duration(uint8_t prach_format){ + + switch(prach_format){ + + case 0: // format 0 + return 0; + + case 1: // format 1 + return 0; + + case 2: // format 2 + return 0; + + case 3: // format 3 + return 0; + + case 4: // format A1 + return 2; + + case 5: // format A2 + return 4; + + case 6: // format A3 + return 6; + + case 7: // format B1 + return 2; + + case 8: // format B4 + return 12; + + case 9: // format C0 + return 2; + + case 10: // format C2 + return 6; + + case 11: // format A1/B1 + return 2; + + case 12: // format A2/B2 + return 4; + + case 13: // format A3/B3 + return 6; + + default : + AssertFatal(1==0,"Invalid Prach format\n"); + break; + + } +} + void L1_nr_prach_procedures(PHY_VARS_gNB *gNB,int frame,int slot) { uint16_t max_preamble[4]={0},max_preamble_energy[4]={0},max_preamble_delay[4]={0}; @@ -121,7 +174,7 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB,int frame,int slot) { if ((gNB->prach_energy_counter == 100) && (max_preamble_energy[0] > gNB->measurements.prach_I0+gNB->prach_thres)) { - LOG_I(PHY,"[gNB %d][RAPROC] Frame %d, slot %d Initiating RA procedure with preamble %d, energy %d.%d dB (I0 %d, thres %d), delay %d start symbol %u freq index %u\n", + LOG_I(NR_PHY,"[gNB %d][RAPROC] Frame %d, slot %d Initiating RA procedure with preamble %d, energy %d.%d dB (I0 %d, thres %d), delay %d start symbol %u freq index %u\n", gNB->Mod_id, frame, slot, diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c index eb0a4f8cdc..d8fa11d157 100644 --- a/openair1/SCHED_NR/nr_ru_procedures.c +++ b/openair1/SCHED_NR/nr_ru_procedures.c @@ -531,12 +531,12 @@ void nr_fep0(RU_t *ru, int first_half) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+proc->tti_rx, 1); - // remove_7_5_kHz(ru,(slot&1)+(proc->tti_rx<<1)); + int offset = (proc->tti_rx&3) * fp->symbols_per_slot * fp->ofdm_symbol_size; for (l = start_symbol; l < end_symbol; l++) { for (aa = 0; aa < fp->nb_antennas_rx; aa++) { nr_slot_fep_ul(fp, ru->common.rxdata[aa], - ru->common.rxdataF[aa], + &ru->common.rxdataF[aa][offset], l, proc->tti_rx, ru->N_TA_offset); @@ -665,14 +665,15 @@ void nr_fep_full(RU_t *ru, int slot) { start_meas(&ru->ofdm_demod_stats); if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 1 ); + // remove_7_5_kHz(ru,proc->tti_rx<<1); // remove_7_5_kHz(ru,1+(proc->tti_rx<<1)); - + int offset = (proc->tti_rx&3)*(fp->symbols_per_slot * fp->ofdm_symbol_size); for (l = 0; l < fp->symbols_per_slot; l++) { for (aa = 0; aa < fp->nb_antennas_rx; aa++) { nr_slot_fep_ul(fp, ru->common.rxdata[aa], - ru->common.rxdataF[aa], + &ru->common.rxdataF[aa][offset], l, proc->tti_rx, ru->N_TA_offset); diff --git a/openair1/SCHED_NR/phy_frame_config_nr.c b/openair1/SCHED_NR/phy_frame_config_nr.c index 9be6780597..25c39846fe 100644 --- a/openair1/SCHED_NR/phy_frame_config_nr.c +++ b/openair1/SCHED_NR/phy_frame_config_nr.c @@ -30,6 +30,7 @@ ************************************************************************/ #include "PHY/defs_nr_common.h" +#include "PHY/defs_gNB.h" #include "PHY/defs_nr_UE.h" #include "SCHED_NR/phy_frame_config_nr.h" @@ -308,6 +309,21 @@ int set_tdd_configuration_dedicated_nr(NR_DL_FRAME_PARMS *frame_parms) { * *********************************************************************/ +int get_next_downlink_slot(PHY_VARS_gNB *gNB, nfapi_nr_config_request_scf_t *cfg, int nr_frame, int nr_slot) { + + int slot = nr_slot; + int frame = nr_frame; + int slots_per_frame = gNB->frame_parms.slots_per_frame; + while (true) { + slot++; + if (slot/slots_per_frame) frame++; + slot %= slots_per_frame; + int slot_type = nr_slot_select(cfg, frame, slot); + if (slot_type == NR_DOWNLINK_SLOT || slot_type == NR_MIXED_SLOT) return slot; + AssertFatal(frame < (nr_frame+2), "Something went worng. This shouldn't happen\n"); + } +} + int nr_slot_select(nfapi_nr_config_request_scf_t *cfg, int nr_frame, int nr_slot) { /* for FFD all slot can be considered as an uplink */ int mu = cfg->ssb_config.scs_common.value,check_slot=0; diff --git a/openair1/SCHED_NR/phy_frame_config_nr.h b/openair1/SCHED_NR/phy_frame_config_nr.h index 434dc41d1f..aba26283ed 100644 --- a/openair1/SCHED_NR/phy_frame_config_nr.h +++ b/openair1/SCHED_NR/phy_frame_config_nr.h @@ -92,5 +92,7 @@ void free_tdd_configuration_nr(NR_DL_FRAME_PARMS *frame_parms); void free_tdd_configuration_dedicated_nr(NR_DL_FRAME_PARMS *frame_parms); +int get_next_downlink_slot(PHY_VARS_gNB *gNB, nfapi_nr_config_request_scf_t *cfg, int nr_frame, int nr_slot); + #endif /* PHY_FRAME_CONFIG_NR_H */ diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 0a87a08a56..63cf6f2f2d 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -124,10 +124,12 @@ void nr_common_signal_procedures (PHY_VARS_gNB *gNB,int frame,int slot,nfapi_nr_ } -void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, - int frame,int slot, +void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, + int frame, + int slot, int do_meas) { int aa; + PHY_VARS_gNB *gNB = msgTx->gNB; NR_DL_FRAME_PARMS *fp=&gNB->frame_parms; nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; int offset = gNB->CC_id; @@ -138,7 +140,7 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_TX+offset,1); - if (do_meas==1) start_meas(&gNB->phy_proc_tx); + if (do_meas==1) start_meas(&msgTx->phy_proc_tx); // clear the transmit data array and beam index for the current slot for (aa=0; aacarrier_config.num_tx_ant.value; aa++) { @@ -147,58 +149,44 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_COMMON_TX,1); - for (int i=0; iLmax; i++) { - if (gNB->ssb[i].active) { - nr_common_signal_procedures(gNB,frame,slot,gNB->ssb[i].ssb_pdu); - gNB->ssb[i].active = false; + if (msgTx->ssb[i].active) { + nr_common_signal_procedures(gNB,frame,slot,msgTx->ssb[i].ssb_pdu); + msgTx->ssb[i].active = false; } } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_COMMON_TX,0); - int pdcch_pdu_id=find_nr_pdcch(frame,slot,gNB,SEARCH_EXIST); - int ul_pdcch_pdu_id=find_nr_ul_dci(frame,slot,gNB,SEARCH_EXIST); + int num_dl_dci = msgTx->pdcch_pdu.pdcch_pdu_rel15.numDlDci; + int num_ul_dci = msgTx->ul_pdcch_pdu.pdcch_pdu.pdcch_pdu_rel15.numDlDci; - LOG_D(PHY,"[gNB %d] Frame %d slot %d, pdcch_pdu_id %d, ul_pdcch_pdu_id %d\n", - gNB->Mod_id,frame,slot,pdcch_pdu_id,ul_pdcch_pdu_id); - - if (pdcch_pdu_id >= 0 || ul_pdcch_pdu_id >= 0) { + if (num_dl_dci > 0 || num_ul_dci > 0) { LOG_D(PHY, "[gNB %d] Frame %d slot %d Calling nr_generate_dci_top (number of UL/DL DCI %d/%d)\n", - gNB->Mod_id, frame, slot, - gNB->ul_pdcch_pdu[ul_pdcch_pdu_id].pdcch_pdu.pdcch_pdu.pdcch_pdu_rel15.numDlDci, - gNB->pdcch_pdu[pdcch_pdu_id].pdcch_pdu.pdcch_pdu_rel15.numDlDci); + gNB->Mod_id, frame, slot, num_ul_dci, num_dl_dci); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_PDCCH_TX,1); nr_generate_dci_top(gNB, - pdcch_pdu_id>=0 ? &gNB->pdcch_pdu[pdcch_pdu_id].pdcch_pdu : NULL, - ul_pdcch_pdu_id>=0 ? &gNB->ul_pdcch_pdu[ul_pdcch_pdu_id].pdcch_pdu.pdcch_pdu : NULL, + num_dl_dci > 0 ? &msgTx->pdcch_pdu : NULL, + num_ul_dci > 0 ? &msgTx->ul_pdcch_pdu.pdcch_pdu : NULL, gNB->nr_gold_pdcch_dmrs[slot], &gNB->common_vars.txdataF[0][txdataF_offset], AMP, fp); - // free up entry in pdcch tables - if (pdcch_pdu_id>=0) gNB->pdcch_pdu[pdcch_pdu_id].frame = -1; - if (ul_pdcch_pdu_id>=0) gNB->ul_pdcch_pdu[ul_pdcch_pdu_id].frame = -1; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_PDCCH_TX,0); - if (pdcch_pdu_id >= 0) gNB->pdcch_pdu[pdcch_pdu_id].frame = -1; - if (ul_pdcch_pdu_id >= 0) gNB->ul_pdcch_pdu[ul_pdcch_pdu_id].frame = -1; } - for (int i=0; inum_pdsch_rnti[slot]; i++) { + if (msgTx->num_pdsch_slot > 0) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,1); - LOG_D(PHY, "PDSCH generation started (%d) in frame %d.%d\n", gNB->num_pdsch_rnti[slot],frame,slot); - nr_generate_pdsch(gNB,frame, slot); + LOG_D(PHY, "PDSCH generation started (%d) in frame %d.%d\n", msgTx->num_pdsch_slot,frame,slot); + nr_generate_pdsch(msgTx, frame, slot); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,0); } for (int i=0;icsirs_pdu[i]; - if ((csirs->active == 1) && - (csirs->frame == frame) && - (csirs->slot == slot) ) { + NR_gNB_CSIRS_t *csirs = &msgTx->csirs_pdu[i]; + if ((csirs->active == 1)) { LOG_D(PHY, "CSI-RS generation started in frame %d.%d\n",frame,slot); nfapi_nr_dl_tti_csi_rs_pdu_rel15_t csi_params = csirs->csirs_pdu.csi_rs_pdu_rel15; nr_generate_csi_rs(gNB, AMP, csi_params, gNB->gNB_config.cell_config.phy_cell_id.value, slot); @@ -206,9 +194,9 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, } } - if (do_meas==1) stop_meas(&gNB->phy_proc_tx); + if (do_meas==1) stop_meas(&msgTx->phy_proc_tx); - if ((frame&127) == 0) dump_pdsch_stats(gNB); +// if ((frame&127) == 0) dump_pdsch_stats(gNB); //apply the OFDM symbol rotation here for (aa=0; aacarrier_config.num_tx_ant.value; aa++) { @@ -234,6 +222,7 @@ void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req) { NR_UL_gNB_HARQ_t *ulsch_harq = rdata->ulsch_harq; NR_gNB_ULSCH_t *ulsch = rdata->ulsch; int r = rdata->segment_r; + nfapi_nr_pusch_pdu_t *pusch_pdu = &gNB->ulsch[rdata->ulsch_id][0]->harq_processes[rdata->harq_pid]->ulsch_pdu; bool decodeSuccess = (rdata->decodeIterations <= rdata->decoderParms.numMaxIter); ulsch_harq->processedSegments++; @@ -260,21 +249,30 @@ void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req) { } } - // if all segments are done + //int dumpsig=0; + // if all segments are done if (rdata->nbSegments == ulsch_harq->processedSegments) { if (decodeSuccess) { - LOG_D(PHY,"[gNB %d] ULSCH: Setting ACK for slot %d TBS %d\n", - gNB->Mod_id,ulsch_harq->slot,ulsch_harq->TBS); + LOG_D(PHY,"[gNB %d] ULSCH: Setting ACK for SFN/SF %d.%d (pid %d, ndi %d, status %d, round %d, TBS %d, Max interation (all seg) %d)\n", + gNB->Mod_id,ulsch_harq->frame,ulsch_harq->slot,rdata->harq_pid,pusch_pdu->pusch_data.new_data_indicator,ulsch_harq->status,ulsch_harq->round,ulsch_harq->TBS,rdata->decodeIterations); ulsch_harq->status = SCH_IDLE; ulsch_harq->round = 0; ulsch->harq_mask &= ~(1 << rdata->harq_pid); LOG_D(PHY, "ULSCH received ok \n"); - nr_fill_indication(gNB,ulsch_harq->frame, ulsch_harq->slot, rdata->ulsch_id, rdata->harq_pid, 0); + nr_fill_indication(gNB,ulsch_harq->frame, ulsch_harq->slot, rdata->ulsch_id, rdata->harq_pid, 0,0); + //dumpsig=1; } else { - LOG_D(PHY,"[gNB %d] ULSCH: Setting NAK for SFN/SF %d/%d (pid %d, status %d, round %d, TBS %d) r %d\n", + LOG_I(PHY,"[gNB %d] ULSCH: Setting NAK for SFN/SF %d/%d (pid %d, ndi %d, status %d, round %d, RV %d, prb_start %d, prb_size %d, TBS %d) r %d\n", gNB->Mod_id, ulsch_harq->frame, ulsch_harq->slot, - rdata->harq_pid,ulsch_harq->status, ulsch_harq->round,ulsch_harq->TBS,r); + rdata->harq_pid, pusch_pdu->pusch_data.new_data_indicator, ulsch_harq->status, + ulsch_harq->round, + ulsch_harq->ulsch_pdu.pusch_data.rv_index, + ulsch_harq->ulsch_pdu.rb_start, + ulsch_harq->ulsch_pdu.rb_size, + ulsch_harq->TBS, + r); + ulsch_harq->round++; if (ulsch_harq->round >= ulsch->Mlimit) { ulsch_harq->status = SCH_IDLE; ulsch_harq->round = 0; @@ -284,8 +282,42 @@ void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req) { ulsch_harq->handled = 1; LOG_D(PHY, "ULSCH %d in error\n",rdata->ulsch_id); - nr_fill_indication(gNB,ulsch_harq->frame, ulsch_harq->slot, rdata->ulsch_id, rdata->harq_pid, 1); + nr_fill_indication(gNB,ulsch_harq->frame, ulsch_harq->slot, rdata->ulsch_id, rdata->harq_pid, 1,0); } +/* + if (ulsch_harq->ulsch_pdu.mcs_index == 9 && dumpsig==1) { +#ifdef __AVX2__ + int off = ((ulsch_harq->ulsch_pdu.rb_size&1) == 1)? 4:0; +#else + int off = 0; +#endif + + LOG_M("rxsigF0_ext.m","rxsF0_ext", + &gNB->pusch_vars[0]->rxdataF_ext[0][ulsch_harq->ulsch_pdu.start_symbol_index*NR_NB_SC_PER_RB * ulsch_harq->ulsch_pdu.rb_size],ulsch_harq->ulsch_pdu.nr_of_symbols*(off+(NR_NB_SC_PER_RB * ulsch_harq->ulsch_pdu.rb_size)),1,1); + LOG_M("chestF0.m","chF0", + &gNB->pusch_vars[0]->ul_ch_estimates[0][ulsch_harq->ulsch_pdu.start_symbol_index*gNB->frame_parms.ofdm_symbol_size],gNB->frame_parms.ofdm_symbol_size,1,1); + LOG_M("chestF0_ext.m","chF0_ext", + &gNB->pusch_vars[0]->ul_ch_estimates_ext[0][(ulsch_harq->ulsch_pdu.start_symbol_index+1)*(off+(NR_NB_SC_PER_RB * ulsch_harq->ulsch_pdu.rb_size))], + (ulsch_harq->ulsch_pdu.nr_of_symbols-1)*(off+(NR_NB_SC_PER_RB * ulsch_harq->ulsch_pdu.rb_size)),1,1); + LOG_M("rxsigF0_comp.m","rxsF0_comp", + &gNB->pusch_vars[0]->rxdataF_comp[0][ulsch_harq->ulsch_pdu.start_symbol_index*(off+(NR_NB_SC_PER_RB * ulsch_harq->ulsch_pdu.rb_size))],ulsch_harq->ulsch_pdu.nr_of_symbols*(off+(NR_NB_SC_PER_RB * ulsch_harq->ulsch_pdu.rb_size)),1,1); + LOG_M("rxsigF0_llr.m","rxsF0_llr", + &gNB->pusch_vars[0]->llr[0],(ulsch_harq->ulsch_pdu.nr_of_symbols-1)*NR_NB_SC_PER_RB * ulsch_harq->ulsch_pdu.rb_size * ulsch_harq->ulsch_pdu.qam_mod_order,1,0); + if (gNB->frame_parms.nb_antennas_rx > 1) { + + LOG_M("rxsigF1_ext.m","rxsF0_ext", + &gNB->pusch_vars[0]->rxdataF_ext[1][ulsch_harq->ulsch_pdu.start_symbol_index*NR_NB_SC_PER_RB * ulsch_harq->ulsch_pdu.rb_size],ulsch_harq->ulsch_pdu.nr_of_symbols*(off+(NR_NB_SC_PER_RB * ulsch_harq->ulsch_pdu.rb_size)),1,1); + LOG_M("chestF1.m","chF1", + &gNB->pusch_vars[0]->ul_ch_estimates[1][ulsch_harq->ulsch_pdu.start_symbol_index*gNB->frame_parms.ofdm_symbol_size],gNB->frame_parms.ofdm_symbol_size,1,1); + LOG_M("chestF1_ext.m","chF1_ext", + &gNB->pusch_vars[0]->ul_ch_estimates_ext[1][(ulsch_harq->ulsch_pdu.start_symbol_index+1)*(off+(NR_NB_SC_PER_RB * ulsch_harq->ulsch_pdu.rb_size))], + (ulsch_harq->ulsch_pdu.nr_of_symbols-1)*(off+(NR_NB_SC_PER_RB * ulsch_harq->ulsch_pdu.rb_size)),1,1); + LOG_M("rxsigF1_comp.m","rxsF1_comp", + &gNB->pusch_vars[0]->rxdataF_comp[1][ulsch_harq->ulsch_pdu.start_symbol_index*(off+(NR_NB_SC_PER_RB * ulsch_harq->ulsch_pdu.rb_size))],ulsch_harq->ulsch_pdu.nr_of_symbols*(off+(NR_NB_SC_PER_RB * ulsch_harq->ulsch_pdu.rb_size)),1,1); + } + exit(-1); + + } */ ulsch->last_iteration_cnt = rdata->decodeIterations; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_ULSCH_DECODING,0); } @@ -367,7 +399,7 @@ void nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH } - void nr_fill_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int ULSCH_id, uint8_t harq_pid, uint8_t crc_flag) { +void nr_fill_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int ULSCH_id, uint8_t harq_pid, uint8_t crc_flag, int dtx_flag) { pthread_mutex_lock(&gNB->UL_INFO_mutex); @@ -375,6 +407,7 @@ void nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH int sync_pos; NR_gNB_ULSCH_t *ulsch = gNB->ulsch[ULSCH_id][0]; NR_UL_gNB_HARQ_t *harq_process = ulsch->harq_processes[harq_pid]; + NR_gNB_SCH_STATS_t *stats=get_ulsch_stats(gNB,ulsch); nfapi_nr_pusch_pdu_t *pusch_pdu = &harq_process->ulsch_pdu; @@ -389,6 +422,8 @@ void nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH sync_pos_rounded = sync_pos + (bw_scaling / 2) - 1; else sync_pos_rounded = sync_pos - (bw_scaling / 2) - 1; + if (stats) stats->sync_pos = sync_pos; + timing_advance_update = sync_pos_rounded / bw_scaling; // put timing advance command in 0..63 range @@ -397,8 +432,16 @@ void nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH if (timing_advance_update < 0) timing_advance_update = 0; if (timing_advance_update > 63) timing_advance_update = 63; - LOG_D(PHY, "Estimated timing advance PUSCH is = %d, timing_advance_update is %d \n", sync_pos,timing_advance_update); - + if (crc_flag == 0) LOG_D(PHY, "%d.%d : Received PUSCH : Estimated timing advance PUSCH is = %d, timing_advance_update is %d \n", frame,slot_rx,sync_pos,timing_advance_update); + else if (harq_process->round>0 || dtx_flag == 0) { // increment round if crc_flag == 1 and not(dtx_flag ==1 and round==0) + harq_process->round++; + if (harq_process->round >= ulsch->Mlimit) { + harq_process->status = SCH_IDLE; + harq_process->round = 0; + harq_process->handled = 0; + ulsch->harq_mask &= ~(1 << harq_pid); + } + } // estimate UL_CQI for MAC int SNRtimes10 = dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_power_tot) - @@ -410,6 +453,41 @@ void nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH else if (SNRtimes10 > 635) cqi=255; else cqi=(640+SNRtimes10)/5; + + if (0/*pusch_pdu->mcs_index == 9*/) { +#ifdef __AVX2__ + int off = ((pusch_pdu->rb_size&1) == 1)? 4:0; +#else + int off = 0; +#endif + LOG_M("rxsigF0.m","rxsF0",&gNB->common_vars.rxdataF[0][(slot_rx&3)*gNB->frame_parms.ofdm_symbol_size*gNB->frame_parms.symbols_per_slot],gNB->frame_parms.ofdm_symbol_size*gNB->frame_parms.symbols_per_slot,1,1); + LOG_M("rxsigF0_ext.m","rxsF0_ext", + &gNB->pusch_vars[0]->rxdataF_ext[0][pusch_pdu->start_symbol_index*NR_NB_SC_PER_RB * pusch_pdu->rb_size],pusch_pdu->nr_of_symbols*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("chestF0.m","chF0", + &gNB->pusch_vars[0]->ul_ch_estimates[0][pusch_pdu->start_symbol_index*gNB->frame_parms.ofdm_symbol_size],gNB->frame_parms.ofdm_symbol_size,1,1); + LOG_M("chestF0_ext.m","chF0_ext", + &gNB->pusch_vars[0]->ul_ch_estimates_ext[0][(pusch_pdu->start_symbol_index+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], + (pusch_pdu->nr_of_symbols-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("rxsigF0_comp.m","rxsF0_comp", + &gNB->pusch_vars[0]->rxdataF_comp[0][pusch_pdu->start_symbol_index*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],pusch_pdu->nr_of_symbols*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("rxsigF0_llr.m","rxsF0_llr", + &gNB->pusch_vars[0]->llr[0],(pusch_pdu->nr_of_symbols-1)*NR_NB_SC_PER_RB *pusch_pdu->rb_size * pusch_pdu->qam_mod_order,1,0); + if (gNB->frame_parms.nb_antennas_rx > 1) { + LOG_M("rxsigF1.m","rxsF1",&gNB->common_vars.rxdataF[1][(slot_rx&3)*gNB->frame_parms.ofdm_symbol_size*gNB->frame_parms.symbols_per_slot],gNB->frame_parms.ofdm_symbol_size*gNB->frame_parms.symbols_per_slot,1,1); + LOG_M("rxsigF1_ext.m","rxsF1_ext", + &gNB->pusch_vars[0]->rxdataF_ext[1][pusch_pdu->start_symbol_index*NR_NB_SC_PER_RB * pusch_pdu->rb_size],pusch_pdu->nr_of_symbols*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("chestF1.m","chF1", + &gNB->pusch_vars[0]->ul_ch_estimates[1][pusch_pdu->start_symbol_index*gNB->frame_parms.ofdm_symbol_size],gNB->frame_parms.ofdm_symbol_size,1,1); + LOG_M("chestF1_ext.m","chF1_ext", + &gNB->pusch_vars[0]->ul_ch_estimates_ext[1][(pusch_pdu->start_symbol_index+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], + (pusch_pdu->nr_of_symbols-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("rxsigF1_comp.m","rxsF1_comp", + &gNB->pusch_vars[0]->rxdataF_comp[1][pusch_pdu->start_symbol_index*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],pusch_pdu->nr_of_symbols*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + } + exit(-1); + + } + // crc indication uint16_t num_crc = gNB->UL_INFO.crc_ind.number_crcs; gNB->UL_INFO.crc_ind.crc_list = &gNB->crc_pdu_list[0]; @@ -424,7 +502,7 @@ void nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH gNB->crc_pdu_list[num_crc].ul_cqi = cqi; gNB->crc_pdu_list[num_crc].timing_advance = timing_advance_update; // in terms of dBFS range -128 to 0 with 0.1 step - gNB->crc_pdu_list[num_crc].rssi = 1280 - (10*dB_fixed(32767*32767)-dB_fixed_times10(gNB->pusch_vars[ULSCH_id]->ulsch_power[0])); + gNB->crc_pdu_list[num_crc].rssi = (dtx_flag==0) ? 1280 - (10*dB_fixed(32767*32767)-dB_fixed_times10(gNB->pusch_vars[ULSCH_id]->ulsch_power[0])) : 0; gNB->UL_INFO.crc_ind.number_crcs++; @@ -438,7 +516,7 @@ void nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH gNB->rx_pdu_list[num_rx].harq_id = harq_pid; gNB->rx_pdu_list[num_rx].ul_cqi = cqi; gNB->rx_pdu_list[num_rx].timing_advance = timing_advance_update; - gNB->rx_pdu_list[num_rx].rssi = 1280 - (10*dB_fixed(32767*32767)-dB_fixed_times10(gNB->pusch_vars[ULSCH_id]->ulsch_power[0])); + gNB->rx_pdu_list[num_rx].rssi = gNB->crc_pdu_list[num_crc].rssi; if (crc_flag) gNB->rx_pdu_list[num_rx].pdu_length = 0; else { @@ -454,66 +532,74 @@ void nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH // Function to fill UL RB mask to be used for N0 measurements void fill_ul_rb_mask(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { - int rb2, rb, nb_rb; + int rb = 0; + int rb2 = 0; + int prbpos = 0; + for (int symbol=0;symbol<14;symbol++) { - if (gNB->gNB_config.tdd_table.max_tdd_periodicity_list[slot_rx].max_num_of_symbol_per_slot_list[symbol].slot_config.value==1){ - nb_rb = 0; - for (int m=0;m<9;m++) gNB->rb_mask_ul[m] = 0; - gNB->ulmask_symb = -1; - - for (int i=0;ipucch[i]; - if (pucch) { - if ((pucch->active == 1) && - (pucch->frame == frame_rx) && - (pucch->slot == slot_rx) ) { - gNB->ulmask_symb = symbol; - nfapi_nr_pucch_pdu_t *pucch_pdu = &pucch->pucch_pdu; - if ((symbol>=pucch_pdu->start_symbol_index) && - (symbol<(pucch_pdu->start_symbol_index + pucch_pdu->nr_of_symbols))){ - for (rb=0; rbprb_size; rb++) { - rb2 = rb+pucch_pdu->prb_start+pucch_pdu->bwp_start; - gNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31)); - } - nb_rb+=pucch_pdu->prb_size; - } - } - } + for (int m=0;m<9;m++) { + gNB->rb_mask_ul[symbol][m] = 0; + for (int i=0;i<32;i++) { + prbpos = (m*32)+i; + if (prbpos>gNB->frame_parms.N_RB_UL) break; + gNB->rb_mask_ul[symbol][m] |= (gNB->ulprbbl[prbpos]>0 ? 1 : 0)<number_of_nr_ulsch_max;ULSCH_id++) { - NR_gNB_ULSCH_t *ulsch = gNB->ulsch[ULSCH_id][0]; - int harq_pid; - NR_UL_gNB_HARQ_t *ulsch_harq; - - if ((ulsch) && - (ulsch->rnti > 0)) { - for (harq_pid=0;harq_pidharq_processes[harq_pid]; - AssertFatal(ulsch_harq!=NULL,"harq_pid %d is not allocated\n",harq_pid); - if ((ulsch_harq->status == NR_ACTIVE) && - (ulsch_harq->frame == frame_rx) && - (ulsch_harq->slot == slot_rx) && - (ulsch_harq->handled == 0)){ - uint8_t symbol_start = ulsch_harq->ulsch_pdu.start_symbol_index; - uint8_t symbol_end = symbol_start + ulsch_harq->ulsch_pdu.nr_of_symbols; - gNB->ulmask_symb = symbol; - if ((symbol>=symbol_start) && - (symbolulsch_pdu.rb_size; rb++) { - rb2 = rb+ulsch_harq->ulsch_pdu.rb_start+ulsch_harq->ulsch_pdu.bwp_start; - gNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31)); - } - nb_rb+=ulsch_harq->ulsch_pdu.rb_size; - } - } - } - } - //TODO Add check for PRACH as well? - } - if (nb_rbframe_parms.N_RB_UL) - return; } } + + for (int i=0;ipucch[i]; + if (pucch) { + if ((pucch->active == 1) && + (pucch->frame == frame_rx) && + (pucch->slot == slot_rx) ) { + nfapi_nr_pucch_pdu_t *pucch_pdu = &pucch->pucch_pdu; + LOG_D(PHY,"%d.%d pucch %d : start_symbol %d, nb_symbols %d, prb_size %d\n",frame_rx,slot_rx,i,pucch_pdu->start_symbol_index,pucch_pdu->nr_of_symbols,pucch_pdu->prb_size); + for (int symbol=pucch_pdu->start_symbol_index ; symbol<(pucch_pdu->start_symbol_index+pucch_pdu->nr_of_symbols);symbol++) { + if(gNB->frame_parms.frame_type == FDD || + (gNB->frame_parms.frame_type == TDD && gNB->gNB_config.tdd_table.max_tdd_periodicity_list[slot_rx].max_num_of_symbol_per_slot_list[symbol].slot_config.value==1)) { + for (rb=0; rbprb_size; rb++) { + rb2 = rb + pucch_pdu->bwp_start + + ((symbol < pucch_pdu->start_symbol_index+(pucch_pdu->nr_of_symbols>>1)) || (pucch_pdu->freq_hop_flag == 0) ? + pucch_pdu->prb_start : pucch_pdu->second_hop_prb); + gNB->rb_mask_ul[symbol][rb2>>5] |= (1<<(rb2&31)); + } + } + } + } + } + } + + for (int ULSCH_id=0;ULSCH_idnumber_of_nr_ulsch_max;ULSCH_id++) { + NR_gNB_ULSCH_t *ulsch = gNB->ulsch[ULSCH_id][0]; + int harq_pid; + NR_UL_gNB_HARQ_t *ulsch_harq; + if ((ulsch) && + (ulsch->rnti > 0)) { + for (harq_pid=0;harq_pidharq_processes[harq_pid]; + AssertFatal(ulsch_harq!=NULL,"harq_pid %d is not allocated\n",harq_pid); + if ((ulsch_harq->status == NR_ACTIVE) && + (ulsch_harq->frame == frame_rx) && + (ulsch_harq->slot == slot_rx) && + (ulsch_harq->handled == 0)){ + uint8_t symbol_start = ulsch_harq->ulsch_pdu.start_symbol_index; + uint8_t symbol_end = symbol_start + ulsch_harq->ulsch_pdu.nr_of_symbols; + for (int symbol=symbol_start ; symbolframe_parms.frame_type == FDD || + (gNB->frame_parms.frame_type == TDD && gNB->gNB_config.tdd_table.max_tdd_periodicity_list[slot_rx].max_num_of_symbol_per_slot_list[symbol].slot_config.value==1)) { + LOG_D(PHY,"symbol %d Filling rb_mask_ul rb_size %d\n",symbol,ulsch_harq->ulsch_pdu.rb_size); + for (rb=0; rbulsch_pdu.rb_size; rb++) { + rb2 = rb+ulsch_harq->ulsch_pdu.rb_start+ulsch_harq->ulsch_pdu.bwp_start; + gNB->rb_mask_ul[symbol][rb2>>5] |= (1<<(rb2&31)); + } + } + } + } + } + } + } + } void phy_procedures_gNB_common_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { @@ -551,8 +637,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_UESPEC_RX,1); LOG_D(PHY,"phy_procedures_gNB_uespec_RX frame %d, slot %d\n",frame_rx,slot_rx); - if (gNB->frame_parms.frame_type == TDD) - fill_ul_rb_mask(gNB, frame_rx, slot_rx); + fill_ul_rb_mask(gNB, frame_rx, slot_rx); int first_symb=0,num_symb=0; if (gNB->frame_parms.frame_type == TDD) @@ -563,7 +648,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { } } else num_symb=NR_NUMBER_OF_SYMBOLS_PER_SLOT; - gNB_I0_measurements(gNB,first_symb,num_symb); + gNB_I0_measurements(gNB,slot_rx,first_symb,num_symb); int offset = 10*gNB->frame_parms.ofdm_symbol_size + gNB->frame_parms.first_carrier_offset; int power_rxF = signal_energy_nodc(&gNB->common_vars.rxdataF[0][offset+(47*12)],12*18); @@ -683,7 +768,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { no_sig = nr_rx_pusch(gNB, ULSCH_id, frame_rx, slot_rx, harq_pid); if (no_sig) { LOG_D(PHY, "PUSCH not detected in frame %d, slot %d\n", frame_rx, slot_rx); - nr_fill_indication(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid, 1); + nr_fill_indication(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid, 1,1); return 1; } gNB->pusch_vars[ULSCH_id]->ulsch_power_tot=0; @@ -702,7 +787,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_power_tot), dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot),gNB->pusch_thres); gNB->pusch_vars[ULSCH_id]->ulsch_power_tot = gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot; - nr_fill_indication(gNB,frame_rx, slot_rx, ULSCH_id, harq_pid, 1); + nr_fill_indication(gNB,frame_rx, slot_rx, ULSCH_id, harq_pid, 1,1); gNB->pusch_vars[ULSCH_id]->DTX=1; if (stats) stats->DTX++; return 1; @@ -723,7 +808,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { stop_meas(&gNB->phy_proc_rx); // figure out a better way to choose slot_rx, 19 is ok for a particular TDD configuration with 30kHz SCS if ((frame_rx&127) == 0 && slot_rx==19) { - LOG_I(PHY, "Number of bad PUCCH received: %lu\n", gNB->bad_pucch); + LOG_I(NR_PHY, "Number of bad PUCCH received: %lu\n", gNB->bad_pucch); } if (pucch_decode_done || pusch_decode_done) { diff --git a/openair1/SCHED_NR/sched_nr.h b/openair1/SCHED_NR/sched_nr.h index 5e31c08d38..d7e0332b85 100644 --- a/openair1/SCHED_NR/sched_nr.h +++ b/openair1/SCHED_NR/sched_nr.h @@ -36,7 +36,7 @@ void fill_ul_rb_mask(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx); void nr_set_ssb_first_subcarrier(nfapi_nr_config_request_scf_t *cfg, NR_DL_FRAME_PARMS *fp); -void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, int frame_tx, int slot_tx, int do_meas); +void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, int frame_tx, int slot_tx, int do_meas); void phy_procedures_gNB_common_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx); int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx); void L1_nr_prach_procedures(PHY_VARS_gNB *gNB,int frame,int slot); diff --git a/openair1/SCHED_NR_UE/defs.h b/openair1/SCHED_NR_UE/defs.h index 5bde9502dc..b3527365a5 100644 --- a/openair1/SCHED_NR_UE/defs.h +++ b/openair1/SCHED_NR_UE/defs.h @@ -340,8 +340,6 @@ uint16_t nr_get_n1_pucch(PHY_VARS_NR_UE *phy_vars_ue, */ UE_MODE_t get_nrUE_mode(uint8_t Mod_id,uint8_t CC_id,uint8_t gNB_index); -uint8_t get_ra_PreambleIndex(uint8_t Mod_id, uint8_t CC_id, uint8_t gNB_id); - /*! \brief This function implements the power control mechanism for PUCCH from 36.213. @param phy_vars_ue PHY variables @param proc Pointer to proc descriptor diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 63935124a6..c9d8222e4c 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -52,7 +52,8 @@ #endif #include "executables/softmodem-common.h" #include "executables/nr-uesoftmodem.h" -#include "openair2/LAYER2/NR_MAC_UE/mac_proto.h" +#include "LAYER2/NR_MAC_UE/mac_proto.h" +#include "LAYER2/NR_MAC_UE/nr_l1_helpers.h" //#define DEBUG_PHY_PROC #define NR_PDCCH_SCHED @@ -64,8 +65,6 @@ #define PUCCH #endif -#include "LAYER2/NR_MAC_UE/mac_defs.h" -#include "LAYER2/NR_MAC_UE/mac_proto.h" #include "common/utils/LOG/log.h" #ifdef EMOS @@ -226,12 +225,6 @@ UE_MODE_t get_nrUE_mode(uint8_t Mod_id,uint8_t CC_id,uint8_t gNB_id){ return(PHY_vars_UE_g[Mod_id][CC_id]->UE_mode[gNB_id]); } -uint8_t get_ra_PreambleIndex(uint8_t Mod_id, uint8_t CC_id, uint8_t gNB_id){ - - return PHY_vars_UE_g[Mod_id][CC_id]->prach_resources[gNB_id]->ra_PreambleIndex; - -} - // convert time factor "16 * 64 * T_c / (2^mu)" in N_TA calculation in TS38.213 section 4.2 to samples by multiplying with samples per second // 16 * 64 * T_c / (2^mu) * samples_per_second // = 16 * T_s / (2^mu) * samples_per_second @@ -263,7 +256,7 @@ void ue_ta_procedures(PHY_VARS_NR_UE *ue, int slot_tx, int frame_tx){ ue->timing_advance += (ul_time_alignment->ta_command - 31) * bw_scaling; - LOG_I(PHY, "In %s: [UE %d] [%d.%d] Got timing advance command %u from MAC, new value is %d\n", + LOG_D(PHY, "In %s: [UE %d] [%d.%d] Got timing advance command %u from MAC, new value is %d\n", __FUNCTION__, ue->Mod_id, frame_tx, @@ -293,9 +286,8 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, LOG_D(PHY,"****** start TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx); -#if UE_TIMING_TRACE + start_meas(&ue->phy_proc_tx); -#endif if (ue->UE_mode[gNB_id] <= PUSCH){ @@ -307,9 +299,8 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX, VCD_FUNCTION_OUT); -#if UE_TIMING_TRACE stop_meas(&ue->phy_proc_tx); -#endif + } @@ -491,8 +482,8 @@ unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int N_RB_UL, int nb #ifdef NR_PDCCH_SCHED int nr_ue_pdcch_procedures(uint8_t gNB_id, - PHY_VARS_NR_UE *ue, - UE_nr_rxtx_proc_t *proc, + PHY_VARS_NR_UE *ue, + UE_nr_rxtx_proc_t *proc, int n_ss) { int frame_rx = proc->frame_rx; @@ -658,9 +649,7 @@ int nr_ue_pdcch_procedures(uint8_t gNB_id, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PDCCH_PROCEDURES, VCD_FUNCTION_IN); -#if UE_TIMING_TRACE - start_meas(&ue->dlsch_rx_pdcch_stats); -#endif + start_meas(&ue->dlsch_rx_pdcch_stats); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RX_PDCCH, VCD_FUNCTION_IN); #ifdef NR_PDCCH_SCHED_DEBUG @@ -760,9 +749,7 @@ int nr_ue_pdcch_procedures(uint8_t gNB_id, // send to mac ue->if_inst->dl_indication(&dl_indication, NULL); -#if UE_TIMING_TRACE stop_meas(&ue->dlsch_rx_pdcch_stats); -#endif VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PDCCH_PROCEDURES, VCD_FUNCTION_OUT); return(dci_cnt); @@ -844,12 +831,10 @@ int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, int gNB_ else first_symbol_flag = 0; -#if UE_TIMING_TRACE uint8_t slot = 0; if(m >= ue->frame_parms.symbols_per_slot>>1) slot = 1; start_meas(&ue->dlsch_llr_stats_parallelization[proc->thread_id][slot]); -#endif // process DLSCH received symbols in the slot // symbol by symbol processing (if data/DMRS are multiplexed is checked inside the function) if (pdsch == PDSCH || pdsch == SI_PDSCH || pdsch == RA_PDSCH) { @@ -868,13 +853,11 @@ int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, int gNB_ return -1; } else AssertFatal(1==0,"Not RA_PDSCH, SI_PDSCH or PDSCH\n"); -#if UE_TIMING_TRACE stop_meas(&ue->dlsch_llr_stats_parallelization[proc->thread_id][slot]); -#if DISABLE_LOG_X +#if PHYSIM printf("[AbsSFN %d.%d] LLR Computation Symbol %d %5.2f \n",frame_rx,nr_slot_rx,m,ue->dlsch_llr_stats_parallelization[proc->thread_id][slot].p_time/(cpuf*1000.0)); #else LOG_D(PHY, "[AbsSFN %d.%d] LLR Computation Symbol %d %5.2f \n",frame_rx,nr_slot_rx,m,ue->dlsch_llr_stats_parallelization[proc->thread_id][slot].p_time/(cpuf*1000.0)); -#endif #endif if(first_symbol_flag) { @@ -982,19 +965,17 @@ bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, dmrs_len, dlsch0->harq_processes[harq_pid]->Qm, dlsch0->harq_processes[harq_pid]->Nl); -#if UE_TIMING_TRACE - start_meas(&ue->dlsch_unscrambling_stats); -#endif - nr_dlsch_unscrambling(pdsch_vars->llr[0], - dlsch0->harq_processes[harq_pid]->G, - 0, - ue->frame_parms.Nid_cell, - dlsch0->rnti); + + start_meas(&ue->dlsch_unscrambling_stats); + nr_dlsch_unscrambling(pdsch_vars->llr[0], + dlsch0->harq_processes[harq_pid]->G, + 0, + ue->frame_parms.Nid_cell, + dlsch0->rnti); -#if UE_TIMING_TRACE - stop_meas(&ue->dlsch_unscrambling_stats); -#endif + stop_meas(&ue->dlsch_unscrambling_stats); + #if 0 LOG_I(PHY," ------ start ldpc decoder for AbsSubframe %d.%d / %d ------ \n", frame_rx, nr_slot_rx, harq_pid); @@ -1007,9 +988,8 @@ bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, LOG_I(PHY,"start ldpc decode for CW 0 for AbsSubframe %d.%d / %d --> Pdcch Sym %d \n", frame_rx, nr_slot_rx, harq_pid, ue->pdcch_vars[proc->thread_id][gNB_id]->num_pdcch_symbols); #endif -#if UE_TIMING_TRACE - start_meas(&ue->dlsch_decoding_stats[proc->thread_id]); -#endif + + start_meas(&ue->dlsch_decoding_stats[proc->thread_id]); if( dlsch_parallel) { ret = nr_dlsch_decoding_mthread(ue, @@ -1070,9 +1050,9 @@ bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, -#if UE_TIMING_TRACE - stop_meas(&ue->dlsch_decoding_stats[proc->thread_id]); -#if DISABLE_LOG_X + + stop_meas(&ue->dlsch_decoding_stats[proc->thread_id]); +#if PHYSIM printf(" --> Unscrambling for CW0 %5.3f\n", (ue->dlsch_unscrambling_stats.p_time)/(cpuf*1000.0)); printf("AbsSubframe %d.%d --> LDPC Decoding for CW0 %5.3f\n", @@ -1084,7 +1064,6 @@ bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, frame_rx%1024, nr_slot_rx,(ue->dlsch_decoding_stats[proc->thread_id].p_time)/(cpuf*1000.0)); #endif -#endif if(is_cw1_active) { // start ldpc decode for CW 1 dlsch1->harq_processes[harq_pid]->G = nr_get_G(dlsch1->harq_processes[harq_pid]->nb_rb, @@ -1093,17 +1072,13 @@ bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, dmrs_len, dlsch1->harq_processes[harq_pid]->Qm, dlsch1->harq_processes[harq_pid]->Nl); -#if UE_TIMING_TRACE start_meas(&ue->dlsch_unscrambling_stats); -#endif nr_dlsch_unscrambling(pdsch_vars->llr[1], dlsch1->harq_processes[harq_pid]->G, 0, ue->frame_parms.Nid_cell, dlsch1->rnti); -#if UE_TIMING_TRACE stop_meas(&ue->dlsch_unscrambling_stats); -#endif #if 0 LOG_I(PHY,"start ldpc decode for CW 1 for AbsSubframe %d.%d / %d --> nb_rb %d \n", frame_rx, nr_slot_rx, harq_pid, dlsch1->harq_processes[harq_pid]->nb_rb); @@ -1115,9 +1090,8 @@ bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, LOG_I(PHY,"start ldpc decode for CW 1 for AbsSubframe %d.%d / %d --> Pdcch Sym %d \n", frame_rx, nr_slot_rx, harq_pid, ue->pdcch_vars[proc->thread_id][gNB_id]->num_pdcch_symbols); #endif -#if UE_TIMING_TRACE start_meas(&ue->dlsch_decoding_stats[proc->thread_id]); -#endif + if(dlsch_parallel) { ret1 = nr_dlsch_decoding_mthread(ue, @@ -1152,9 +1126,9 @@ bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, LOG_T(PHY,"CWW sequential dlsch decoding, ret1 = %d\n", ret1); } -#if UE_TIMING_TRACE - stop_meas(&ue->dlsch_decoding_stats[proc->thread_id]); -#if DISABLE_LOG_X + + stop_meas(&ue->dlsch_decoding_stats[proc->thread_id]); +#if PHYSIM printf(" --> Unscrambling for CW1 %5.3f\n", (ue->dlsch_unscrambling_stats.p_time)/(cpuf*1000.0)); printf("AbsSubframe %d.%d --> ldpc Decoding for CW1 %5.3f\n", @@ -1166,7 +1140,7 @@ bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, frame_rx%1024, nr_slot_rx,(ue->dlsch_decoding_stats[proc->thread_id].p_time)/(cpuf*1000.0)); #endif -#endif + LOG_D(PHY,"AbsSubframe %d.%d --> ldpc Decoding for CW1 %5.3f\n", frame_rx%1024, nr_slot_rx,(ue->dlsch_decoding_stats[proc->thread_id].p_time)/(cpuf*1000.0)); @@ -1383,9 +1357,9 @@ void *UE_thread_slot1_dl_processing(void *arg) { } /**** Slot1 FE Processing ****/ -#if UE_TIMING_TRACE + start_meas(&ue->ue_front_end_per_slot_stat[proc->thread_id][1]); -#endif + // I- start dl slot1 processing // do first symbol of next downlink nr_slot_rx for channel estimation /* @@ -1410,9 +1384,8 @@ void *UE_thread_slot1_dl_processing(void *arg) { { //if( (l != pilot0) && (l != pilot1)) { -#if UE_TIMING_TRACE + start_meas(&ue->ofdm_demod_stats); -#endif VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP, VCD_FUNCTION_IN); //printf("AbsSubframe %d.%d FFT slot %d, symbol %d\n", frame_rx,nr_slot_rx,slot1,l); front_end_fft(ue, @@ -1421,9 +1394,7 @@ void *UE_thread_slot1_dl_processing(void *arg) { 0, 0); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP, VCD_FUNCTION_OUT); -#if UE_TIMING_TRACE stop_meas(&ue->ofdm_demod_stats); -#endif } } // for l=1..l2 @@ -1476,14 +1447,13 @@ void *UE_thread_slot1_dl_processing(void *arg) { //printf(" [slot1 dl processing] ==> Start LLR Comuptation slot1 for AbsSubframe %d.%d \n", proc->frame_rx, proc->nr_slot_rx); -#if UE_TIMING_TRACE + stop_meas(&ue->ue_front_end_per_slot_stat[proc->thread_id][1]); -#if DISABLE_LOG_X +#if PHYSIM printf("[AbsSFN %d.%d] Slot1: FFT + Channel Estimate + Pdsch Proc Slot0 %5.2f \n",frame_rx,nr_slot_rx,ue->ue_front_end_per_slot_stat[proc->thread_id][1].p_time/(cpuf*1000.0)); #else LOG_D(PHY, "[AbsSFN %d.%d] Slot1: FFT + Channel Estimate + Pdsch Proc Slot0 %5.2f \n",frame_rx,nr_slot_rx,ue->ue_front_end_per_slot_stat[proc->thread_id][1].p_time/(cpuf*1000.0)); #endif -#endif //wait until pdcch is decoded @@ -1501,9 +1471,8 @@ void *UE_thread_slot1_dl_processing(void *arg) { //printf("AbsSubframe %d.%d Pdsch Procedure (slot1)\n",frame_rx,nr_slot_rx); -#if UE_TIMING_TRACE start_meas(&ue->pdsch_procedures_per_slot_stat[proc->thread_id][1]); -#endif + // start slave thread for Pdsch Procedure (slot1) // do procedures for C-RNTI uint8_t gNB_id = 0; @@ -1573,13 +1542,11 @@ void *UE_thread_slot1_dl_processing(void *arg) { proc->llr_slot1_available=1; //printf("Set available LLR slot1 to 1 AbsSubframe %d.%d \n",frame_rx,nr_slot_rx); -#if UE_TIMING_TRACE stop_meas(&ue->pdsch_procedures_per_slot_stat[proc->thread_id][1]); -#if DISABLE_LOG_X +#if PHYSIM printf("[AbsSFN %d.%d] Slot1: LLR Computation %5.2f \n",frame_rx,nr_slot_rx,ue->pdsch_procedures_per_slot_stat[proc->thread_id][1].p_time/(cpuf*1000.0)); #else LOG_D(PHY, "[AbsSFN %d.%d] Slot1: LLR Computation %5.2f \n",frame_rx,nr_slot_rx,ue->pdsch_procedures_per_slot_stat[proc->thread_id][1].p_time/(cpuf*1000.0)); -#endif #endif if (pthread_mutex_lock(&proc->mutex_slot1_dl_processing) != 0) { @@ -1693,7 +1660,9 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_IN); - LOG_D(PHY," ****** start RX-Chain for Frame.Slot %d.%d ****** \n", frame_rx%1024, nr_slot_rx); + LOG_D(PHY," ****** start RX-Chain for Frame.Slot %d.%d (energy %d dB)****** \n", + frame_rx%1024, nr_slot_rx, + dB_fixed(signal_energy(ue->common_vars.common_vars_rx_data_per_thread[proc->thread_id].rxdataF[0],2048*14))); /* uint8_t next1_thread_id = proc->thread_id== (RX_NB_TH-1) ? 0:(proc->thread_id+1); @@ -1720,13 +1689,10 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue, (ue->symbol_offset+i)%(fp->symbols_per_slot), nr_slot_rx); -#if UE_TIMING_TRACE + start_meas(&ue->dlsch_channel_estimation_stats); -#endif nr_pbch_channel_estimation(ue,proc,gNB_id,nr_slot_rx,(ue->symbol_offset+i)%(fp->symbols_per_slot),i-1,(fp->ssb_index)&7,fp->half_frame_bit); -#if UE_TIMING_TRACE stop_meas(&ue->dlsch_channel_estimation_stats); -#endif } nr_ue_rsrp_measurements(ue, gNB_id, proc, nr_slot_rx, 0); @@ -1754,9 +1720,9 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue, } if ((frame_rx%64 == 0) && (nr_slot_rx==0)) { - LOG_I(PHY,"============================================\n"); - LOG_I(PHY,"Harq round stats for Downlink: %d/%d/%d/%d DLSCH errors: %d\n",ue->dl_stats[0],ue->dl_stats[1],ue->dl_stats[2],ue->dl_stats[3],ue->dl_stats[4]); - LOG_I(PHY,"============================================\n"); + LOG_I(NR_PHY,"============================================\n"); + LOG_I(NR_PHY,"Harq round stats for Downlink: %d/%d/%d/%d DLSCH errors: %d\n",ue->dl_stats[0],ue->dl_stats[1],ue->dl_stats[2],ue->dl_stats[3],ue->dl_stats[4]); + LOG_I(NR_PHY,"============================================\n"); } #ifdef NR_PDCCH_SCHED @@ -1766,9 +1732,7 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue, for (uint16_t l=0; lofdm_demod_stats); -#endif nr_slot_fep(ue, proc, l, @@ -1792,9 +1756,8 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue, fp->first_carrier_offset+(pdcch_vars->pdcch_config[n_ss].BWPStart + coreset_start_rb)*12, coreset_nb_rb); -#if UE_TIMING_TRACE stop_meas(&ue->ofdm_demod_stats); -#endif + } dci_cnt = dci_cnt + nr_ue_pdcch_procedures(gNB_id, ue, proc, n_ss); } @@ -1844,10 +1807,7 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue, curMsg->UE = ue; curMsg->ue_sched_mode = ONLY_PUSCH; pushTpool(&(get_nrUE_params()->Tpool), newElt); - -#if UE_TIMING_TRACE start_meas(&ue->generic_stat); -#endif // do procedures for C-RNTI int ret_pdsch = 0; if (ue->dlsch[proc->thread_id][gNB_id][0]->active == 1) { @@ -1944,9 +1904,7 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue, LOG_D(PHY, "DLSCH data reception at nr_slot_rx: %d \n \n", nr_slot_rx); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_IN); -#if UE_TIMING_TRACE start_meas(&ue->dlsch_procedures_stat[proc->thread_id]); -#endif if (ret_pdsch >= 0) nr_ue_dlsch_procedures(ue, @@ -1958,10 +1916,8 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue, &ue->dlsch_errors[gNB_id], dlsch_parallel); - -#if UE_TIMING_TRACE stop_meas(&ue->dlsch_procedures_stat[proc->thread_id]); -#if DISABLE_LOG_X +#if PHYSIM printf("[SFN %d] Slot1: Pdsch Proc %5.2f\n",nr_slot_rx,ue->pdsch_procedures_stat[proc->thread_id].p_time/(cpuf*1000.0)); printf("[SFN %d] Slot0 Slot1: Dlsch Proc %5.2f\n",nr_slot_rx,ue->dlsch_procedures_stat[proc->thread_id].p_time/(cpuf*1000.0)); #else @@ -1969,7 +1925,7 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue, LOG_D(PHY, "[SFN %d] Slot0 Slot1: Dlsch Proc %5.2f\n",nr_slot_rx,ue->dlsch_procedures_stat[proc->thread_id].p_time/(cpuf*1000.0)); #endif -#endif + // deactivate dlsch once dlsch proc is done ue->dlsch[proc->thread_id][gNB_id][0]->active = 0; @@ -1978,9 +1934,7 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue, } -#if UE_TIMING_TRACE start_meas(&ue->generic_stat); -#endif #if 0 @@ -2045,8 +1999,8 @@ if (nr_slot_rx==9) { } -#if UE_TIMING_TRACE stop_meas(&ue->generic_stat); +#if PHYSIM printf("after tubo until end of Rx %5.2f \n",ue->generic_stat.p_time/(cpuf*1000.0)); #endif @@ -2057,14 +2011,12 @@ phy_procedures_emos_UE_RX(ue,slot,gNB_id); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_OUT); -#if UE_TIMING_TRACE stop_meas(&ue->phy_proc_rx[proc->thread_id]); -#if DISABLE_LOG_X +#if PHYSIM printf("------FULL RX PROC [SFN %d]: %5.2f ------\n",nr_slot_rx,ue->phy_proc_rx[proc->thread_id].p_time/(cpuf*1000.0)); #else LOG_D(PHY, "------FULL RX PROC [SFN %d]: %5.2f ------\n",nr_slot_rx,ue->phy_proc_rx[proc->thread_id].p_time/(cpuf*1000.0)); #endif -#endif //#endif //pdsch diff --git a/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c b/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c index 2dbe6dcb9a..77ac105e14 100644 --- a/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c +++ b/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c @@ -38,7 +38,6 @@ #include "PHY/defs_nr_UE.h" #include #include -#include "openair2/LAYER2/NR_MAC_UE/mac_proto.h" #include "openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h" #include #include @@ -58,115 +57,6 @@ uint8_t nr_is_cqi_TXOp(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t gNB_id); uint8_t nr_is_ri_TXOp(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t gNB_id); -/* TS 36.213 Table 9.2.5.2-1: Code rate corresponding to higher layer parameter PUCCH-F2-maximum-coderate, */ -/* or PUCCH-F3-maximum-coderate, or PUCCH-F4-maximum-coderate */ -/* add one additional element set to 0 for parsing the array until this end */ -/* stored values are code rates * 100 */ -//static const int code_rate_r_time_100[8] = { (0.08 * 100), (0.15 * 100), (0.25*100), (0.35*100), (0.45*100), (0.60*100), (0.80*100), 0 } ; - -static float RSRP_meas_mapping_nr[98] -= { - -140, - -139, - -138, - -137, - -136, - -135, - -134, - -133, - -132, - -131, - -130, - -129, - -128, - -127, - -126, - -125, - -124, - -123, - -122, - -121, - -120, - -119, - -118, - -117, - -116, - -115, - -114, - -113, - -112, - -111, - -110, - -109, - -108, - -107, - -106, - -105, - -104, - -103, - -102, - -101, - -100, - -99, - -98, - -97, - -96, - -95, - -94, - -93, - -92, - -91, - -90, - -89, - -88, - -87, - -86, - -85, - -84, - -83, - -82, - -81, - -80, - -79, - -78, - -77, - -76, - -75, - -74, - -73, - -72, - -71, - -70, - -69, - -68, - -67, - -66, - -65, - -64, - -63, - -62, - -61, - -60, - -59, - -58, - -57, - -56, - -55, - -54, - -53, - -52, - -51, - -50, - -49, - -48, - -47, - -46, - -45, - -44, - -43 - } - ; - long binary_search_float_nr( float elements[], @@ -341,12 +231,14 @@ void pucch_procedures_ue_nr(PHY_VARS_NR_UE *ue, int tx_amp; + /* tx_amp = nr_get_tx_amp(pucch_tx_power, ue->tx_power_max_dBm, ue->frame_parms.N_RB_UL, nb_of_prbs); - if (tx_amp == 0) - tx_amp = AMP; + if (tx_amp == 0)*/ + // FIXME temporarly using fixed amplitude before pucch power control implementation revised + tx_amp = AMP; LOG_D(PHY,"Generation of PUCCH format %d at frame.slot %d.%d\n",pucch_pdu->format_type,proc->frame_tx,nr_slot_tx); @@ -392,187 +284,10 @@ void pucch_procedures_ue_nr(PHY_VARS_NR_UE *ue, } -/******************************************************************* -* -* NAME : check_pucch_format -* -* PARAMETERS : ue context -* processing slots of reception/transmission -* gNB_id identifier -* -* RETURN : harq process identifier -* -* DESCRIPTION : return tx harq process identifier for given transmission slot -* YS 38.213 9.2.2 PUCCH Formats for UCI transmission -* -*********************************************************************/ - -boolean_t check_pucch_format(NR_UE_MAC_INST_t *mac, uint8_t gNB_id, pucch_format_nr_t format_pucch, int nb_symbols_for_tx, int uci_size) -{ - pucch_format_nr_t selected_pucch_format; - pucch_format_nr_t selected_pucch_format_second; - /*NR_SetupRelease_PUCCH_FormatConfig_t *identified_format = NULL; - - switch (format_pucch) { - case pucch_format1_nr: - if (mac->ULbwp[bwp_id-1]->bwp_Dedicated->pucch_Config->choice.setup->format1 != NULL) - identified_format = mac->ULbwp[bwp_id-1]->bwp_Dedicated->pucch_Config->choice.setup->format1; - break; - - case pucch_format2_nr: - if (mac->ULbwp[bwp_id-1]->bwp_Dedicated->pucch_Config->choice.setup->format2 != NULL) - identified_format = mac->ULbwp[bwp_id-1]->bwp_Dedicated->pucch_Config->choice.setup->format2; - break; - - case pucch_format3_nr: - if (mac->ULbwp[bwp_id-1]->bwp_Dedicated->pucch_Config->choice.setup->format3 != NULL) - identified_format = mac->ULbwp[bwp_id-1]->bwp_Dedicated->pucch_Config->choice.setup->format3; - break; - - case pucch_format4_nr: - if (mac->ULbwp[bwp_id-1]->bwp_Dedicated->pucch_Config->choice.setup->format4 != NULL) - identified_format = mac->ULbwp[bwp_id-1]->bwp_Dedicated->pucch_Config->choice.setup->format4; - break; - - default: - break; - }*/ - - /* if ((identified_format != NULL) && (identified_format->choice.setup->nrofSlots[0] != 1)) { - LOG_E(PHY,"PUCCH not implemented multislots transmission : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); - return (FALSE); - }*/ - - if (nb_symbols_for_tx <= 2) { - if (uci_size <= 2) { - selected_pucch_format = pucch_format0_nr; - selected_pucch_format_second = selected_pucch_format; - } - else { - selected_pucch_format = pucch_format2_nr; - selected_pucch_format_second = selected_pucch_format; - } - } - else { - if (nb_symbols_for_tx >= 4) { - if (uci_size <= 2) { - selected_pucch_format = pucch_format1_nr; - selected_pucch_format_second = selected_pucch_format; - } - else { - selected_pucch_format = pucch_format3_nr; /* in this case choice can be done between two formats */ - selected_pucch_format_second = pucch_format4_nr; - } - } - else { - LOG_D(PHY,"PUCCH Undefined PUCCH format : set PUCCH to format 4 : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); - return (FALSE); - } - } - - NR_TST_PHY_PRINTF("PUCCH format %d nb symbols total %d uci size %d selected format %d \n", format_pucch, nb_symbols_for_tx, uci_size, selected_pucch_format); - - if (format_pucch != selected_pucch_format) { - if (format_pucch != selected_pucch_format_second) { - NR_TST_PHY_PRINTF("PUCCH mismatched of selected format: at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); - LOG_D(PHY,"PUCCH format mismatched of selected format: at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); - return (FALSE); - } - else { - return (TRUE); - } - } - else { - return (TRUE); - } -} - - - -/******************************************************************* -* -* NAME : get_csi_nr -* PARAMETERS : ue context -* processing slots of reception/transmission -* gNB_id identifier -* -* RETURN : size of csi payload -* -* DESCRIPTION : CSI management is not already implemented -* so it has been simulated thank to two functions: -* - set_csi_nr -* - get_csi_nr -* -*********************************************************************/ int dummy_csi_status = 0; uint32_t dummy_csi_payload = 0; -/* FFS TODO_NR code that should be developed */ - -uint16_t get_nr_csi_bitlen(NR_UE_MAC_INST_t *mac) { - - uint16_t csi_bitlen =0; - uint16_t rsrp_bitlen = 0; - uint16_t diff_rsrp_bitlen = 0; - uint16_t nb_ssbri_cri = 0; - uint16_t cri_ssbri_bitlen = 0; - - NR_CSI_MeasConfig_t *csi_MeasConfig = mac->cg->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup; - struct NR_CSI_ResourceConfig__csi_RS_ResourceSetList__nzp_CSI_RS_SSB * nzp_CSI_RS_SSB = csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[0]->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB; - - uint16_t nb_csi_ssb_report = nzp_CSI_RS_SSB->csi_SSB_ResourceSetList!=NULL ? nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.count:0; - - if (0 != nb_csi_ssb_report){ - uint8_t nb_ssb_resources =0; - - if (NULL != csi_MeasConfig->csi_ReportConfigToAddModList->list.array[0]->groupBasedBeamReporting.choice.disabled->nrofReportedRS) - nb_ssbri_cri = *(csi_MeasConfig->csi_ReportConfigToAddModList->list.array[0]->groupBasedBeamReporting.choice.disabled->nrofReportedRS)+1; - else - nb_ssbri_cri = 1; - - nb_ssb_resources = csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[0]->csi_SSB_ResourceList.list.count; - - if (nb_ssb_resources){ - cri_ssbri_bitlen =ceil(log2 (nb_ssb_resources)); - rsrp_bitlen = 7; - diff_rsrp_bitlen = 4; - } - else{ - cri_ssbri_bitlen =0; - rsrp_bitlen = 0; - diff_rsrp_bitlen = 0; - } - - csi_bitlen = ((cri_ssbri_bitlen * nb_ssbri_cri) + rsrp_bitlen +(diff_rsrp_bitlen *(nb_ssbri_cri -1 ))) *nb_csi_ssb_report; - - //printf("get csi bitlen %d nb_ssbri_cri %d nb_csi_report %d nb_resources %d\n", csi_bitlen,nb_ssbri_cri ,nb_csi_ssb_report, nb_ssb_resources); - } - return csi_bitlen; -} - -int get_csi_nr(NR_UE_MAC_INST_t *mac, PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint32_t *csi_payload) -{ - VOID_PARAMETER ue; - VOID_PARAMETER gNB_id; - float rsrp_db[7]; - int nElem = 98; - int rsrp_offset = 17; - int csi_status = 0; - - csi_status = get_nr_csi_bitlen(mac); - rsrp_db[0] = get_nr_RSRP(0,0,0); - - - if (csi_status == 0) { - *csi_payload = 0; - } - else { - *csi_payload = binary_search_float_nr(RSRP_meas_mapping_nr,nElem, rsrp_db[0]) + rsrp_offset; - } - - return (csi_status); -} /* FFS TODO_NR code that should be removed */ diff --git a/openair1/SCHED_NR_UE/pucch_uci_ue_nr.h b/openair1/SCHED_NR_UE/pucch_uci_ue_nr.h index 101b80fb8d..37e24f43bc 100644 --- a/openair1/SCHED_NR_UE/pucch_uci_ue_nr.h +++ b/openair1/SCHED_NR_UE/pucch_uci_ue_nr.h @@ -41,8 +41,6 @@ /************** INCLUDE *******************************************/ #include "PHY/defs_nr_UE.h" -#include "openair2/LAYER2/NR_MAC_UE/mac_proto.h" -#include "openair2/LAYER2/NR_MAC_UE/mac_defs.h" #include "RRC/NR_UE/rrc_proto.h" #ifdef DEFINE_VARIABLES_PUCCH_UE_NR_H @@ -65,31 +63,6 @@ void pucch_procedures_ue_nr(PHY_VARS_NR_UE *ue, uint8_t gNB_id, UE_nr_rxtx_proc_t *proc); -/** \brief This function check pucch format - @param ue context - @param gNB_id identity - @param format_pucch pucch format - @param nb_symbols_for_tx number of symbols for pucch transmission - @param uci size number of uci bits - @returns TRUE pucch format matched uci size and constraints, FALSE invalid pucch format */ - -boolean_t check_pucch_format(NR_UE_MAC_INST_t *mac, uint8_t gNB_id, pucch_format_nr_t format_pucch, int nb_symbols_for_tx, - int uci_size); - -/** \brief This function reads current CSI - @param ue context - @param gNB_id identity - @param csi_payload is updated with CSI - @returns number of bits of CSI */ - -int get_csi_nr(NR_UE_MAC_INST_t *mac, PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint32_t *csi_payload); - -/** \brief This dummy function sets current CSI for simulation - @param csi_status - @param csi_payload is updated with CSI - @returns none */ - -uint16_t get_nr_csi_bitlen(NR_UE_MAC_INST_t *mac); void set_csi_nr(int csi_status, uint32_t csi_payload); diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 3a34efbb93..833207a408 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -182,7 +182,7 @@ void DL_channel(RU_t *ru,PHY_VARS_UE *UE,uint subframe,int awgn_flag,double SNR, if (UE->perfect_ce==1) { // fill in perfect channel estimates - freq_channel(eNB2UE[round],UE->frame_parms.N_RB_DL,12*UE->frame_parms.N_RB_DL + 1); + freq_channel(eNB2UE[round],UE->frame_parms.N_RB_DL,12*UE->frame_parms.N_RB_DL + 1, 15); /* LOG_M("channel.m","ch",eNB2UE[round]->ch[0],eNB2UE[round]->channel_length,1,8); LOG_M("channelF.m","chF",eNB2UE[round]->chF[0],12*UE->frame_parms.N_RB_DL + 1,1,8); @@ -193,7 +193,7 @@ void DL_channel(RU_t *ru,PHY_VARS_UE *UE,uint subframe,int awgn_flag,double SNR, if(abstx) { if (trials==0 && round==0) { // calculate freq domain representation to compute SINR - freq_channel(eNB2UE[0], ru->frame_parms->N_RB_DL,2*ru->frame_parms->N_RB_DL + 1); + freq_channel(eNB2UE[0], ru->frame_parms->N_RB_DL,2*ru->frame_parms->N_RB_DL + 1, 15); // snr=pow(10.0,.1*SNR); fprintf(csv_fd,"%f,",SNR); @@ -208,7 +208,7 @@ void DL_channel(RU_t *ru,PHY_VARS_UE *UE,uint subframe,int awgn_flag,double SNR, } if(num_rounds>1) { - freq_channel(eNB2UE[1], ru->frame_parms->N_RB_DL,2*ru->frame_parms->N_RB_DL + 1); + freq_channel(eNB2UE[1], ru->frame_parms->N_RB_DL,2*ru->frame_parms->N_RB_DL + 1, 15); for (u=0; u<2*ru->frame_parms->N_RB_DL; u++) { for (aarx=0; aarxnb_rx; aarx++) { @@ -220,7 +220,7 @@ void DL_channel(RU_t *ru,PHY_VARS_UE *UE,uint subframe,int awgn_flag,double SNR, } } - freq_channel(eNB2UE[2], ru->frame_parms->N_RB_DL,2*ru->frame_parms->N_RB_DL + 1); + freq_channel(eNB2UE[2], ru->frame_parms->N_RB_DL,2*ru->frame_parms->N_RB_DL + 1, 15); for (u=0; u<2*ru->frame_parms->N_RB_DL; u++) { for (aarx=0; aarxnb_rx; aarx++) { @@ -232,7 +232,7 @@ void DL_channel(RU_t *ru,PHY_VARS_UE *UE,uint subframe,int awgn_flag,double SNR, } } - freq_channel(eNB2UE[3], ru->frame_parms->N_RB_DL,2*ru->frame_parms->N_RB_DL + 1); + freq_channel(eNB2UE[3], ru->frame_parms->N_RB_DL,2*ru->frame_parms->N_RB_DL + 1, 15); for (u=0; u<2*ru->frame_parms->N_RB_DL; u++) { for (aarx=0; aarxnb_rx; aarx++) { diff --git a/openair1/SIMULATION/LTE_PHY/mbmssim.c b/openair1/SIMULATION/LTE_PHY/mbmssim.c index 78fd1a293e..53c15ccc89 100644 --- a/openair1/SIMULATION/LTE_PHY/mbmssim.c +++ b/openair1/SIMULATION/LTE_PHY/mbmssim.c @@ -181,7 +181,7 @@ void DL_channel(RU_t *ru,PHY_VARS_UE *UE,uint subframe,int awgn_flag,double SNR, if (UE->perfect_ce==1) { // fill in perfect channel estimates - freq_channel(eNB2UE[round],UE->frame_parms.N_RB_DL,12*UE->frame_parms.N_RB_DL + 1); + freq_channel(eNB2UE[round],UE->frame_parms.N_RB_DL,12*UE->frame_parms.N_RB_DL + 1, 15); /* LOG_M("channel.m","ch",eNB2UE[round]->ch[0],eNB2UE[round]->channel_length,1,8); LOG_M("channelF.m","chF",eNB2UE[round]->chF[0],12*UE->frame_parms.N_RB_DL + 1,1,8); @@ -192,7 +192,7 @@ void DL_channel(RU_t *ru,PHY_VARS_UE *UE,uint subframe,int awgn_flag,double SNR, if(abstx) { if (trials==0 && round==0) { // calculate freq domain representation to compute SINR - freq_channel(eNB2UE[0], ru->frame_parms.N_RB_DL,2*ru->frame_parms.N_RB_DL + 1); + freq_channel(eNB2UE[0], ru->frame_parms.N_RB_DL,2*ru->frame_parms.N_RB_DL + 1, 15); // snr=pow(10.0,.1*SNR); fprintf(csv_fd,"%f,",SNR); @@ -207,7 +207,7 @@ void DL_channel(RU_t *ru,PHY_VARS_UE *UE,uint subframe,int awgn_flag,double SNR, } if(num_rounds>1) { - freq_channel(eNB2UE[1], ru->frame_parms.N_RB_DL,2*ru->frame_parms.N_RB_DL + 1); + freq_channel(eNB2UE[1], ru->frame_parms.N_RB_DL,2*ru->frame_parms.N_RB_DL + 1, 15); for (u=0; u<2*ru->frame_parms.N_RB_DL; u++) { for (aarx=0; aarxnb_rx; aarx++) { @@ -219,7 +219,7 @@ void DL_channel(RU_t *ru,PHY_VARS_UE *UE,uint subframe,int awgn_flag,double SNR, } } - freq_channel(eNB2UE[2], ru->frame_parms.N_RB_DL,2*ru->frame_parms.N_RB_DL + 1); + freq_channel(eNB2UE[2], ru->frame_parms.N_RB_DL,2*ru->frame_parms.N_RB_DL + 1, 15); for (u=0; u<2*ru->frame_parms.N_RB_DL; u++) { for (aarx=0; aarxnb_rx; aarx++) { @@ -231,7 +231,7 @@ void DL_channel(RU_t *ru,PHY_VARS_UE *UE,uint subframe,int awgn_flag,double SNR, } } - freq_channel(eNB2UE[3], ru->frame_parms.N_RB_DL,2*ru->frame_parms.N_RB_DL + 1); + freq_channel(eNB2UE[3], ru->frame_parms.N_RB_DL,2*ru->frame_parms.N_RB_DL + 1, 15); for (u=0; u<2*ru->frame_parms.N_RB_DL; u++) { for (aarx=0; aarxnb_rx; aarx++) { diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index 20a348f6c3..39593a640c 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -1102,7 +1102,7 @@ int main(int argc, char **argv) { if(saving_bler==0) if (trials==0 && round==0) { // calculate freq domain representation to compute SINR - freq_channel(UE2eNB, N_RB_DL,12*N_RB_DL + 1); + freq_channel(UE2eNB, N_RB_DL,12*N_RB_DL + 1, 15); // snr=pow(10.0,.1*SNR); fprintf(csv_fdUL,"%f,%u,%u,%f,%f,%f,",SNR,tx_lev,tx_lev_dB,sigma2_dB,tx_gain,SNR2); diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c index 633a214699..a0e0183fd1 100644 --- a/openair1/SIMULATION/NR_PHY/dlschsim.c +++ b/openair1/SIMULATION/NR_PHY/dlschsim.c @@ -426,7 +426,9 @@ int main(int argc, char **argv) UE->dlsch_SI[0] = new_nr_ue_dlsch(1, 1, Nsoft, 5, N_RB_DL, 0); UE->dlsch_ra[0] = new_nr_ue_dlsch(1, 1, Nsoft, 5, N_RB_DL, 0); unsigned char harq_pid = 0; //dlsch->harq_ids[subframe]; - NR_gNB_DLSCH_t *dlsch = gNB->dlsch[0][0]; + processingData_L1tx_t msgDataTx; + init_DLSCH_struct(gNB, &msgDataTx); + NR_gNB_DLSCH_t *dlsch = msgDataTx.dlsch[0][0]; nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->harq_process.pdsch_pdu.pdsch_pdu_rel15; //time_stats_t *rm_stats, *te_stats, *i_stats; uint8_t is_crnti = 0, llr8_flag = 0; @@ -634,7 +636,7 @@ int main(int argc, char **argv) for (i = 0; i < 2; i++) { printf("gNB %d\n", i); - free_gNB_dlsch(&(gNB->dlsch[0][i]),N_RB_DL); + free_gNB_dlsch(&(msgDataTx.dlsch[0][i]),N_RB_DL); printf("UE %d\n", i); free_nr_ue_dlsch(&(UE->dlsch[0][0][i]),N_RB_DL); } diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 9c81443e0f..16c6c94bbe 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -27,6 +27,7 @@ #include #include "common/ran_context.h" #include "common/config/config_userapi.h" +#include "common/utils/nr/nr_common.h" #include "common/utils/LOG/log.h" #include "LAYER2/NR_MAC_gNB/nr_mac_gNB.h" #include "LAYER2/NR_MAC_UE/mac_defs.h" @@ -263,19 +264,23 @@ void nr_dlsim_preprocessor(module_id_t module_id, uint8_t nr_of_candidates; find_aggregation_candidates(&sched_ctrl->aggregation_level, &nr_of_candidates, - sched_ctrl->search_space); - sched_ctrl->coreset = get_coreset(scc, sched_ctrl->active_bwp, sched_ctrl->search_space, target_ss); + sched_ctrl->search_space,4); + sched_ctrl->coreset = get_coreset(module_id, scc, sched_ctrl->active_bwp->bwp_Dedicated, sched_ctrl->search_space, target_ss); sched_ctrl->cce_index = 0; NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; ps->nrOfLayers = g_nrOfLayers; + int dci_format = sched_ctrl->search_space && sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats ? + NR_DL_DCI_FORMAT_1_1 : NR_DL_DCI_FORMAT_1_0; + nr_set_pdsch_semi_static(scc, UE_info->CellGroup[0], sched_ctrl->active_bwp, + NULL, /* tda = */ 2, - /* num_dmrs_cdm_grps_no_data = */ 1, + dci_format, ps); NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; @@ -427,7 +432,9 @@ int main(int argc, char **argv) FILE *scg_fd=NULL; - while ((c = getopt (argc, argv, "f:hA:pf:g:in:s:S:t:x:y:z:M:N:F:GR:dPIL:Ea:b:d:e:m:w:T:U:q")) != -1) { + + while ((c = getopt (argc, argv, "f:hA:pf:g:in:s:S:t:x:y:z:M:N:F:GR:dPIL:Ea:b:D:e:m:w:T:U:q")) != -1) { + switch (c) { case 'f': scg_fd = fopen(optarg,"r"); @@ -593,7 +600,7 @@ int main(int argc, char **argv) case 'b': g_rbSize = atoi(optarg); break; - case 'd': + case 'D': dlsch_threads = atoi(optarg); break; case 'e': @@ -666,7 +673,7 @@ int main(int argc, char **argv) printf("-U Change DMRS Config, arguments list DMRS TYPE{0=A,1=B} DMRS AddPos{0:2} DMRS ConfType{1:2}, e.g. -U 3 0 2 1 \n"); printf("-P Print DLSCH performances\n"); printf("-w Write txdata to binary file (one frame)\n"); - printf("-d number of dlsch threads, 0: no dlsch parallelization\n"); + printf("-D number of dlsch threads, 0: no dlsch parallelization\n"); exit (-1); break; } @@ -683,7 +690,7 @@ int main(int argc, char **argv) if (snr1set==0) snr1 = snr0+10; - init_dlsch_tpool(dlsch_threads); + RC.gNB = (PHY_VARS_gNB**) malloc(sizeof(PHY_VARS_gNB *)); @@ -782,9 +789,9 @@ int main(int argc, char **argv) AssertFatal((gNB->if_inst = NR_IF_Module_init(0))!=NULL,"Cannot register interface"); gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; // common configuration - rrc_mac_config_req_gNB(0,0, n_tx, n_tx, 0, scc, 0, 0, NULL); + rrc_mac_config_req_gNB(0,0, n_tx, n_tx, 0, scc, NULL, 0, 0, NULL); // UE dedicated configuration - rrc_mac_config_req_gNB(0,0, n_tx, n_tx, 0, scc, 1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); + rrc_mac_config_req_gNB(0,0, n_tx, n_tx, 0, scc, NULL, 1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); // reset preprocessor to the one of DLSIM after it has been set during // rrc_mac_config_req_gNB gNB_mac->pre_processor_dl = nr_dlsim_preprocessor; @@ -931,8 +938,6 @@ int main(int argc, char **argv) // generate signal AssertFatal(input_fd==NULL,"Not ready for input signal file\n"); gNB->pbch_configured = 1; - gNB->ssb[0].ssb_pdu.ssb_pdu_rel15.bchPayload=0x001234; - gNB->ssb[0].ssb_pdu.ssb_pdu_rel15.SsbBlockIndex = 0; //Configure UE rrc.carrier.MIB = (uint8_t*) malloc(4); @@ -962,11 +967,29 @@ int main(int argc, char **argv) //NR_COMMON_channels_t *cc = RC.nrmac[0]->common_channels; snrRun = 0; - + gNB->threadPool = (tpool_t*)malloc(sizeof(tpool_t)); + char tp_param[] = "n"; + initTpool(tp_param, gNB->threadPool, true); + gNB->resp_L1_tx = (notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t)); + initNotifiedFIFO(gNB->resp_L1_tx); + // we create 2 threads for L1 tx processing + notifiedFIFO_elt_t *msgL1Tx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t),0,gNB->resp_L1_tx,processSlotTX); + processingData_L1tx_t *msgDataTx = (processingData_L1tx_t *)NotifiedFifoData(msgL1Tx); + init_DLSCH_struct(gNB, msgDataTx); + msgDataTx->slot = slot; + msgDataTx->frame = frame; + memset(msgDataTx->ssb, 0, 64*sizeof(NR_gNB_SSB_t)); + reset_meas(&msgDataTx->phy_proc_tx); + gNB->phy_proc_tx_0 = &msgDataTx->phy_proc_tx; + pushTpool(gNB->threadPool,msgL1Tx); + if (dlsch_threads ) { + init_dlsch_tpool(dlsch_threads); + pthread_t dlsch0_threads; + threadCreate(&dlsch0_threads, dlsch_thread, (void *)UE, "DLthread", -1, OAI_PRIORITY_RT_MAX-1); + } for (SNR = snr0; SNR < snr1; SNR += .2) { varArray_t *table_tx=initVarArray(1000,sizeof(double)); - reset_meas(&gNB->phy_proc_tx); // total gNB tx reset_meas(&gNB->dlsch_scrambling_stats); reset_meas(&gNB->dlsch_interleaving_stats); reset_meas(&gNB->dlsch_rate_matching_stats); @@ -1007,7 +1030,7 @@ int main(int argc, char **argv) int harq_pid = slot; NR_DL_UE_HARQ_t *UE_harq_process = dlsch0->harq_processes[harq_pid]; - NR_gNB_DLSCH_t *gNB_dlsch = gNB->dlsch[0][0]; + NR_gNB_DLSCH_t *gNB_dlsch = msgDataTx->dlsch[0][0]; nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &gNB_dlsch->harq_process.pdsch_pdu.pdsch_pdu_rel15; UE_harq_process->ack = 0; @@ -1058,10 +1081,14 @@ int main(int argc, char **argv) ptrsRePerSymb = ((rel15->rbSize + rel15->PTRSFreqDensity - 1)/rel15->PTRSFreqDensity); printf("[DLSIM] PTRS Symbols in a slot: %2u, RE per Symbol: %3u, RE in a slot %4d\n", ptrsSymbPerSlot,ptrsRePerSymb, ptrsSymbPerSlot*ptrsRePerSymb ); } + + msgDataTx->ssb[0].ssb_pdu.ssb_pdu_rel15.bchPayload=0x001234; + msgDataTx->ssb[0].ssb_pdu.ssb_pdu_rel15.SsbBlockIndex = 0; + msgDataTx->gNB = gNB; if (run_initial_sync) - nr_common_signal_procedures(gNB,frame,slot,gNB->ssb[0].ssb_pdu); + nr_common_signal_procedures(gNB,frame,slot,msgDataTx->ssb[0].ssb_pdu); else - phy_procedures_gNB_TX(gNB,frame,slot,1); + phy_procedures_gNB_TX(msgDataTx,frame,slot,1); int txdataF_offset = (slot%2) * frame_parms->samples_per_slot_wCP; @@ -1263,17 +1290,17 @@ int main(int argc, char **argv) (float) n_errors / (float) n_trials); printf("*****************************************\n"); printf("\n"); - dump_pdsch_stats(gNB); + dump_pdsch_stats(stdout,gNB); printf("SNR %f : n_errors (negative CRC) = %d/%d, Avg round %.2f, Channel BER %e, BLER %.2f, Eff Rate %.4f bits/slot, Eff Throughput %.2f, TBS %u bits/slot\n", SNR, n_errors, n_trials,roundStats[snrRun],berStats[snrRun],blerStats[snrRun],effRate,effRate/TBS*100,TBS); printf("\n"); if (print_perf==1) { printf("\ngNB TX function statistics (per %d us slot, NPRB %d, mcs %d, TBS %d, Kr %d (Zc %d))\n", 1000>>*scc->ssbSubcarrierSpacing, g_rbSize, g_mcsIndex, - gNB->dlsch[0][0]->harq_process.pdsch_pdu.pdsch_pdu_rel15.TBSize[0]<<3, - gNB->dlsch[0][0]->harq_process.K, - gNB->dlsch[0][0]->harq_process.K/((gNB->dlsch[0][0]->harq_process.pdsch_pdu.pdsch_pdu_rel15.TBSize[0]<<3)>3824?22:10)); - printDistribution(&gNB->phy_proc_tx,table_tx,"PHY proc tx"); + msgDataTx->dlsch[0][0]->harq_process.pdsch_pdu.pdsch_pdu_rel15.TBSize[0]<<3, + msgDataTx->dlsch[0][0]->harq_process.K, + msgDataTx->dlsch[0][0]->harq_process.K/((msgDataTx->dlsch[0][0]->harq_process.pdsch_pdu.pdsch_pdu_rel15.TBSize[0]<<3)>3824?22:10)); + printDistribution(gNB->phy_proc_tx_0,table_tx,"PHY proc tx"); printStatIndent2(&gNB->dlsch_encoding_stats,"DLSCH encoding time"); printStatIndent3(&gNB->dlsch_segmentation_stats,"DLSCH segmentation time"); printStatIndent3(&gNB->tinput,"DLSCH LDPC input processing time"); @@ -1326,6 +1353,8 @@ int main(int argc, char **argv) LOG_M("chestF0.m","chF0",&UE->pdsch_vars[0][0]->dl_ch_estimates_ext[0][0],g_rbSize*12*14,1,1); write_output("rxF_comp.m","rxFc",&UE->pdsch_vars[0][0]->rxdataF_comp0[0][0],N_RB_DL*12*14,1,1); LOG_M("rxF_llr.m","rxFllr",UE->pdsch_vars[UE_proc.thread_id][0]->llr[0],available_bits,1,0); + LOG_M("pdcch_rxFcomp.m","pdcch_rxFcomp",&UE->pdcch_vars[0][0]->rxdataF_comp[0][0],96*12,1,1); + LOG_M("pdcch_rxFllr.m","pdcch_rxFllr",UE->pdcch_vars[0][0]->llr,96*12,1,1); break; } diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index 46b42666b5..1169b8ecd8 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -28,6 +28,7 @@ #include "common/config/config_userapi.h" #include "common/utils/LOG/log.h" #include "common/ran_context.h" +#include "common/utils/nr/nr_common.h" #include "PHY/types.h" #include "PHY/defs_nr_common.h" #include "PHY/defs_nr_UE.h" @@ -565,14 +566,15 @@ int main(int argc, char **argv) nr_gold_pbch(UE); + processingData_L1tx_t msgDataTx; // generate signal if (input_fd==NULL) { for (i=0; iLmax; i++) { if((SSB_positions >> i) & 0x01) { - gNB->ssb[i].ssb_pdu.ssb_pdu_rel15.bchPayload = 0x55dd33; - gNB->ssb[i].ssb_pdu.ssb_pdu_rel15.SsbBlockIndex = i; + msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.bchPayload = 0x55dd33; + msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.SsbBlockIndex = i; start_symbol = nr_get_ssb_start_symbol(frame_parms,i); int slot = start_symbol/14; @@ -580,7 +582,7 @@ int main(int argc, char **argv) for (aa=0; aaframe_parms.nb_antennas_tx; aa++) memset(gNB->common_vars.txdataF[aa],0,frame_parms->samples_per_slot_wCP*sizeof(int32_t)); - nr_common_signal_procedures (gNB,frame,slot,gNB->ssb[i].ssb_pdu); + nr_common_signal_procedures (gNB,frame,slot,msgDataTx.ssb[i].ssb_pdu); for (aa=0; aaframe_parms.nb_antennas_tx; aa++) { if (cyclic_prefix_type == 1) { @@ -750,7 +752,7 @@ int main(int argc, char **argv) payload_ret = (UE->pbch_vars[0]->xtra_byte == gNB_xtra_byte); for (i=0;i<3;i++){ - payload_ret += (UE->pbch_vars[0]->decoded_output[i] == ((gNB->ssb[ssb_index].ssb_pdu.ssb_pdu_rel15.bchPayload>>(8*i)) & 0xff)); + payload_ret += (UE->pbch_vars[0]->decoded_output[i] == ((msgDataTx.ssb[ssb_index].ssb_pdu.ssb_pdu_rel15.bchPayload>>(8*i)) & 0xff)); } //printf("xtra byte gNB: 0x%02x UE: 0x%02x\n",gNB_xtra_byte, UE->pbch_vars[0]->xtra_byte); //printf("ret %d\n", payload_ret); diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index 96f6fe4990..6b9512a38b 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -47,6 +47,7 @@ #include "nr_unitary_defs.h" #include "OCG_vars.h" #include +#include #include #include #include diff --git a/openair1/SIMULATION/NR_PHY/pucchsim.c b/openair1/SIMULATION/NR_PHY/pucchsim.c index a3eb4452d7..0aed6d9780 100644 --- a/openair1/SIMULATION/NR_PHY/pucchsim.c +++ b/openair1/SIMULATION/NR_PHY/pucchsim.c @@ -67,7 +67,7 @@ void init_downlink_harq_status(NR_DL_UE_HARQ_t *dl_harq) {} int main(int argc, char **argv) { char c; - int i,aa=0;//,l; + int i;//,l; double sigma2, sigma2_dB=10,SNR,snr0=-2.0,snr1=2.0; double cfo=0; uint8_t snr1set=0; @@ -104,7 +104,8 @@ int main(int argc, char **argv) SCM_t channel_model=AWGN;//Rayleigh1_anticorr; double DS_TDL = .03; - + + double delay_us = 0; int N_RB_DL=273,mu=1; float target_error_rate=0.001; int frame_length_complex_samples; @@ -113,7 +114,7 @@ int main(int argc, char **argv) //unsigned char frame_type = 0; int loglvl=OAILOG_WARNING; int sr_flag = 0; - + int pucch_DTX_thres = 50; cpuf = get_cpu_freq_GHz(); if ( load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY) == 0) { @@ -123,7 +124,7 @@ int main(int argc, char **argv) randominit(0); logInit(); - while ((c = getopt (argc, argv, "f:hA:f:g:i:I:P:B:b:T:m:n:r:o:s:S:x:y:z:N:F:GR:IL:q:c")) != -1) { + while ((c = getopt (argc, argv, "f:hA:f:g:i:I:P:B:b:t:T:m:n:r:o:s:S:x:y:z:N:F:GR:IL:q:cd:")) != -1) { switch (c) { case 'f': //write_output_file=1; @@ -207,11 +208,11 @@ int main(int argc, char **argv) printf("Setting SNR1 to %f\n",snr1); break; - /* + case 't': - Td= atof(optarg); + pucch_DTX_thres= atoi(optarg); break; - + /* case 'p': extended_prefix_flag=1; break; @@ -228,6 +229,9 @@ int main(int argc, char **argv) } break; */ + case 'd': + delay_us=atof(optarg); + break; case 'x': transmission_mode=atoi(optarg); @@ -251,7 +255,7 @@ int main(int argc, char **argv) case 'z': n_rx=atoi(optarg); - if ((n_rx==0) || (n_rx>2)) { + if ((n_rx==0) || (n_rx>8)) { printf("Unsupported number of rx antennas %d\n",n_rx); exit(-1); } @@ -346,29 +350,33 @@ int main(int argc, char **argv) } } + double phase = (1<2)&&(nr_bit<65)),"illegal combination format %d, nr_bit %d\n", format,nr_bit); + int do_DTX=0; + if ((format < 2) && (actual_payload == 4)) do_DTX=1; actual_payload &= ((1<pucch0_thres = pucch_DTX_thres; frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH) frame_parms->nb_antennas_tx = n_tx; frame_parms->nb_antennas_rx = n_rx; @@ -430,31 +438,28 @@ int main(int argc, char **argv) frame_length_complex_samples = frame_parms->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME; //frame_length_complex_samples_no_prefix = frame_parms->samples_per_subframe_wCP; - s_re = malloc(2*sizeof(double*)); - s_im = malloc(2*sizeof(double*)); - r_re = malloc(2*sizeof(double*)); - r_im = malloc(2*sizeof(double*)); - txdataF = malloc(2*sizeof(int*)); - rxdataF = malloc(2*sizeof(int*)); + s_re = malloc(n_tx*sizeof(double*)); + s_im = malloc(n_tx*sizeof(double*)); + r_re = malloc(n_rx*sizeof(double*)); + r_im = malloc(n_rx*sizeof(double*)); + txdataF = malloc(n_tx*sizeof(int*)); + rxdataF = malloc(n_rx*sizeof(int*)); gNB->common_vars.rxdataF=rxdataF; memcpy((void*)&gNB->frame_parms,(void*)frame_parms,sizeof(frame_parms)); - for (i=0; i<2; i++) { + for (int aatx=0; aatxsymbols_per_slot*frame_parms->ofdm_symbol_size); + txdataF[aatx] = memalign(32,14*frame_parms->ofdm_symbol_size*sizeof(int)); + bzero(txdataF[aatx],14*frame_parms->ofdm_symbol_size*sizeof(int)); + } - s_re[i] = malloc(frame_length_complex_samples*sizeof(double)); - bzero(s_re[i],frame_length_complex_samples*sizeof(double)); - s_im[i] = malloc(frame_length_complex_samples*sizeof(double)); - bzero(s_im[i],frame_length_complex_samples*sizeof(double)); - - r_re[i] = malloc(frame_length_complex_samples*sizeof(double)); - bzero(r_re[i],frame_length_complex_samples*sizeof(double)); - r_im[i] = malloc(frame_length_complex_samples*sizeof(double)); - bzero(r_im[i],frame_length_complex_samples*sizeof(double)); - - printf("Allocating %d samples for txdataF/rxdataF\n",14*frame_parms->ofdm_symbol_size); - txdataF[i] = memalign(32,14*frame_parms->ofdm_symbol_size*sizeof(int)); - bzero(txdataF[i],14*frame_parms->ofdm_symbol_size*sizeof(int)); - rxdataF[i] = memalign(32,14*frame_parms->ofdm_symbol_size*sizeof(int)); - bzero(rxdataF[i],14*frame_parms->ofdm_symbol_size*sizeof(int)); + for (int aarx=0; aarxsymbols_per_slot*frame_parms->ofdm_symbol_size); + rxdataF[aarx] = memalign(32,14*frame_parms->ofdm_symbol_size*sizeof(int)); + bzero(rxdataF[aarx],14*frame_parms->ofdm_symbol_size*sizeof(int)); } uint8_t mcs=0; @@ -471,14 +476,26 @@ int main(int argc, char **argv) else AssertFatal(1==0,"Either nr_bit %d or sr_flag %d must be non-zero\n", nr_bit, sr_flag); } else if (format == 2 && nr_bit > 11) gNB->uci_polarParams = nr_polar_params(2, nr_bit, nrofPRB, 1, NULL); - - startingPRB_intraSlotHopping=N_RB_DL-1; - uint32_t hopping_id=Nid_cell; - uint32_t dmrs_scrambling_id = 0, data_scrambling_id=0; + + startingPRB_intraSlotHopping = N_RB_DL-1; + uint32_t hopping_id = Nid_cell; + uint32_t dmrs_scrambling_id = 0; + uint32_t data_scrambling_id = 0; //configure UE - UE = malloc(sizeof(PHY_VARS_NR_UE)); + UE = calloc(1,sizeof(PHY_VARS_NR_UE)); memcpy(&UE->frame_parms,frame_parms,sizeof(NR_DL_FRAME_PARMS)); + UE->frame_parms.nb_antennas_rx=1; + UE->perfect_ce = 0; + + if(eps!=0.0) + UE->UE_fo_compensation = 1; // if a frequency offset is set then perform fo estimation and compensation + + if (init_nr_ue_signal(UE, 1, 0) != 0) + { + printf("Error at UE NR initialisation\n"); + exit(-1); + } fapi_nr_ul_config_pucch_pdu pucch_tx_pdu; if (format==0) { @@ -514,80 +531,112 @@ int main(int argc, char **argv) pucch_tx_pdu.second_hop_prb = startingPRB_intraSlotHopping; } - UE->perfect_ce = 0; - - if(eps!=0.0) - UE->UE_fo_compensation = 1; // if a frequency offset is set then perform fo estimation and compensation - - if (init_nr_ue_signal(UE, 1, 0) != 0) - { - printf("Error at UE NR initialisation\n"); - exit(-1); - } - pucch_GroupHopping_t PUCCH_GroupHopping = pucch_tx_pdu.group_hop_flag + (pucch_tx_pdu.sequence_hop_flag<<1); - //t_nrPolar_params *currentPtr; - - for(SNR=snr0;SNR<=snr1;SNR=SNR+1){ + for(SNR=snr0;SNR<=snr1;SNR+=1){ ack_nack_errors=0; sr_errors=0; n_errors = 0; for (trial=0; trialofdm_symbol_size*sizeof(int)); - if(format==0){ - nr_generate_pucch0(UE, - txdataF, - frame_parms, - amp, - nr_slot_tx, - &pucch_tx_pdu); + for (int aatx=0;aatx<1;aatx++) + bzero(txdataF[aatx],frame_parms->ofdm_symbol_size*sizeof(int)); + if(format==0 && do_DTX==0){ + nr_generate_pucch0(UE, txdataF, frame_parms, amp, nr_slot_tx, &pucch_tx_pdu); + } else if (format == 1 && do_DTX==0){ + nr_generate_pucch1(UE, txdataF, frame_parms, amp, nr_slot_tx, &pucch_tx_pdu); + } else if (do_DTX == 0){ + nr_generate_pucch2(UE, txdataF, frame_parms, amp, nr_slot_tx, &pucch_tx_pdu); } - else if (format == 1){ - nr_generate_pucch1(UE, - txdataF, - frame_parms, - amp, - nr_slot_tx, - &pucch_tx_pdu); - } - else { - nr_generate_pucch2(UE, - txdataF, - frame_parms, - amp, - nr_slot_tx, - &pucch_tx_pdu); - } - - int txlev = signal_energy(&txdataF[aa][startingSymbolIndex*frame_parms->ofdm_symbol_size], - frame_parms->ofdm_symbol_size); - // printf("txlev %d (%d dB), offset %d\n",txlev,dB_fixed(txlev),startingSymbolIndex*frame_parms->ofdm_symbol_size); - - // note : this scaling - int nb_re = (format == 0 || format == 1)? 12 : 12*nrofPRB; - sigma2_dB = 10*log10((double)txlev*UE->frame_parms.ofdm_symbol_size/nb_re)-SNR; - sigma2 = pow(10,sigma2_dB/10); - - for(i=startingSymbolIndex*frame_parms->ofdm_symbol_size; i<(startingSymbolIndex+1)*frame_parms->ofdm_symbol_size; i++) { - ((int16_t*)rxdataF[aa])[i<<1] = (int16_t)(100.0*((double)(((int16_t *)txdataF[aa])[(i<<1)]) + sqrt(sigma2/2)*gaussdouble(0.0,1.0))/sqrt((double)txlev)); - ((int16_t*)rxdataF[aa])[1+(i<<1)]=(int16_t)(100.0*((double)(((int16_t *)txdataF[aa])[(i<<1)+1])+ sqrt(sigma2/2)*gaussdouble(0.0,1.0))/sqrt((double)txlev)); - } - int rxlev = signal_energy(&rxdataF[aa][startingSymbolIndex*frame_parms->ofdm_symbol_size], - frame_parms->ofdm_symbol_size); - // noise measurement - gNB->ulmask_symb = startingSymbolIndex; - for (int rb=0; rbrb_mask_ul[rb2>>5] |= (1<<(rb2&31)); - } - gNB_I0_measurements(gNB, startingSymbolIndex, nrofSymbols); + // SNR Computation + // standard says: SNR = S / N, where S is the total signal energy, N is the noise energy in the transmission bandwidth (i.e. N_RB_DL resource blocks) + // txlev = S. + int txlev = signal_energy(&txdataF[0][startingSymbolIndex*frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size); - if (n_trials==1) printf("rxlev %d (%d dB), sigma2 %f dB, SNR %f, TX %f\n",rxlev,dB_fixed(rxlev),sigma2_dB,SNR,10*log10((double)txlev*UE->frame_parms.ofdm_symbol_size/12)); + // sigma2 is variance per dimension, so N/(N_RB*12) + // so, sigma2 = N/(N_RB_DL*12) => (S/SNR)/(N_RB*12) + int N_RB = (format == 0 || format == 1) ? 1 : nrofPRB; + sigma2_dB = 10*log10(txlev*(N_RB_DL/N_RB))-SNR; + sigma2 = pow(10.0,sigma2_dB/10.0); + + if (n_trials==1) printf("txlev %d (%f dB), offset %d, sigma2 %f ( %f dB)\n",txlev,10*log10(txlev),startingSymbolIndex*frame_parms->ofdm_symbol_size,sigma2,sigma2_dB); + + int i0; + double txr,txi,rxr,rxi,nr,ni; + for (int symb=0; symbframe_parms.symbols_per_slot;symb++) { + if (symb= startingSymbolIndex+nrofSymbols) { + i0 = symb*gNB->frame_parms.ofdm_symbol_size; + for (int re=0;reframe_parms.first_carrier_offset + re)%gNB->frame_parms.ofdm_symbol_size); + for (int aarx=0;aarxframe_parms.ofdm_symbol_size; + for (int re=0;reframe_parms.first_carrier_offset + re)%gNB->frame_parms.ofdm_symbol_size); + phasor.r = cos(2*M_PI*phase*re); + phasor.i = sin(2*M_PI*phase*re); + for (int aarx=0;aarxchF[aarx][re].r - txi*UE2gNB->chF[aarx][re].i; + rxi = txr*UE2gNB->chF[aarx][re].i + txi*UE2gNB->chF[aarx][re].r; + rxr_tmp = rxr*phasor.r - rxi*phasor.i; + rxi = rxr*phasor.i + rxi*phasor.r; + rxr = rxr_tmp; + nr = sqrt(sigma2/2)*gaussdouble(0.0,1.0); + ni = sqrt(sigma2/2)*gaussdouble(0.0,1.0); + ((int16_t*)rxdataF[aarx])[i<<1] = (int16_t)(100.0*(rxr + nr)/sqrt((double)txlev)); + ((int16_t*)rxdataF[aarx])[1+(i<<1)]=(int16_t)(100.0*(rxi + ni)/sqrt((double)txlev)); + + if (n_trials==1 && abs(txr) > 0) printf("symb %d, re %d , aarx %d : txr %f, txi %f, chr %f, chi %f, nr %f, ni %f, rxr %f, rxi %f => %d,%d\n", + symb, re, aarx, txr,txi, + UE2gNB->chF[aarx][re].r,UE2gNB->chF[aarx][re].i, + nr,ni, rxr,rxi, + ((int16_t*)rxdataF[aarx])[i<<1],((int16_t*)rxdataF[aarx])[1+(i<<1)]); + } + } + } + + int rxlev=0; + for (int aarx=0;aarxofdm_symbol_size], + frame_parms->ofdm_symbol_size); + + int rxlev_pucch=0; + + for (int aarx=0;aarxofdm_symbol_size], + 12); + + // set UL mask for pucch allocation + for (int s=0;ssymbols_per_slot;s++){ + if (s>=startingSymbolIndex && s<(startingSymbolIndex+nrofSymbols)) + for (int rb=0; rbrb_mask_ul[s][rb2>>5] |= (1<<(rb2&31)); + } + } + + // noise measurement (all PRBs) + gNB_I0_measurements(gNB, nr_slot_tx, 0, gNB->frame_parms.symbols_per_slot); + + if (n_trials==1) printf("noise rxlev %d (%d dB), rxlev pucch %d dB sigma2 %f dB, SNR %f, TX %f, I0 (pucch) %d, I0 (avg) %d\n",rxlev,dB_fixed(rxlev),dB_fixed(rxlev_pucch),sigma2_dB,SNR,10*log10((double)txlev*UE->frame_parms.ofdm_symbol_size/12),gNB->measurements.n0_subband_power_tot_dB[startingPRB],gNB->measurements.n0_subband_power_avg_dB); if(format==0){ nfapi_nr_uci_pucch_pdu_format_0_1_t uci_pdu; nfapi_nr_pucch_pdu_t pucch_pdu; + gNB->uci_stats[0].rnti = 0x1234; + pucch_pdu.rnti = 0x1234; pucch_pdu.subcarrier_spacing = 1; pucch_pdu.group_hop_flag = PUCCH_GroupHopping&1; pucch_pdu.sequence_hop_flag = (PUCCH_GroupHopping>>1)&1; @@ -601,18 +650,27 @@ int main(int argc, char **argv) pucch_pdu.start_symbol_index = startingSymbolIndex; pucch_pdu.prb_start = startingPRB; pucch_pdu.bwp_start = 0; - pucch_pdu.freq_hop_flag = 0; + pucch_pdu.bwp_size = N_RB_DL; + if (nrofSymbols>1) { + pucch_pdu.freq_hop_flag = 1; + pucch_pdu.second_hop_prb = N_RB_DL-1; + } + else pucch_pdu.freq_hop_flag = 0; + nr_decode_pucch0(gNB, nr_frame_tx, nr_slot_tx,&uci_pdu,&pucch_pdu); if(sr_flag==1){ if (uci_pdu.sr->sr_indication == 0 || uci_pdu.sr->sr_confidence_level == 1) sr_errors+=1; } if(nr_bit>0){ - if(nr_bit==1) + if (nr_bit==1 && do_DTX == 0) ack_nack_errors+=(actual_payload^uci_pdu.harq->harq_list[0].harq_value); - else + else if (do_DTX == 0) ack_nack_errors+=(((actual_payload&1)^uci_pdu.harq->harq_list[0].harq_value)+((actual_payload>>1)^uci_pdu.harq->harq_list[1].harq_value)); - free(uci_pdu.harq->harq_list); + else if ((uci_pdu.harq->harq_confidence_level == 0 && uci_pdu.harq->harq_list[0].harq_value == 1) || + (uci_pdu.harq->harq_confidence_level == 0 && nr_bit == 2 && uci_pdu.harq->harq_list[1].harq_value==1)) + ack_nack_errors++; + free(uci_pdu.harq->harq_list); } } else if (format==1) { @@ -644,6 +702,11 @@ int main(int argc, char **argv) pucch_pdu.prb_start = startingPRB; pucch_pdu.dmrs_scrambling_id = dmrs_scrambling_id; pucch_pdu.data_scrambling_id = data_scrambling_id; + if (nrofSymbols>1) { + pucch_pdu.freq_hop_flag = 1; + pucch_pdu.second_hop_prb = N_RB_DL-1; + } + else pucch_pdu.freq_hop_flag = 0; nr_decode_pucch2(gNB,nr_slot_tx,&uci_pdu,&pucch_pdu); int csi_part1_bytes=pucch_pdu.bit_len_csi_part1>>3; if ((pucch_pdu.bit_len_csi_part1&7) > 0) csi_part1_bytes++; @@ -668,13 +731,15 @@ int main(int argc, char **argv) } } - for (i=0; i<2; i++) { - free(s_re[i]); - free(s_im[i]); - free(r_re[i]); - free(r_im[i]); - free(txdataF[i]); - free(rxdataF[i]); + for (int aatx=0; aatx 2)) { + if ((n_rx == 0) || (n_rx > 8)) { printf("Unsupported number of rx antennas %d\n", n_rx); exit(-1); } @@ -673,8 +666,15 @@ int main(int argc, char **argv) gNB->threadPool = (tpool_t*)malloc(sizeof(tpool_t)); gNB->respDecode = (notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t)); char tp_param[] = "n"; - initTpool(tp_param, gNB->threadPool, true); + initTpool(tp_param, gNB->threadPool, false); initNotifiedFIFO(gNB->respDecode); + gNB->resp_L1_tx = (notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t)); + initNotifiedFIFO(gNB->resp_L1_tx); + notifiedFIFO_elt_t *msgL1Tx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t),0,gNB->resp_L1_tx,NULL); + processingData_L1tx_t *msgDataTx = (processingData_L1tx_t *)NotifiedFifoData(msgL1Tx); + msgDataTx->slot = -1; + gNB->phy_proc_tx_0 = &msgDataTx->phy_proc_tx; + pushNotifiedFIFO(gNB->resp_L1_tx,msgL1Tx); // to unblock the process in the beginning //gNB_config = &gNB->gNB_config; //memset((void *)&gNB->UL_INFO,0,sizeof(gNB->UL_INFO)); @@ -685,13 +685,14 @@ int main(int argc, char **argv) gNB->prb_interpolation = prb_inter; frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH) - - //frame_parms->nb_antennas_tx = n_tx; - //frame_parms->nb_antennas_rx = n_rx; frame_parms->N_RB_DL = N_RB_DL; frame_parms->N_RB_UL = N_RB_UL; frame_parms->Ncp = extended_prefix_flag ? EXTENDED : NORMAL; + s_re = malloc(n_tx*sizeof(double*)); + s_im = malloc(n_tx*sizeof(double*)); + r_re = malloc(n_rx*sizeof(double*)); + r_im = malloc(n_rx*sizeof(double*)); RC.nb_nr_macrlc_inst = 1; RC.nb_nr_mac_CC = (int*)malloc(RC.nb_nr_macrlc_inst*sizeof(int)); @@ -726,9 +727,15 @@ int main(int argc, char **argv) gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; // common configuration - rrc_mac_config_req_gNB(0,0, n_tx, n_tx, 0, scc, 0, 0, NULL); + rrc_mac_config_req_gNB(0,0, n_tx, n_rx, 0, scc, &rrc.carrier.mib,0, 0, NULL); // UE dedicated configuration - rrc_mac_config_req_gNB(0,0, n_tx, n_tx, 0, scc, 1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); + rrc_mac_config_req_gNB(0,0, n_tx, n_rx, 0, scc, &rrc.carrier.mib,1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); + frame_parms->nb_antennas_tx = n_tx; + frame_parms->nb_antennas_rx = n_rx; + nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; + cfg->carrier_config.num_tx_ant.value = n_tx; + cfg->carrier_config.num_rx_ant.value = n_rx; + nr_phy_config_request_sim(gNB,N_RB_DL,N_RB_DL,mu,0,0x01); phy_init_nr_gNB(gNB,0,1); N_RB_DL = gNB->frame_parms.N_RB_DL; @@ -770,8 +777,16 @@ int main(int argc, char **argv) } } */ - - nr_l2_init_ue(NULL); + + //Configure UE + NR_UE_RRC_INST_t rrcue; + memset(&rrcue,0,sizeof(NR_UE_RRC_INST_t)); + rrc.carrier.MIB = (uint8_t*) malloc(4); + rrc.carrier.sizeof_MIB = do_MIB_NR(&rrc,0); + rrcue.mib = rrc.carrier.mib.message.choice.mib; + rrcue.scell_group_config=secondaryCellGroup; + nr_l2_init_ue(&rrcue); + NR_UE_MAC_INST_t* UE_mac = get_mac_inst(0); UE->if_inst = nr_ue_if_module_init(0); @@ -782,11 +797,7 @@ int main(int argc, char **argv) UE_mac->if_module = nr_ue_if_module_init(0); - //Configure UE - rrc.carrier.MIB = (uint8_t*) malloc(4); - rrc.carrier.sizeof_MIB = do_MIB_NR(&rrc,0); - - nr_rrc_mac_config_req_ue(0,0,0,rrc.carrier.mib.message.choice.mib, NULL, NULL, secondaryCellGroup); +// nr_rrc_mac_config_req_ue(0,0,0,rrc.carrier.mib.message.choice.mib, NULL, NULL, secondaryCellGroup); nr_ue_phy_config_request(&UE_mac->phy_config); @@ -854,12 +865,13 @@ int main(int argc, char **argv) { add_pos = dmrs_arg[1]; } - printf("NOTE: DMRS config is modified with Mapping Type %d , Additional Position %d \n", mapping_type, add_pos ); } + printf("NOTE: DMRS config is modified with Mapping Type %d , Additional Position %d \n", mapping_type, add_pos ); uint8_t length_dmrs = pusch_len1; uint16_t l_prime_mask = get_l_prime(nb_symb_sch, mapping_type, add_pos, length_dmrs, start_symbol, NR_MIB__dmrs_TypeA_Position_pos2); uint16_t number_dmrs_symbols = get_dmrs_symbols_in_slot(l_prime_mask, nb_symb_sch); + printf("num dmrs sym %d\n",number_dmrs_symbols); uint8_t nb_re_dmrs = (dmrs_config_type == pusch_dmrs_type1) ? 6 : 4; // if transform precoding is enabled @@ -871,11 +883,11 @@ int main(int argc, char **argv) AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n"); dmrs_config_type = pusch_dmrs_type1; - nb_re_dmrs = nb_re_dmrs * num_dmrs_cdm_grps_no_data; printf("[ULSIM]: TRANSFORM PRECODING ENABLED. Num RBs: %d, index for DMRS_SEQ: %d\n", nb_rb, index); } + nb_re_dmrs = nb_re_dmrs * num_dmrs_cdm_grps_no_data; unsigned int available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, number_dmrs_symbols, mod_order, 1); unsigned int TBS = nr_compute_tbs(mod_order, code_rate, nb_rb, nb_symb_sch, nb_re_dmrs * number_dmrs_symbols, 0, 0, precod_nbr_layers); @@ -917,13 +929,24 @@ int main(int argc, char **argv) printf("NOTE: PTRS Enabled with L %d, K %d \n", ptrs_time_density, ptrs_freq_density ); } - if (input_fd != NULL) max_rounds=1; + if (input_fd != NULL || n_trials == 1) max_rounds=1; if(1<= nb_symb_sch) pdu_bit_map &= ~PUSCH_PDU_BITMAP_PUSCH_PTRS; // disable PUSCH PTRS printf("\n"); + int frame_length_complex_samples = frame_parms->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME; + for (int aatx=0; aatxcommon_vars.rxdata[0][slot_offset])[i], @@ -975,14 +1001,24 @@ int main(int argc, char **argv) code_rate = nr_get_code_rate_ul(Imcs, mcs_table); } + uint32_t errors_scrambling[4][100]; + int n_errors[4][100]; + int round_trials[4][100]; + double blerStats[4][100]; + double berStats[4][100]; + double snrStats[100]; + memset(errors_scrambling, 0, sizeof(uint32_t)*4*100); + memset(n_errors, 0, sizeof(int)*4*100); + memset(round_trials, 0, sizeof(int)*4*100); + memset(blerStats, 0, sizeof(double)*4*100); + memset(berStats, 0, sizeof(double)*4*100); + memset(snrStats, 0, sizeof(double)*100); for (SNR = snr0; SNR < snr1; SNR += snr_step) { varArray_t *table_rx=initVarArray(1000,sizeof(double)); int error_flag = 0; n_false_positive = 0; - effRate = 0; - int n_errors[4] = {0,0,0,0};; - int round_trials[4]={0,0,0,0}; - uint32_t errors_scrambling[4] = {0,0,0,0}; + effRate[snrRun] = 0; + effTP[snrRun] = 0; reset_meas(&gNB->phy_proc_rx); reset_meas(&gNB->rx_pusch_stats); reset_meas(&gNB->ulsch_decoding_stats); @@ -1007,7 +1043,7 @@ int main(int argc, char **argv) errors_decoding = 0; memset((void*)roundStats,0,50*sizeof(roundStats[0])); while (roundharq_processes[harq_pid]->round = round; gNB->ulsch[0][0]->harq_processes[harq_pid]->round = round; rv_index = nr_rv_round_map[round]; @@ -1057,7 +1093,7 @@ int main(int argc, char **argv) pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId; pusch_pdu->scid = 0; pusch_pdu->dmrs_ports = 1; - pusch_pdu->num_dmrs_cdm_grps_no_data = msg3_flag == 0 ? 1 : 2; + pusch_pdu->num_dmrs_cdm_grps_no_data = num_dmrs_cdm_grps_no_data; pusch_pdu->resource_alloc = 1; pusch_pdu->rb_start = start_rb; pusch_pdu->rb_size = nb_rb; @@ -1120,7 +1156,7 @@ int main(int argc, char **argv) ul_config.ul_config_list[0].pusch_config_pdu.dmrs_config_type = dmrs_config_type; ul_config.ul_config_list[0].pusch_config_pdu.mcs_index = Imcs; ul_config.ul_config_list[0].pusch_config_pdu.mcs_table = mcs_table; - ul_config.ul_config_list[0].pusch_config_pdu.num_dmrs_cdm_grps_no_data = msg3_flag == 0 ? 1 : 2; + ul_config.ul_config_list[0].pusch_config_pdu.num_dmrs_cdm_grps_no_data = num_dmrs_cdm_grps_no_data; ul_config.ul_config_list[0].pusch_config_pdu.nrOfLayers = precod_nbr_layers; ul_config.ul_config_list[0].pusch_config_pdu.absolute_delta_PUSCH = 0; @@ -1265,6 +1301,58 @@ int main(int argc, char **argv) (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); LOG_M("rxsigF0_comp.m","rxsF0_comp", &gNB->pusch_vars[0]->rxdataF_comp[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("chmagF0.m","chmF0", + &gNB->pusch_vars[0]->ul_ch_mag[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_M("chmagbF0.m","chmbF0", + &gNB->pusch_vars[0]->ul_ch_magb[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + if (n_rx == 2) { + LOG_MM("rxsigF0_comp.m","rxsF1_comp", + &gNB->pusch_vars[0]->rxdataF_comp[1][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("rxsigF0_ext.m","rxsF1_ext", + &gNB->pusch_vars[0]->rxdataF_ext[1][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("chestF0_ext.m","chF1_ext", + &gNB->pusch_vars[0]->ul_ch_estimates_ext[1][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], + (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("chmagF0.m","chmF1", + &gNB->pusch_vars[0]->ul_ch_mag[1][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("chmagbF0.m","chmbF1", + &gNB->pusch_vars[0]->ul_ch_magb[1][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + } else if (n_rx == 4) { + LOG_MM("rxsigF0_comp.m","rxsF1_comp", + &gNB->pusch_vars[0]->rxdataF_comp[1][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("rxsigF0_comp.m","rxsF2_comp", + &gNB->pusch_vars[0]->rxdataF_comp[2][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("rxsigF0_comp.m","rxsF3_comp", + &gNB->pusch_vars[0]->rxdataF_comp[3][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("rxsigF0_ext.m","rxsF1_ext", + &gNB->pusch_vars[0]->rxdataF_ext[1][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("rxsigF0_ext.m","rxsF2_ext", + &gNB->pusch_vars[0]->rxdataF_ext[2][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("rxsigF0_ext.m","rxsF3_ext", + &gNB->pusch_vars[0]->rxdataF_ext[3][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("chestF0_ext.m","chF1_ext", + &gNB->pusch_vars[0]->ul_ch_estimates_ext[1][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], + (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("chestF0_ext.m","chF2_ext", + &gNB->pusch_vars[0]->ul_ch_estimates_ext[2][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], + (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("chestF0_ext.m","chF3_ext", + &gNB->pusch_vars[0]->ul_ch_estimates_ext[3][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))], + (nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("chmagF0.m","chmF1", + &gNB->pusch_vars[0]->ul_ch_mag[1][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("chmagF0.m","chmF2", + &gNB->pusch_vars[0]->ul_ch_mag[2][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("chmagF0.m","chmF3", + &gNB->pusch_vars[0]->ul_ch_mag[3][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("chmagbF0.m","chmbF1", + &gNB->pusch_vars[0]->ul_ch_magb[1][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("chmagbF0.m","chmbF2", + &gNB->pusch_vars[0]->ul_ch_magb[2][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + LOG_MM("chmagbF0.m","chmbF3", + &gNB->pusch_vars[0]->ul_ch_magb[3][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1); + } + LOG_M("rxsigF0_llr.m","rxsF0_llr", &gNB->pusch_vars[0]->llr[0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0); } @@ -1273,7 +1361,7 @@ int main(int argc, char **argv) if ((gNB->ulsch[0][0]->last_iteration_cnt >= gNB->ulsch[0][0]->max_ldpc_iterations+1) || ul_proc_error == 1) { error_flag = 1; - n_errors[round]++; + n_errors[round][snrRun]++; crc_status = 1; } else { crc_status = 0; @@ -1301,15 +1389,15 @@ int main(int argc, char **argv) { /*if(errors_scrambling == 0) printf("\x1B[34m" "[frame %d][trial %d]\t1st bit in error in unscrambling = %d\n" "\x1B[0m", frame, trial, i);*/ - errors_scrambling[round]++; + errors_scrambling[round][snrRun]++; } } round++; } // round - if (n_trials == 1 && errors_scrambling[0] > 0) { - printf("\x1B[31m""[frame %d][trial %d]\tnumber of errors in unscrambling = %u\n" "\x1B[0m", frame, trial, errors_scrambling[0]); + if (n_trials == 1 && errors_scrambling[0][snrRun] > 0) { + printf("\x1B[31m""[frame %d][trial %d]\tnumber of errors in unscrambling = %u\n" "\x1B[0m", frame, trial, errors_scrambling[0][snrRun]); } for (i = 0; i < TBS; i++) { @@ -1326,8 +1414,8 @@ int main(int argc, char **argv) if (n_trials == 1) { for (int r=0;rharq_processes[harq_pid]->C;r++) for (int i=0;iharq_processes[harq_pid]->K>>3;i++) { - /*if ((ulsch_ue[0]->harq_processes[harq_pid]->c[r][i]^ulsch_gNB->harq_processes[harq_pid]->c[r][i]) != 0) printf("************"); - printf("r %d: in[%d] %x, out[%d] %x (%x)\n",r, + if ((ulsch_ue[0]->harq_processes[harq_pid]->c[r][i]^ulsch_gNB->harq_processes[harq_pid]->c[r][i]) != 0) printf("************"); + /*printf("r %d: in[%d] %x, out[%d] %x (%x)\n",r, i,ulsch_ue[0]->harq_processes[harq_pid]->c[r][i], i,ulsch_gNB->harq_processes[harq_pid]->c[r][i], ulsch_ue[0]->harq_processes[harq_pid]->c[r][i]^ulsch_gNB->harq_processes[harq_pid]->c[r][i]);*/ @@ -1339,26 +1427,36 @@ int main(int argc, char **argv) printf("\x1B[31m""[frame %d][trial %d]\tnumber of errors in decoding = %u\n" "\x1B[0m", frame, trial, errors_decoding); } roundStats[snrRun] += ((float)round); - if (!crc_status) effRate += ((float)TBS)/round; + if (!crc_status) effRate[snrRun] += ((double)TBS)/(double)round; } // trial loop roundStats[snrRun]/=((float)n_trials); - effRate /= n_trials; + effRate[snrRun] /= (double)n_trials; printf("*****************************************\n"); - printf("SNR %f: n_errors (%d/%d,%d/%d,%d/%d,%d/%d) (negative CRC), false_positive %d/%d, errors_scrambling (%u/%u,%u/%u,%u/%u,%u/%u\n", SNR, n_errors[0], round_trials[0],n_errors[1], round_trials[1],n_errors[2], round_trials[2],n_errors[3], round_trials[3], n_false_positive, n_trials, errors_scrambling[0],available_bits*n_trials,errors_scrambling[1],available_bits*n_trials,errors_scrambling[2],available_bits*n_trials,errors_scrambling[3],available_bits*n_trials); + printf("SNR %f: n_errors (%d/%d,%d/%d,%d/%d,%d/%d) (negative CRC), false_positive %d/%d, errors_scrambling (%u/%u,%u/%u,%u/%u,%u/%u\n", SNR, n_errors[0][snrRun], round_trials[0][snrRun],n_errors[1][snrRun], round_trials[1][snrRun],n_errors[2][snrRun], round_trials[2][snrRun],n_errors[3][snrRun], round_trials[3][snrRun], n_false_positive, n_trials, errors_scrambling[0][snrRun],available_bits*n_trials,errors_scrambling[1][snrRun],available_bits*n_trials,errors_scrambling[2][snrRun],available_bits*n_trials,errors_scrambling[3][snrRun],available_bits*n_trials); printf("\n"); + blerStats[0][snrRun] = (double)n_errors[0][snrRun]/round_trials[0][snrRun]; + blerStats[1][snrRun] = (double)n_errors[1][snrRun]/round_trials[1][snrRun]; + blerStats[2][snrRun] = (double)n_errors[2][snrRun]/round_trials[2][snrRun]; + blerStats[3][snrRun] = (double)n_errors[3][snrRun]/round_trials[3][snrRun]; + + berStats[0][snrRun] = (double)errors_scrambling[0][snrRun]/available_bits/round_trials[0][snrRun]; + berStats[1][snrRun] = (double)errors_scrambling[1][snrRun]/available_bits/round_trials[1][snrRun]; + berStats[2][snrRun] = (double)errors_scrambling[2][snrRun]/available_bits/round_trials[2][snrRun]; + berStats[3][snrRun] = (double)errors_scrambling[3][snrRun]/available_bits/round_trials[3][snrRun]; + effTP[snrRun] = effRate[snrRun]/(double)TBS*(double)100; printf("SNR %f: Channel BLER (%e,%e,%e,%e), Channel BER (%e,%e,%e,%e) Avg round %.2f, Eff Rate %.4f bits/slot, Eff Throughput %.2f, TBS %u bits/slot\n", SNR, - (double)n_errors[0]/round_trials[0], - (double)n_errors[1]/round_trials[0], - (double)n_errors[2]/round_trials[0], - (double)n_errors[3]/round_trials[0], - (double)errors_scrambling[0]/available_bits/round_trials[0], - (double)errors_scrambling[1]/available_bits/round_trials[0], - (double)errors_scrambling[2]/available_bits/round_trials[0], - (double)errors_scrambling[3]/available_bits/round_trials[0], - roundStats[snrRun],effRate,effRate/TBS*100,TBS); + blerStats[0][snrRun], + blerStats[1][snrRun], + blerStats[2][snrRun], + blerStats[3][snrRun], + berStats[0][snrRun], + berStats[1][snrRun], + berStats[2][snrRun], + berStats[3][snrRun], + roundStats[snrRun],effRate[snrRun],effTP[snrRun],TBS); FILE *fd=fopen("nr_ulsim.log","w"); dump_pusch_stats(fd,gNB); @@ -1391,18 +1489,47 @@ int main(int argc, char **argv) if(n_trials==1) break; - if ((float)n_errors[0]/(float)n_trials <= target_error_rate) { + if ((float)n_errors[0][snrRun]/(float)n_trials <= target_error_rate) { printf("*************\n"); printf("PUSCH test OK\n"); printf("*************\n"); break; } + snrStats[snrRun] = SNR; snrRun++; - n_errs = n_errors[0]; + n_errs = n_errors[0][snrRun]; } // SNR loop printf("\n"); + printf( "Num RB:\t%d\n" + "Num symbols:\t%d\n" + "MCS:\t%d\n" + "DMRS config type:\t%d\n" + "DMRS add pos:\t%d\n" + "PUSCH mapping type:\t%d\n" + "DMRS length:\t%d\n" + "DMRS CDM gr w/o data:\t%d\n", + nb_rb, + nb_symb_sch, + Imcs, + dmrs_config_type, + add_pos, + mapping_type, + length_dmrs, + num_dmrs_cdm_grps_no_data); + + LOG_M("ulsimStats.m","SNR",snrStats,snrRun,1,7); + LOG_MM("ulsimStats.m","BLER_round0",blerStats[0],snrRun,1,7); + LOG_MM("ulsimStats.m","BLER_round1",blerStats[1],snrRun,1,7); + LOG_MM("ulsimStats.m","BLER_round2",blerStats[2],snrRun,1,7); + LOG_MM("ulsimStats.m","BLER_round3",blerStats[3],snrRun,1,7); + LOG_MM("ulsimStats.m","BER_round0",berStats[0],snrRun,1,7); + LOG_MM("ulsimStats.m","BER_round1",berStats[1],snrRun,1,7); + LOG_MM("ulsimStats.m","BER_round2",berStats[2],snrRun,1,7); + LOG_MM("ulsimStats.m","BER_round3",berStats[3],snrRun,1,7); + LOG_MM("ulsimStats.m","EffRate",effRate,snrRun,1,7); + LOG_MM("ulsimStats.m","EffTP",effTP,snrRun,1,7); free(test_input_bit); free(estimated_output_bit); diff --git a/openair1/SIMULATION/TOOLS/abstraction.c b/openair1/SIMULATION/TOOLS/abstraction.c index d19afcd030..a6b0586882 100644 --- a/openair1/SIMULATION/TOOLS/abstraction.c +++ b/openair1/SIMULATION/TOOLS/abstraction.c @@ -39,7 +39,7 @@ double **cos_lut=NULL,* *sin_lut=NULL; -int init_freq_channel(channel_desc_t *desc,uint16_t nb_rb,int16_t n_samples) { +int init_freq_channel(channel_desc_t *desc,uint16_t nb_rb,int16_t n_samples,int scs) { double delta_f,freq; // 90 kHz spacing double delay; int16_t f; @@ -52,7 +52,7 @@ int init_freq_channel(channel_desc_t *desc,uint16_t nb_rb,int16_t n_samples) { cos_lut = (double **)malloc(n_samples*sizeof(double *)); sin_lut = (double **)malloc(n_samples*sizeof(double *)); - delta_f = nb_rb*180000/(n_samples-1); + delta_f = nb_rb*12*scs*1000/(n_samples-1); for (f=-(n_samples>>1); f<=(n_samples>>1); f++) { freq=delta_f*(double)f*1e-6;// due to the fact that delays is in mus @@ -67,14 +67,14 @@ int init_freq_channel(channel_desc_t *desc,uint16_t nb_rb,int16_t n_samples) { cos_lut[f+(n_samples>>1)][l] = cos(2*M_PI*freq*delay); sin_lut[f+(n_samples>>1)][l] = sin(2*M_PI*freq*delay); - //printf("values cos:%d, sin:%d\n", cos_lut[f][l], sin_lut[f][l]); + // printf("values cos:%f, sin:%f\n", cos_lut[f+(n_samples>>1)][l], sin_lut[f+(n_samples>>1)][l]); } } return(0); } -int freq_channel(channel_desc_t *desc,uint16_t nb_rb,int16_t n_samples) { +int freq_channel(channel_desc_t *desc,uint16_t nb_rb,int16_t n_samples,int scs) { int16_t f,f2,d; uint8_t aarx,aatx,l; double *clut,*slut; @@ -95,14 +95,14 @@ int freq_channel(channel_desc_t *desc,uint16_t nb_rb,int16_t n_samples) { // if called with n_samples<12*nb_rb+1, we decimate the lut n_samples_max=12*nb_rb+1; - if (init_freq_channel(desc,nb_rb,n_samples_max)==0) + if (init_freq_channel(desc,nb_rb,n_samples_max,scs)==0) freq_channel_init=1; else return(-1); } d=(n_samples_max-1)/(n_samples-1); - //printf("no_samples=%d, n_samples_max=%d, d=%d\n",n_samples,n_samples_max,d); + // printf("no_samples=%d, n_samples_max=%d, d=%d,nb_taps %d\n",n_samples,n_samples_max,d,desc->nb_taps); start_meas(&desc->interp_freq); for (f=-n_samples_max/2,f2=-n_samples/2; fnb_rx; aarx++) { for (aatx=0; aatxnb_tx; aatx++) { + AssertFatal(n_samples/2+f2 < (2+(275*12)),"reading past chF %d (n_samples %d, f2 %d)\n",n_samples/2+f2,n_samples,f2); desc->chF[aarx+(aatx*desc->nb_rx)][n_samples/2+f2].r=0.0; desc->chF[aarx+(aatx*desc->nb_rx)][n_samples/2+f2].i=0.0; diff --git a/openair1/SIMULATION/TOOLS/random_channel.c b/openair1/SIMULATION/TOOLS/random_channel.c index d393bb1342..f09d1a7ce1 100644 --- a/openair1/SIMULATION/TOOLS/random_channel.c +++ b/openair1/SIMULATION/TOOLS/random_channel.c @@ -519,12 +519,12 @@ void tdlModel(int tdl_paths, double *tdl_delays, double *tdl_amps_dB, double DS chan_desc->ch[i] = (struct complexd *) malloc(chan_desc->channel_length * sizeof(struct complexd)); for (int i = 0; ichF[i] = (struct complexd *) malloc(1200 * sizeof(struct complexd)); + chan_desc->chF[i] = (struct complexd *) malloc((2+(275*12)) * sizeof(struct complexd)); for (int i = 0; inb_taps; i++) chan_desc->a[i] = (struct complexd *) malloc(nb_tx*nb_rx * sizeof(struct complexd)); - chan_desc->R_sqrt = (struct complexd **) malloc(6*sizeof(struct complexd **)); + chan_desc->R_sqrt = (struct complexd **) malloc(tdl_pathsby3*sizeof(struct complexd **)); if (nb_tx==2 && nb_rx==2) { for (int i = 0; i<(tdl_pathsby3); i++) @@ -1708,10 +1708,9 @@ void set_channeldesc_name(channel_desc_t *cdesc,char *modelname) { int random_channel(channel_desc_t *desc, uint8_t abstraction_flag) { double s; int i,k,l,aarx,aatx; - struct complexd anew[NB_ANTENNAS_TX*NB_ANTENNAS_RX],acorr[NB_ANTENNAS_TX*NB_ANTENNAS_RX]; + struct complexd anew[desc->nb_tx*desc->nb_rx]; + struct complexd acorr[desc->nb_tx*desc->nb_rx]; struct complexd phase, alpha, beta; - AssertFatal(desc->nb_tx<=NB_ANTENNAS_TX && desc->nb_rx <= NB_ANTENNAS_RX, - "random_channel.c: Error: temporary buffer for channel not big enough (%d,%d)\n",desc->nb_tx,desc->nb_rx); start_meas(&desc->random_channel); for (i=0; i<(int)desc->nb_taps; i++) { @@ -1735,7 +1734,7 @@ int random_channel(channel_desc_t *desc, uint8_t abstraction_flag) { } #ifdef DEBUG_CH - printf("(%d,%d,%d) %f->(%f,%f) (%f,%f) phase (%f,%f)\n",aarx,aatx,i,desc->amps[i],anew[aarx+(aatx*desc->nb_rx)].x,anew[aarx+(aatx*desc->nb_rx)].y,desc->aoa,desc->ricean_factor,phase.x,phase.y); + printf("(%d,%d,%d) %f->(%f,%f) (%f,%f) phase (%f,%f)\n",aarx,aatx,i,desc->amps[i],anew[aarx+(aatx*desc->nb_rx)].r,anew[aarx+(aatx*desc->nb_rx)].i,desc->aoa,desc->ricean_factor,phase.r,phase.i); #endif } //aatx } //aarx @@ -1752,6 +1751,11 @@ int random_channel(channel_desc_t *desc, uint8_t abstraction_flag) { */ //apply correlation matrix //compute acorr = R_sqrt[i] * anew + bzero(acorr,desc->nb_tx*desc->nb_rx*sizeof(struct complexd)); + cblas_zaxpy(desc->nb_tx*desc->nb_rx, (void *) desc->R_sqrt[i/3], (void *) anew, 1, (void *) acorr, 1); + + /* + FIXME: Function cblas_zgemv has an undefined output (for the same input) after a second call in RHEL8 (acorr = nan) alpha.r = 1.0; alpha.i = 0.0; beta.r = 0.0; @@ -1759,6 +1763,7 @@ int random_channel(channel_desc_t *desc, uint8_t abstraction_flag) { cblas_zgemv(CblasRowMajor, CblasNoTrans, desc->nb_tx*desc->nb_rx, desc->nb_tx*desc->nb_rx, (void *) &alpha, (void *) desc->R_sqrt[i/3], desc->nb_rx*desc->nb_tx, (void *) anew, 1, (void *) &beta, (void *) acorr, 1); + */ /* for (aarx=0;aarxnb_rx;aarx++) { @@ -1827,7 +1832,7 @@ int random_channel(channel_desc_t *desc, uint8_t abstraction_flag) { } //nb_taps #ifdef DEBUG_CH - printf("(%d,%d,%d)->(%e,%e)\n",k,aarx,aatx,desc->ch[aarx+(aatx*desc->nb_rx)][k].x,desc->ch[aarx+(aatx*desc->nb_rx)][k].y); + printf("(%d,%d,%d)->(%e,%e)\n",k,aarx,aatx,desc->ch[aarx+(aatx*desc->nb_rx)][k].r,desc->ch[aarx+(aatx*desc->nb_rx)][k].i); #endif } //channel_length } diff --git a/openair1/SIMULATION/TOOLS/sim.h b/openair1/SIMULATION/TOOLS/sim.h index 4b3ac5f862..ce470fe0b0 100644 --- a/openair1/SIMULATION/TOOLS/sim.h +++ b/openair1/SIMULATION/TOOLS/sim.h @@ -477,8 +477,8 @@ int gauss(unsigned int *gauss_LUT,unsigned char Nbits); double gaussdouble(double,double); void randominit(unsigned int seed_init); double uniformrandom(void); -int freq_channel(channel_desc_t *desc,uint16_t nb_rb, int16_t n_samples); -int init_freq_channel(channel_desc_t *desc,uint16_t nb_rb,int16_t n_samples); +int freq_channel(channel_desc_t *desc,uint16_t nb_rb, int16_t n_samples,int scs); +int init_freq_channel(channel_desc_t *desc,uint16_t nb_rb,int16_t n_samples,int scs); uint8_t multipath_channel_nosigconv(channel_desc_t *desc); void multipath_tv_channel(channel_desc_t *desc, double **tx_sig_re, diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index ecf5307dc0..8238b7961a 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -307,7 +307,7 @@ typedef struct f1ap_initial_ul_rrc_message_s { uint16_t crnti; uint8_t *rrc_container; int rrc_container_length; - char du2cu_rrc_container[100]; + char du2cu_rrc_container[200]; int du2cu_rrc_container_length; } f1ap_initial_ul_rrc_message_t; diff --git a/openair2/COMMON/gtpv1_u_messages_def.h b/openair2/COMMON/gtpv1_u_messages_def.h index e5ce496701..2835d07e4a 100644 --- a/openair2/COMMON/gtpv1_u_messages_def.h +++ b/openair2/COMMON/gtpv1_u_messages_def.h @@ -29,9 +29,8 @@ MESSAGE_DEF(GTPV1U_ENB_DATA_FORWARDING_REQ, MESSAGE_PRIORITY_MED, gtpv1u_enb_dat MESSAGE_DEF(GTPV1U_ENB_DATA_FORWARDING_IND, MESSAGE_PRIORITY_MED, gtpv1u_enb_data_forwarding_ind_t,Gtpv1uDataForwardingInd) MESSAGE_DEF(GTPV1U_ENB_END_MARKER_REQ, MESSAGE_PRIORITY_MED, gtpv1u_enb_end_marker_req_t, Gtpv1uEndMarkerReq) MESSAGE_DEF(GTPV1U_ENB_END_MARKER_IND, MESSAGE_PRIORITY_MED, gtpv1u_enb_end_marker_ind_t, Gtpv1uEndMarkerInd) -MESSAGE_DEF(GTPV1U_ENB_S1_REQ, MESSAGE_PRIORITY_MED, Gtpv1uS1Req, gtpv1uS1Req) +MESSAGE_DEF(GTPV1U_REQ, MESSAGE_PRIORITY_MED, Gtpv1uReq, gtpv1uReq) MESSAGE_DEF(GTPV1U_GNB_DELETE_TUNNEL_REQ, MESSAGE_PRIORITY_MED, gtpv1u_gnb_delete_tunnel_req_t, NRGtpv1uDeleteTunnelReq) MESSAGE_DEF(GTPV1U_GNB_DELETE_TUNNEL_RESP, MESSAGE_PRIORITY_MED, gtpv1u_gnb_delete_tunnel_resp_t, NRGtpv1uDeleteTunnelResp) -MESSAGE_DEF(GTPV1U_GNB_NG_REQ, MESSAGE_PRIORITY_MED, Gtpv1uNGReq, gtpv1uNGReq) MESSAGE_DEF(GTPV1U_GNB_TUNNEL_DATA_REQ, MESSAGE_PRIORITY_MED, gtpv1u_gnb_tunnel_data_req_t, NRGtpv1uTunnelDataReq) diff --git a/openair2/COMMON/gtpv1_u_messages_types.h b/openair2/COMMON/gtpv1_u_messages_types.h index 1dff6b89cb..2dd476ab68 100644 --- a/openair2/COMMON/gtpv1_u_messages_types.h +++ b/openair2/COMMON/gtpv1_u_messages_types.h @@ -39,11 +39,10 @@ #define GTPV1U_ENB_END_MARKER_REQ(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uEndMarkerReq #define GTPV1U_ENB_END_MARKER_IND(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uEndMarkerInd -#define GTPV1U_ENB_S1_REQ(mSGpTR) (mSGpTR)->ittiMsg.gtpv1uS1Req +#define GTPV1U_REQ(mSGpTR) (mSGpTR)->ittiMsg.gtpv1uReq #define GTPV1U_GNB_DELETE_TUNNEL_REQ(mSGpTR) (mSGpTR)->ittiMsg.NRGtpv1uDeleteTunnelReq #define GTPV1U_GNB_DELETE_TUNNEL_RESP(mSGpTR) (mSGpTR)->ittiMsg.NRGtpv1uDeleteTunnelResp -#define GTPV1U_GNB_NG_REQ(mSGpTR) (mSGpTR)->ittiMsg.gtpv1uNGReq #define GTPV1U_GNB_TUNNEL_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.NRGtpv1uTunnelDataReq #define GTPV1U_ALL_TUNNELS_TEID (teid_t)0xFFFFFFFF @@ -174,18 +173,13 @@ typedef struct gtpv1u_enb_end_marker_ind_s { } gtpv1u_enb_end_marker_ind_t; typedef struct { - in_addr_t enb_ip_address_for_S1u_S12_S4_up; - tcp_udp_port_t enb_port_for_S1u_S12_S4_up; - char addrStr[256]; - char portStr[256]; -} Gtpv1uS1Req; + in_addr_t localAddr; + tcp_udp_port_t localPort; + char localAddrStr[256]; + char localPortStr[256]; +} Gtpv1uReq; + -typedef struct { - in_addr_t gnb_ip_address_for_NGu_up; - tcp_udp_port_t gnb_port_for_NGu_up; - char addrStr[256]; - char portStr[256]; -} Gtpv1uNGReq; typedef struct gtpv1u_gnb_create_tunnel_req_s { rnti_t rnti; int num_tunnels; diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index af746b9193..60d48c8284 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -369,6 +369,57 @@ typedef enum ngap_Cause_e { } ngap_Cause_t; +typedef enum ngap_Cause_radio_network_e { + NGAP_CAUSE_RADIO_NETWORK_UNSPECIFIED, + NGAP_CAUSE_RADIO_NETWORK_TXNRELOCOVERALL_EXPIRY, + NGAP_CAUSE_RADIO_NETWORK_SUCCESSFUL_HANDOVER, + NGAP_CAUSE_RADIO_NETWORK_RELEASE_DUE_TO_NGRAN_GENERATED_REASON, + NGAP_CAUSE_RADIO_NETWORK_RELEASE_DUE_TO_5GC_GENERATED_REASON, + NGAP_CAUSE_RADIO_NETWORK_HANDOVER_CANCELLED, + NGAP_CAUSE_RADIO_NETWORK_PARTIAL_HANDOVER, + NGAP_CAUSE_RADIO_NETWORK_HO_FAILURE_IN_TARGET_5GC_NGRAN_NODE_OR_TARGET_SYSTEM, + NGAP_CAUSE_RADIO_NETWORK_HO_TARGET_NOT_ALLOWED, + NGAP_CAUSE_RADIO_NETWORK_TNGRELOCOVERALL_EXPIRY, + NGAP_CAUSE_RADIO_NETWORK_TNGRELOCPREP_EXPIRY, + NGAP_CAUSE_RADIO_NETWORK_CELL_NOT_AVAILABLE, + NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_TARGETID, + NGAP_CAUSE_RADIO_NETWORK_NO_RADIO_RESOURCES_AVAILABLE_IN_TARGET_CELL, + NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_LOCAL_UE_NGAP_ID, + NGAP_CAUSE_RADIO_NETWORK_INCONSISTENT_REMOTE_UE_NGAP_ID, + NGAP_CAUSE_RADIO_NETWORK_HANDOVER_DESIRABLE_FOR_RADIO_REASON, + NGAP_CAUSE_RADIO_NETWORK_TIME_CRITICAL_HANDOVER, + NGAP_CAUSE_RADIO_NETWORK_RESOURCE_OPTIMISATION_HANDOVER, + NGAP_CAUSE_RADIO_NETWORK_REDUCE_LOAD_IN_SERVING_CELL, + NGAP_CAUSE_RADIO_NETWORK_USER_INACTIVITY, + NGAP_CAUSE_RADIO_NETWORK_RADIO_CONNECTION_WITH_UE_LOST, + NGAP_CAUSE_RADIO_NETWORK_RADIO_RESOURCES_NOT_AVAILABLE, + NGAP_CAUSE_RADIO_NETWORK_INVALID_QOS_COMBINATION, + NGAP_CAUSE_RADIO_NETWORK_FAILURE_IN_RADIO_INTERFACE_PROCEDURE, + NGAP_CAUSE_RADIO_NETWORK_INTERACTION_WITH_OTHER_PROCEDURE, + NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_PDU_SESSION_ID, + NGAP_CAUSE_RADIO_NETWORK_UNKOWN_QOS_FLOW_ID, + NGAP_CAUSE_RADIO_NETWORK_MULTIPLE_PDU_SESSION_ID_INSTANCES, + NGAP_CAUSE_RADIO_NETWORK_MULTIPLE_QOS_FLOW_ID_INSTANCES, + NGAP_CAUSE_RADIO_NETWORK_ENCRYPTION_AND_OR_INTEGRITY_PROTECTION_ALGORITHMS_NOT_SUPPORTED, + NGAP_CAUSE_RADIO_NETWORK_NG_INTRA_SYSTEM_HANDOVER_TRIGGERED, + NGAP_CAUSE_RADIO_NETWORK_NG_INTER_SYSTEM_HANDOVER_TRIGGERED, + NGAP_CAUSE_RADIO_NETWORK_XN_HANDOVER_TRIGGERED, + NGAP_CAUSE_RADIO_NETWORK_NOT_SUPPORTED_5QI_VALUE, + NGAP_CAUSE_RADIO_NETWORK_UE_CONTEXT_TRANSFER, + NGAP_CAUSE_RADIO_NETWORK_IMS_VOICE_EPS_FALLBACK_OR_RAT_FALLBACK_TRIGGERED, + NGAP_CAUSE_RADIO_NETWORK_UP_INTEGRITY_PROTECTION_NOT_POSSIBLE, + NGAP_CAUSE_RADIO_NETWORK_UP_CONFIDENTIALITY_PROTECTION_NOT_POSSIBLE, + NGAP_CAUSE_RADIO_NETWORK_SLICE_NOT_SUPPORTED, + NGAP_CAUSE_RADIO_NETWORK_UE_IN_RRC_INACTIVE_STATE_NOT_REACHABLE, + NGAP_CAUSE_RADIO_NETWORK_REDIRECTION, + NGAP_CAUSE_RADIO_NETWORK_RESOURCES_NOT_AVAILABLE_FOR_THE_SLICE, + NGAP_CAUSE_RADIO_NETWORK_UE_MAX_INTEGRITY_PROTECTED_DATA_RATE_REASON, + NGAP_CAUSE_RADIO_NETWORK_RELEASE_DUE_TO_CN_DETECTED_MOBILITY, + NGAP_CAUSE_RADIO_NETWORK_N26_INTERFACE_NOT_AVAILABLE, + NGAP_CAUSE_RADIO_NETWORK_RELEASE_DUE_TO_PRE_EMPTION, + NGAP_CAUSE_RADIO_NETWORK_MULTIPLE_LOCATION_REPORTING_REFERENCE_ID_INSTANCES +} ngap_Cause_radio_network_t; + typedef struct pdusession_failed_s { /* Unique pdusession_id for the UE. */ uint8_t pdusession_id; diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h index 6d48de166e..41dbb26cc1 100644 --- a/openair2/COMMON/rrc_messages_types.h +++ b/openair2/COMMON/rrc_messages_types.h @@ -413,6 +413,7 @@ typedef struct NRRrcConfigurationReq_s { int sib1_tda; int pdsch_AntennaPorts; int pusch_AntennaPorts; + int minRXTXTIMEpdsch; int do_CSIRS; int pusch_TargetSNRx10; int pucch_TargetSNRx10; diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index 7b82ec31a1..a08bcf4baf 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -2074,12 +2074,12 @@ int RCconfig_gtpu(void ) { if (address) { MessageDef *message; - AssertFatal((message = itti_alloc_new_message(TASK_ENB_APP, 0, GTPV1U_ENB_S1_REQ))!=NULL,""); - IPV4_STR_ADDR_TO_INT_NWBO ( address, GTPV1U_ENB_S1_REQ(message).enb_ip_address_for_S1u_S12_S4_up, "BAD IP ADDRESS FORMAT FOR eNB S1_U !\n" ); - LOG_I(GTPU,"Configuring GTPu address : %s -> %x\n",address,GTPV1U_ENB_S1_REQ(message).enb_ip_address_for_S1u_S12_S4_up); - GTPV1U_ENB_S1_REQ(message).enb_port_for_S1u_S12_S4_up = enb_port_for_S1U; - strcpy(GTPV1U_ENB_S1_REQ(message).addrStr,address); - sprintf(GTPV1U_ENB_S1_REQ(message).portStr,"%d", enb_port_for_S1U); + AssertFatal((message = itti_alloc_new_message(TASK_ENB_APP, 0, GTPV1U_REQ))!=NULL,""); + IPV4_STR_ADDR_TO_INT_NWBO ( address, GTPV1U_REQ(message).localAddr, "BAD IP ADDRESS FORMAT FOR eNB S1_U !\n" ); + LOG_I(GTPU,"Configuring GTPu address : %s -> %x\n",address,GTPV1U_REQ(message).localAddr); + GTPV1U_REQ(message).localPort = enb_port_for_S1U; + strcpy(GTPV1U_REQ(message).localAddrStr,address); + sprintf(GTPV1U_REQ(message).localPortStr,"%d", enb_port_for_S1U); itti_send_msg_to_task (TASK_VARIABLE, 0, message); // data model is wrong: gtpu doesn't have enb_id (or module_id) } else LOG_E(GTPU,"invalid address for S1U\n"); diff --git a/openair2/ENB_APP/enb_paramdef.h b/openair2/ENB_APP/enb_paramdef.h index 79e66881b5..22af2a6de0 100644 --- a/openair2/ENB_APP/enb_paramdef.h +++ b/openair2/ENB_APP/enb_paramdef.h @@ -156,7 +156,7 @@ typedef enum { {CONFIG_STRING_RU_SDR_ADDRS, NULL, 0, strptr:NULL, defstrval:"type=b200", TYPE_STRING, 0}, \ {CONFIG_STRING_RU_SDR_CLK_SRC, NULL, 0, strptr:NULL, defstrval:"internal", TYPE_STRING, 0}, \ {CONFIG_STRING_RU_SDR_TME_SRC, NULL, 0, strptr:NULL, defstrval:"internal", TYPE_STRING, 0}, \ - {CONFIG_STRING_RU_SF_EXTENSION, NULL, 0, uptr:NULL, defuintval:312, TYPE_UINT, 0}, \ + {CONFIG_STRING_RU_SF_EXTENSION, NULL, 0, uptr:NULL, defuintval:320, TYPE_UINT, 0}, \ {CONFIG_STRING_RU_END_OF_BURST_DELAY, NULL, 0, uptr:NULL, defuintval:400, TYPE_UINT, 0}, \ {CONFIG_STRING_RU_OTA_SYNC_ENABLE, NULL, 0, strptr:NULL, defstrval:"no", TYPE_STRING, 0}, \ {CONFIG_STRING_RU_BF_WEIGHTS_LIST, NULL, 0, iptr:NULL, defintarrayval:DEFBFW, TYPE_INTARRAY, 0}, \ diff --git a/openair2/F1AP/dummy_enb.c b/openair2/F1AP/dummy_enb.c index cf7527d1f5..d54f9b8df7 100644 --- a/openair2/F1AP/dummy_enb.c +++ b/openair2/F1AP/dummy_enb.c @@ -32,3 +32,16 @@ void apply_macrlc_config(gNB_RRC_INST *rrc, abort(); } +boolean_t sdap_gnb_data_req(protocol_ctxt_t *ctxt_p, + const srb_flag_t srb_flag, + const rb_id_t rb_id, + const mui_t mui, + const confirm_t confirm, + const sdu_size_t sdu_buffer_size, + unsigned char *const sdu_buffer, + const pdcp_transmission_mode_t pt_mode, + const uint32_t *sourceL2Id, + const uint32_t *destinationL2Id + ) { +abort(); +} diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index aca88b9ea7..7858cd6c32 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -55,7 +55,7 @@ #define CONFIG_STRING_MACRLC_REMOTE_S_PORTC "remote_s_portc" #define CONFIG_STRING_MACRLC_LOCAL_S_PORTD "local_s_portd" #define CONFIG_STRING_MACRLC_REMOTE_S_PORTD "remote_s_portd" -#define CONFIG_STRING_MACRLC_ULSCH_MAX_SLOTS_INACTIVITY "ulsch_max_slots_inactivity" +#define CONFIG_STRING_MACRLC_ULSCH_MAX_FRAME_INACTIVITY "ulsch_max_frame_inactivity" #define CONFIG_STRING_MACRLC_PUSCHTARGETSNRX10 "pusch_TargetSNRx10" #define CONFIG_STRING_MACRLC_PUCCHTARGETSNRX10 "pucch_TargetSNRx10" #define CONFIG_STRING_MACRLC_PUCCHFAILURETHRES "pucch_FailureThres" @@ -83,7 +83,7 @@ {CONFIG_STRING_MACRLC_REMOTE_S_PORTC, NULL, 0, uptr:NULL, defintval:50020, TYPE_UINT, 0}, \ {CONFIG_STRING_MACRLC_LOCAL_S_PORTD, NULL, 0, uptr:NULL, defintval:50021, TYPE_UINT, 0}, \ {CONFIG_STRING_MACRLC_REMOTE_S_PORTD, NULL, 0, uptr:NULL, defintval:50021, TYPE_UINT, 0}, \ -{CONFIG_STRING_MACRLC_ULSCH_MAX_SLOTS_INACTIVITY, "Maximum number of slots before a UE is scheduled ULSCH due to inactivity", 0, uptr:NULL, defintval:200, TYPE_UINT, 0}, \ +{CONFIG_STRING_MACRLC_ULSCH_MAX_FRAME_INACTIVITY, NULL, 0, uptr:NULL, defintval:10, TYPE_UINT, 0}, \ {CONFIG_STRING_MACRLC_PUSCHTARGETSNRX10, NULL, 0, iptr:NULL, defintval:200, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUCCHTARGETSNRX10, NULL, 0, iptr:NULL, defintval:150, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUCCHFAILURETHRES, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ @@ -106,10 +106,10 @@ #define MACRLC_REMOTE_S_PORTC_IDX 14 #define MACRLC_LOCAL_S_PORTD_IDX 15 #define MACRLC_REMOTE_S_PORTD_IDX 16 -#define MACRLC_ULSCH_MAX_SLOTS_INACTIVITY 17 +#define MACRLC_ULSCH_MAX_FRAME_INACTIVITY 17 #define MACRLC_PUSCHTARGETSNRX10_IDX 18 #define MACRLC_PUCCHTARGETSNRX10_IDX 19 -#define MACRLC_PUCCHFAILURETHRES_IDX 20 +#define MACRLC_PUCCHFAILURETHRES_IDX 20 #define MACRLC_PUSCHFAILURETHRES_IDX 21 /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ #endif diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 29f3c15355..08255fe422 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -549,6 +549,32 @@ void RCconfig_nr_flexran() void RCconfig_NR_L1(void) { int j; + paramdef_t GNBSParams[] = GNBSPARAMS_DESC; + ////////// Identification parameters + paramdef_t GNBParams[] = GNBPARAMS_DESC; + + paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0}; + + config_get( GNBSParams,sizeof(GNBSParams)/sizeof(paramdef_t),NULL); + int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; + AssertFatal (num_gnbs > 0,"Failed to parse config file no gnbs %s \n",GNB_CONFIG_STRING_ACTIVE_GNBS); + + config_getlist( &GNBParamList,GNBParams,sizeof(GNBParams)/sizeof(paramdef_t),NULL); + char *ulprbbl = *GNBParamList.paramarray[0][GNB_ULPRBBLACKLIST_IDX].strptr; + if (ulprbbl) LOG_I(NR_PHY,"PRB blacklist %s\n",ulprbbl); + char *pt = strtok(ulprbbl,","); + int prbbl[275]; + int num_prbbl=0; + memset(prbbl,0,275*sizeof(int)); + + while (pt) { + prbbl[atoi(pt)] = 1; + LOG_I(NR_PHY,"Blacklisting prb %d\n",atoi(pt)); + pt = strtok(NULL,","); + num_prbbl++; + } + + paramdef_t L1_Params[] = L1PARAMS_DESC; paramlist_def_t L1_ParamList = {CONFIG_STRING_L1_LIST,NULL,0}; @@ -577,6 +603,9 @@ void RCconfig_NR_L1(void) { RC.gNB[j]->pucch0_thres = *(L1_ParamList.paramarray[j][L1_PUCCH0_DTX_THRESHOLD].uptr); RC.gNB[j]->prach_thres = *(L1_ParamList.paramarray[j][L1_PRACH_DTX_THRESHOLD].uptr); RC.gNB[j]->pusch_thres = *(L1_ParamList.paramarray[j][L1_PUSCH_DTX_THRESHOLD].uptr); + RC.gNB[j]->num_ulprbbl = num_prbbl; + LOG_I(NR_PHY,"Copying %d blacklisted PRB to L1 context\n",num_prbbl); + memcpy(RC.gNB[j]->ulprbbl,prbbl,275*sizeof(int)); if(strcmp(*(L1_ParamList.paramarray[j][L1_TRANSPORT_N_PREFERENCE_IDX].strptr), "local_mac") == 0) { //sf_ahead = 2; // Need 4 subframe gap between RX and TX }else if (strcmp(*(L1_ParamList.paramarray[j][L1_TRANSPORT_N_PREFERENCE_IDX].strptr), "nfapi") == 0) { @@ -633,6 +662,30 @@ void RCconfig_NR_L1(void) { void RCconfig_nr_macrlc() { int j; + paramdef_t GNBSParams[] = GNBSPARAMS_DESC; + ////////// Identification parameters + paramdef_t GNBParams[] = GNBPARAMS_DESC; + + paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0}; + + config_get( GNBSParams,sizeof(GNBSParams)/sizeof(paramdef_t),NULL); + int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; + AssertFatal (num_gnbs > 0,"Failed to parse config file no gnbs %s \n",GNB_CONFIG_STRING_ACTIVE_GNBS); + + config_getlist( &GNBParamList,GNBParams,sizeof(GNBParams)/sizeof(paramdef_t),NULL); + char *ulprbbl = *GNBParamList.paramarray[0][GNB_ULPRBBLACKLIST_IDX].strptr; + char *pt = strtok(ulprbbl,","); + int prbbl[275]; + int num_prbbl=0; + int prb; + memset(prbbl,0,275*sizeof(int)); + while (pt) { + prb=atoi(pt); + prbbl[prb] = 1; + pt = strtok(NULL,","); + num_prbbl++; + } + paramdef_t MacRLC_Params[] = MACRLCPARAMS_DESC; paramlist_def_t MacRLC_ParamList = {CONFIG_STRING_MACRLC_LIST,NULL,0}; @@ -650,7 +703,12 @@ void RCconfig_nr_macrlc() { RC.nrmac[j]->pucch_target_snrx10 = *(MacRLC_ParamList.paramarray[j][MACRLC_PUCCHTARGETSNRX10_IDX].iptr); RC.nrmac[j]->pucch_failure_thres = *(MacRLC_ParamList.paramarray[j][MACRLC_PUCCHFAILURETHRES_IDX].iptr); RC.nrmac[j]->pusch_failure_thres = *(MacRLC_ParamList.paramarray[j][MACRLC_PUSCHFAILURETHRES_IDX].iptr); - + + LOG_I(NR_MAC,"PUSCH Target %d, PUCCH Target %d, PUCCH Failure %d, PUSCH Failure %d\n", + RC.nrmac[j]->pusch_target_snrx10, + RC.nrmac[j]->pucch_target_snrx10, + RC.nrmac[j]->pucch_failure_thres, + RC.nrmac[j]->pusch_failure_thres); if (strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_N_PREFERENCE_IDX].strptr), "local_RRC") == 0) { // check number of instances is same as RRC/PDCP @@ -696,7 +754,11 @@ void RCconfig_nr_macrlc() { }else { // other midhaul AssertFatal(1==0,"MACRLC %d: %s unknown southbound midhaul\n",j,*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr)); } - RC.nrmac[j]->ulsch_max_slots_inactivity = *(MacRLC_ParamList.paramarray[j][MACRLC_ULSCH_MAX_SLOTS_INACTIVITY].uptr); + RC.nrmac[j]->ulsch_max_frame_inactivity = *(MacRLC_ParamList.paramarray[j][MACRLC_ULSCH_MAX_FRAME_INACTIVITY].uptr); + RC.nrmac[j]->num_ulprbbl = num_prbbl; + LOG_I(NR_MAC,"Blacklisted PRBS %d\n",num_prbbl); + memcpy(RC.nrmac[j]->ulprbbl,prbbl,275*sizeof(prbbl[0])); + }// for (j=0;j 0 LOG_E(PHY,"No %s configuration found\n", CONFIG_STRING_MACRLC_LIST); @@ -707,83 +769,86 @@ void RCconfig_nr_macrlc() { void config_security(gNB_RRC_INST *rrc) { - paramdef_t logparams_defaults[] = SECURITY_GLOBALPARAMS_DESC; - int ret = config_get(logparams_defaults, - sizeof(logparams_defaults) / sizeof(paramdef_t), + paramdef_t sec_params[] = SECURITY_GLOBALPARAMS_DESC; + int ret = config_get(sec_params, + sizeof(sec_params) / sizeof(paramdef_t), CONFIG_STRING_SECURITY); int i; if (ret < 0) { - LOG_W(RRC, "configuration file does not contain a \"security\" section, applying default parameters (no security)\n"); + LOG_W(RRC, "configuration file does not contain a \"security\" section, applying default parameters (nia2 nea0, integrity disabled for DRBs)\n"); rrc->security.ciphering_algorithms[0] = 0; /* nea0 = no ciphering */ rrc->security.ciphering_algorithms_count = 1; - rrc->security.integrity_algorithms[0] = 0; /* nia0 = no integrity */ - rrc->security.integrity_algorithms_count = 1; + rrc->security.integrity_algorithms[0] = 2; /* nia2 */ + rrc->security.integrity_algorithms[1] = 0; /* nia0 = no integrity, as a fallback (but nia2 should be supported by all UEs) */ + rrc->security.integrity_algorithms_count = 2; + rrc->security.do_drb_ciphering = 1; /* even if nea0 let's activate so that we don't generate cipheringDisabled in pdcp_Config */ + rrc->security.do_drb_integrity = 0; return; } - if (logparams_defaults[SECURITY_CONFIG_CIPHERING_IDX].numelt > 4) { + if (sec_params[SECURITY_CONFIG_CIPHERING_IDX].numelt > 4) { LOG_E(RRC, "too much ciphering algorithms in section \"security\" of the configuration file, maximum is 4\n"); exit(1); } - if (logparams_defaults[SECURITY_CONFIG_INTEGRITY_IDX].numelt > 4) { + if (sec_params[SECURITY_CONFIG_INTEGRITY_IDX].numelt > 4) { LOG_E(RRC, "too much integrity algorithms in section \"security\" of the configuration file, maximum is 4\n"); exit(1); } /* get ciphering algorithms */ rrc->security.ciphering_algorithms_count = 0; - for (i = 0; i < logparams_defaults[SECURITY_CONFIG_CIPHERING_IDX].numelt; i++) { - if (!strcmp(logparams_defaults[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea0")) { + for (i = 0; i < sec_params[SECURITY_CONFIG_CIPHERING_IDX].numelt; i++) { + if (!strcmp(sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea0")) { rrc->security.ciphering_algorithms[rrc->security.ciphering_algorithms_count] = 0; rrc->security.ciphering_algorithms_count++; continue; } - if (!strcmp(logparams_defaults[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea1")) { + if (!strcmp(sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea1")) { rrc->security.ciphering_algorithms[rrc->security.ciphering_algorithms_count] = 1; rrc->security.ciphering_algorithms_count++; continue; } - if (!strcmp(logparams_defaults[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea2")) { + if (!strcmp(sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea2")) { rrc->security.ciphering_algorithms[rrc->security.ciphering_algorithms_count] = 2; rrc->security.ciphering_algorithms_count++; continue; } - if (!strcmp(logparams_defaults[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea3")) { + if (!strcmp(sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea3")) { rrc->security.ciphering_algorithms[rrc->security.ciphering_algorithms_count] = 3; rrc->security.ciphering_algorithms_count++; continue; } LOG_E(RRC, "unknown ciphering algorithm \"%s\" in section \"security\" of the configuration file\n", - logparams_defaults[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i]); + sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i]); exit(1); } /* get integrity algorithms */ rrc->security.integrity_algorithms_count = 0; - for (i = 0; i < logparams_defaults[SECURITY_CONFIG_INTEGRITY_IDX].numelt; i++) { - if (!strcmp(logparams_defaults[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia0")) { + for (i = 0; i < sec_params[SECURITY_CONFIG_INTEGRITY_IDX].numelt; i++) { + if (!strcmp(sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia0")) { rrc->security.integrity_algorithms[rrc->security.integrity_algorithms_count] = 0; rrc->security.integrity_algorithms_count++; continue; } - if (!strcmp(logparams_defaults[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia1")) { + if (!strcmp(sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia1")) { rrc->security.integrity_algorithms[rrc->security.integrity_algorithms_count] = 1; rrc->security.integrity_algorithms_count++; continue; } - if (!strcmp(logparams_defaults[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia2")) { + if (!strcmp(sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia2")) { rrc->security.integrity_algorithms[rrc->security.integrity_algorithms_count] = 2; rrc->security.integrity_algorithms_count++; continue; } - if (!strcmp(logparams_defaults[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia3")) { + if (!strcmp(sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia3")) { rrc->security.integrity_algorithms[rrc->security.integrity_algorithms_count] = 3; rrc->security.integrity_algorithms_count++; continue; } LOG_E(RRC, "unknown integrity algorithm \"%s\" in section \"security\" of the configuration file\n", - logparams_defaults[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i]); + sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i]); exit(1); } @@ -794,9 +859,30 @@ void config_security(gNB_RRC_INST *rrc) } if (rrc->security.integrity_algorithms_count == 0) { - LOG_W(RRC, "no preferred integrity algorithm set in configuration file, applying default parameters (no security)\n"); - rrc->security.integrity_algorithms[0] = 0; /* nia0 = no integrity */ - rrc->security.integrity_algorithms_count = 1; + LOG_W(RRC, "no preferred integrity algorithm set in configuration file, applying default parameters (nia2)\n"); + rrc->security.integrity_algorithms[0] = 2; /* nia2 */ + rrc->security.integrity_algorithms[1] = 0; /* nia0 = no integrity */ + rrc->security.integrity_algorithms_count = 2; + } + + if (!strcmp(*sec_params[SECURITY_CONFIG_DO_DRB_CIPHERING_IDX].strptr, "yes")) { + rrc->security.do_drb_ciphering = 1; + } else if (!strcmp(*sec_params[SECURITY_CONFIG_DO_DRB_CIPHERING_IDX].strptr, "no")) { + rrc->security.do_drb_ciphering = 0; + } else { + LOG_E(RRC, "in configuration file, bad drb_ciphering value '%s', only 'yes' and 'no' allowed\n", + *sec_params[SECURITY_CONFIG_DO_DRB_CIPHERING_IDX].strptr); + exit(1); + } + + if (!strcmp(*sec_params[SECURITY_CONFIG_DO_DRB_INTEGRITY_IDX].strptr, "yes")) { + rrc->security.do_drb_integrity = 1; + } else if (!strcmp(*sec_params[SECURITY_CONFIG_DO_DRB_INTEGRITY_IDX].strptr, "no")) { + rrc->security.do_drb_integrity = 0; + } else { + LOG_E(RRC, "in configuration file, bad drb_integrity value '%s', only 'yes' and 'no' allowed\n", + *sec_params[SECURITY_CONFIG_DO_DRB_INTEGRITY_IDX].strptr); + exit(1); } } @@ -1016,6 +1102,8 @@ void RCconfig_NRRRC(MessageDef *msg_p, uint32_t i, gNB_RRC_INST *rrc) { NRRRC_CONFIGURATION_REQ (msg_p).pdsch_AntennaPorts = *GNBParamList.paramarray[i][GNB_PDSCH_ANTENNAPORTS_IDX].iptr; printf("pusch_AntennaPorts %d\n",*GNBParamList.paramarray[i][GNB_PUSCH_ANTENNAPORTS_IDX].iptr); NRRRC_CONFIGURATION_REQ (msg_p).pusch_AntennaPorts = *GNBParamList.paramarray[i][GNB_PUSCH_ANTENNAPORTS_IDX].iptr; + printf("minTXRXTIMEpdsch %d\n",*GNBParamList.paramarray[i][GNB_MINRXTXTIMEPDSCH_IDX].iptr); + NRRRC_CONFIGURATION_REQ (msg_p).minRXTXTIMEpdsch = *GNBParamList.paramarray[i][GNB_MINRXTXTIMEPDSCH_IDX].iptr; NRRRC_CONFIGURATION_REQ (msg_p).sib1_tda = *GNBParamList.paramarray[i][GNB_SIB1_TDA_IDX].iptr; printf("Do CSI-RS %d\n",*GNBParamList.paramarray[i][GNB_DO_CSIRS_IDX].iptr); NRRRC_CONFIGURATION_REQ (msg_p).do_CSIRS = *GNBParamList.paramarray[i][GNB_DO_CSIRS_IDX].iptr; @@ -1046,7 +1134,6 @@ int RCconfig_nr_gtpu(void ) { char *address = NULL; char *cidr = NULL; char gtpupath[MAX_OPTNAME_SIZE*2 + 8]; - uint8_t gnb_mode = 0; paramdef_t GNBSParams[] = GNBSPARAMS_DESC; paramdef_t NETParams[] = GNBNETPARAMS_DESC; @@ -1064,44 +1151,26 @@ int RCconfig_nr_gtpu(void ) { config_get(NETParams,sizeof(NETParams)/sizeof(paramdef_t),gtpupath); - if (NETParams[0].strptr != NULL) { // SA + if (NETParams[0].strptr != NULL) LOG_I(GTPU, "SA mode \n"); - cidr = gnb_ipv4_address_for_NGU; - gnb_mode = 0; - } else {// NSA + else LOG_I(GTPU, "NSA mode \n"); - cidr = gnb_ipv4_address_for_S1U; - gnb_mode = 1; - } - - address = strtok(cidr, "/"); - - if (address) { - MessageDef *message; - - if (gnb_mode == 1) { // NSA - message = itti_alloc_new_message(TASK_GNB_APP, 0, GTPV1U_ENB_S1_REQ); - AssertFatal(message!=NULL,""); - // IPV4_STR_ADDR_TO_INT_NWBO ( address, RC.gtpv1u_data_g->enb_ip_address_for_S1u_S12_S4_up, "BAD IP ADDRESS FORMAT FOR eNB S1_U !\n" ); - // LOG_I(GTPU,"Configuring GTPu address : %s -> %x\n",address,RC.gtpv1u_data_g->enb_ip_address_for_S1u_S12_S4_up); - IPV4_STR_ADDR_TO_INT_NWBO (address, GTPV1U_ENB_S1_REQ(message).enb_ip_address_for_S1u_S12_S4_up, "BAD IP ADDRESS FORMAT FOR eNB S1_U !\n" ); - LOG_I(GTPU,"Configuring GTPu address : %s -> %x\n",address,GTPV1U_ENB_S1_REQ(message).enb_ip_address_for_S1u_S12_S4_up); - GTPV1U_ENB_S1_REQ(message).enb_port_for_S1u_S12_S4_up = gnb_port_for_S1U; - strcpy(GTPV1U_ENB_S1_REQ(message).addrStr,address); - sprintf(GTPV1U_ENB_S1_REQ(message).portStr,"%d", gnb_port_for_NGU); - } else {// TODO SA - message = itti_alloc_new_message(TASK_GNB_APP, 0, GTPV1U_GNB_NG_REQ); - AssertFatal(message!=NULL,""); - IPV4_STR_ADDR_TO_INT_NWBO (address, GTPV1U_GNB_NG_REQ(message).gnb_ip_address_for_NGu_up, "BAD IP ADDRESS FORMAT FOR gNB NG_U !\n" ); - LOG_I(GTPU,"Configuring GTPu address : %s -> %x\n",address,GTPV1U_GNB_NG_REQ(message).gnb_ip_address_for_NGu_up); - GTPV1U_GNB_NG_REQ(message).gnb_port_for_NGu_up = gnb_port_for_NGU; - strcpy(GTPV1U_GNB_NG_REQ(message).addrStr,address); - sprintf(GTPV1U_GNB_NG_REQ(message).portStr,"%d", gnb_port_for_NGU); - } - itti_send_msg_to_task (TASK_VARIABLE, 0, message); // data model is wrong: gtpu doesn't have enb_id (or module_id) + + cidr = gnb_ipv4_address_for_S1U; + address = strtok(cidr, "/"); + + if (address) { + MessageDef *message; + message = itti_alloc_new_message(TASK_GNB_APP, 0, GTPV1U_REQ); + AssertFatal(message!=NULL,""); + IPV4_STR_ADDR_TO_INT_NWBO (address, GTPV1U_REQ(message).localAddr, "BAD IP ADDRESS FORMAT FOR gNB NG_U !\n" ); + LOG_I(GTPU,"Configuring GTPu address : %s -> %x\n",address,GTPV1U_REQ(message).localAddr); + GTPV1U_REQ(message).localPort = gnb_port_for_NGU; + strcpy(GTPV1U_REQ(message).localAddrStr,address); + sprintf(GTPV1U_REQ(message).localPortStr,"%d", gnb_port_for_NGU); + itti_send_msg_to_task (TASK_VARIABLE, 0, message); // data model is wrong: gtpu doesn't have enb_id (or module_id) } else - LOG_E(GTPU,"invalid address for NGU\n"); - + LOG_E(GTPU,"invalid address for NGU\n"); return 0; } @@ -1938,6 +2007,7 @@ void configure_gnb_du_mac(int inst) { rrc->configuration.pusch_AntennaPorts, rrc->configuration.sib1_tda, rrc->configuration.scc, + NULL, 0, 0, // rnti (NR_CellGroupConfig_t *)NULL diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index ccab98d63c..bf1d12825e 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -119,6 +119,9 @@ typedef enum { #define GNB_CONFIG_STRING_SIB1TDA "sib1_tda" #define GNB_CONFIG_STRING_DOCSIRS "do_CSIRS" #define GNB_CONFIG_STRING_NRCELLID "nr_cellid" +#define GNB_CONFIG_STRING_MINRXTXTIMEPDSCH "min_rxtxtime_pdsch" +#define GNB_CONFIG_STRING_ULPRBBLACKLIST "ul_prbblacklist" + /*-----------------------------------------------------------------------------------------------------------------------------------------*/ /* cell configuration parameters */ @@ -145,7 +148,9 @@ typedef enum { {GNB_CONFIG_STRING_SIB1TDA, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_DOCSIRS, NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_NRCELLID, NULL, 0, u64ptr:NULL, defint64val:1, TYPE_UINT64, 0}, \ -} +{GNB_CONFIG_STRING_MINRXTXTIMEPDSCH, NULL, 0, iptr:NULL, defintval:2, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_ULPRBBLACKLIST, NULL, 0, strptr:NULL, defstrval:"", TYPE_STRING, 0} \ +} #define GNB_GNB_ID_IDX 0 #define GNB_CELL_TYPE_IDX 1 @@ -167,6 +172,8 @@ typedef enum { #define GNB_SIB1_TDA_IDX 17 #define GNB_DO_CSIRS_IDX 18 #define GNB_NRCELLID_IDX 19 +#define GNB_MINRXTXTIMEPDSCH_IDX 20 +#define GNB_ULPRBBLACKLIST_IDX 21 #define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD} #define GNBPARAMS_CHECK { \ @@ -463,10 +470,12 @@ typedef enum { /*----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ /* security configuration */ /*----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ -#define CONFIG_STRING_SECURITY "security" +#define CONFIG_STRING_SECURITY "security" -#define SECURITY_CONFIG_CIPHERING "ciphering_algorithms" -#define SECURITY_CONFIG_INTEGRITY "integrity_algorithms" +#define SECURITY_CONFIG_CIPHERING "ciphering_algorithms" +#define SECURITY_CONFIG_INTEGRITY "integrity_algorithms" +#define SECURITY_CONFIG_DO_DRB_CIPHERING "drb_ciphering" +#define SECURITY_CONFIG_DO_DRB_INTEGRITY "drb_integrity" /*----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ /* security configuration */ @@ -475,10 +484,15 @@ typedef enum { #define SECURITY_GLOBALPARAMS_DESC { \ {SECURITY_CONFIG_CIPHERING, "preferred ciphering algorithms\n", 0, strlistptr:NULL, defstrlistval:NULL, TYPE_STRINGLIST, 0}, \ {SECURITY_CONFIG_INTEGRITY, "preferred integrity algorithms\n", 0, strlistptr:NULL, defstrlistval:NULL, TYPE_STRINGLIST, 0}, \ + {SECURITY_CONFIG_DO_DRB_CIPHERING, "use ciphering for DRBs", 0, strptr:NULL, defstrval:"yes", TYPE_STRING, 0}, \ + {SECURITY_CONFIG_DO_DRB_INTEGRITY, "use integrity for DRBs", 0, strptr:NULL, defstrval:"no", TYPE_STRING, 0}, \ } -#define SECURITY_CONFIG_CIPHERING_IDX 0 -#define SECURITY_CONFIG_INTEGRITY_IDX 1 +#define SECURITY_CONFIG_CIPHERING_IDX 0 +#define SECURITY_CONFIG_INTEGRITY_IDX 1 +#define SECURITY_CONFIG_DO_DRB_CIPHERING_IDX 2 +#define SECURITY_CONFIG_DO_DRB_INTEGRITY_IDX 3 + /*----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ #endif diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_compute_tbs_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_compute_tbs_common.c index 996c2fbe27..4fcbd322db 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_compute_tbs_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_compute_tbs_common.c @@ -51,7 +51,7 @@ uint32_t nr_compute_tbs(uint16_t Qm, uint32_t Ninfo, Np_info, C; uint8_t n, scale; - LOG_D(MAC,"nb_symb_sch %d, nb_dmrs_prb %d, nb_rb_oh %d\n",nb_symb_sch,nb_dmrs_prb,nb_rb_oh); + LOG_D(NR_MAC,"nb_symb_sch %d, nb_dmrs_prb %d, nb_rb_oh %d\n",nb_symb_sch,nb_dmrs_prb,nb_rb_oh); nbp_re = NR_NB_SC_PER_RB * nb_symb_sch - nb_dmrs_prb - nb_rb_oh; nb_re = min(156, nbp_re) * nb_rb; @@ -59,6 +59,7 @@ uint32_t nr_compute_tbs(uint16_t Qm, // Intermediate number of information bits Ninfo = ((nb_re * R * Qm * Nl)>>scale)>>tb_scaling; + if (Ninfo <=3824) { n = max(3, floor(log2(Ninfo)) - 6); Np_info = max(24, (Ninfo>>n)<nrofCandidates->aggregationLevel1 != NR_SearchSpace__nrofCandidates__aggregationLevel1_n0) { - *aggregation_level = 1; - *nr_of_candidates = ss->nrofCandidates->aggregationLevel1; - } - if (ss->nrofCandidates->aggregationLevel2 != NR_SearchSpace__nrofCandidates__aggregationLevel2_n0) { - *aggregation_level = 2; - *nr_of_candidates = ss->nrofCandidates->aggregationLevel2; - } - if (ss->nrofCandidates->aggregationLevel4 != NR_SearchSpace__nrofCandidates__aggregationLevel4_n0) { - *aggregation_level = 4; - *nr_of_candidates = ss->nrofCandidates->aggregationLevel4; - } - if (ss->nrofCandidates->aggregationLevel8 != NR_SearchSpace__nrofCandidates__aggregationLevel8_n0) { - *aggregation_level = 8; - *nr_of_candidates = ss->nrofCandidates->aggregationLevel8; - } - if (ss->nrofCandidates->aggregationLevel16 != NR_SearchSpace__nrofCandidates__aggregationLevel16_n0) { - *aggregation_level = 16; - *nr_of_candidates = ss->nrofCandidates->aggregationLevel16; - } - // n8 does not correspont to a value of 8 but 7, the following corrects this - if(*nr_of_candidates == 7) - *nr_of_candidates = 8; + NR_SearchSpace_t *ss, + int L) { + AssertFatal(L>=1 && L<=16,"L %d not ok\n",L); + *nr_of_candidates = 0; + switch(L) { + case 1: + if (ss->nrofCandidates->aggregationLevel1 != NR_SearchSpace__nrofCandidates__aggregationLevel1_n0) { + *aggregation_level = 1; + *nr_of_candidates = ss->nrofCandidates->aggregationLevel1; + } + break; + case 2: + if (ss->nrofCandidates->aggregationLevel2 != NR_SearchSpace__nrofCandidates__aggregationLevel2_n0) { + *aggregation_level = 2; + *nr_of_candidates = ss->nrofCandidates->aggregationLevel2; + } + break; + case 4: + if (ss->nrofCandidates->aggregationLevel4 != NR_SearchSpace__nrofCandidates__aggregationLevel4_n0) { + *aggregation_level = 4; + *nr_of_candidates = ss->nrofCandidates->aggregationLevel4; + } + break; + case 8: + if (ss->nrofCandidates->aggregationLevel8 != NR_SearchSpace__nrofCandidates__aggregationLevel8_n0) { + *aggregation_level = 8; + *nr_of_candidates = ss->nrofCandidates->aggregationLevel8; + } + break; + case 16: + if (ss->nrofCandidates->aggregationLevel16 != NR_SearchSpace__nrofCandidates__aggregationLevel16_n0) { + *aggregation_level = 16; + *nr_of_candidates = ss->nrofCandidates->aggregationLevel16; + } + break; + } } @@ -1519,7 +1556,7 @@ int get_nr_prach_occasion_info_from_index(uint8_t index, if (table_6_3_3_2_3_prachConfig_Index[index][1] != -1) format2 = (uint8_t) table_6_3_3_2_3_prachConfig_Index[index][1]; *format = ((uint8_t) table_6_3_3_2_3_prachConfig_Index[index][0]) | (format2<<8); - LOG_I(MAC,"Getting Total PRACH info from index %d (col %lu ) absoluteFrequencyPointA %u mu %u frame_type %u start_symbol %u N_t_slot %u N_dur %u N_RA_sfn = %u\n", + LOG_D(NR_MAC,"Getting Total PRACH info from index %d (col %lu ) absoluteFrequencyPointA %u mu %u frame_type %u start_symbol %u N_t_slot %u N_dur %u N_RA_sfn = %u\n", index, table_6_3_3_2_3_prachConfig_Index[index][6], pointa, mu, @@ -1562,60 +1599,6 @@ int get_nr_prach_occasion_info_from_index(uint8_t index, } -uint8_t get_nr_prach_duration(uint8_t prach_format){ - - switch(prach_format){ - - case 0: // format 0 - return 0; - - case 1: // format 1 - return 0; - - case 2: // format 2 - return 0; - - case 3: // format 3 - return 0; - - case 4: // format A1 - return 2; - - case 5: // format A2 - return 4; - - case 6: // format A3 - return 6; - - case 7: // format B1 - return 2; - - case 8: // format B4 - return 12; - - case 9: // format C0 - return 2; - - case 10: // format C2 - return 6; - - case 11: // format A1/B1 - return 2; - - case 12: // format A2/B2 - return 4; - - case 13: // format A3/B3 - return 6; - - default : - AssertFatal(1==0,"Invalid Prach format\n"); - break; - - } - -} - int get_nr_prach_info_from_index(uint8_t index, int frame, int slot, @@ -1970,170 +1953,6 @@ int32_t table_6_4_1_1_3_4_pusch_dmrs_positions_l [12][8] = { {0, 3072, -1, -1, 3, 1539, -1, -1}, //14 // (DMRS l' position) }; -// Returns the corresponding row index of the NR table -int get_nr_table_idx(int nr_bandP, uint8_t scs_index) -{ - int i, j; - int scs_khz = 15 << scs_index; - int supplementary_bands[] = {29,75,76,80,81,82,83,84,86,89,95}; - size_t s = sizeof(supplementary_bands)/sizeof(supplementary_bands[0]); - - for(j = 0; j < s; j++){ - if (nr_bandP == supplementary_bands[j]) - AssertFatal(0 == 1, "Band %d is a supplementary band (%d). This is not supported yet.\n", nr_bandP, supplementary_bands[j]); - } - - AssertFatal(nr_bandP <= nr_bandtable[nr_bandtable_size-1].band, "NR band %d exceeds NR bands table maximum limit %d\n", nr_bandP, nr_bandtable[nr_bandtable_size-1].band); - for (i = 0; i < nr_bandtable_size && nr_bandtable[i].band != nr_bandP; i++); - - // selection of correct Deltaf raster according to SCS - if ((nr_bandtable[i].deltaf_raster != 100) && (nr_bandtable[i].deltaf_raster != scs_khz)) - i++; - - LOG_D(PHY, "NR band table index %d (Band %d, dl_min %lu, ul_min %lu)\n", i, nr_bandtable[i].band, nr_bandtable[i].dl_min,nr_bandtable[i].ul_min); - - return i; -} - -// Computes the duplex spacing (either positive or negative) in KHz -int32_t get_delta_duplex(int nr_bandP, uint8_t scs_index) -{ - int nr_table_idx = get_nr_table_idx(nr_bandP, scs_index); - - int32_t delta_duplex = (nr_bandtable[nr_table_idx].ul_min - nr_bandtable[nr_table_idx].dl_min); - - LOG_I(PHY, "NR band duplex spacing is %d KHz (nr_bandtable[%d].band = %d)\n", delta_duplex, nr_table_idx, nr_bandtable[nr_table_idx].band); - - return delta_duplex; -} - -lte_frame_type_t get_frame_type(uint16_t current_band, uint8_t scs_index) -{ - lte_frame_type_t current_type; - int32_t delta_duplex = get_delta_duplex(current_band, scs_index); - - if (delta_duplex == 0) - current_type = TDD; - else - current_type = FDD; - - LOG_I(MAC, "NR band %d, duplex mode %s, duplex spacing = %d KHz\n", current_band, duplex_mode[current_type], delta_duplex); - - return current_type; -} - -uint16_t config_bandwidth(int mu, int nb_rb, int nr_band) -{ - - if (nr_band < 100) { //FR1 - switch(mu) { - case 0 : - if (nb_rb<=25) - return 5; - if (nb_rb<=52) - return 10; - if (nb_rb<=79) - return 15; - if (nb_rb<=106) - return 20; - if (nb_rb<=133) - return 25; - if (nb_rb<=160) - return 30; - if (nb_rb<=216) - return 40; - if (nb_rb<=270) - return 50; - AssertFatal(1==0,"Number of DL resource blocks %d undefined for mu %d and band %d\n", nb_rb, mu, nr_band); - break; - case 1 : - if (nb_rb<=11) - return 5; - if (nb_rb<=24) - return 10; - if (nb_rb<=38) - return 15; - if (nb_rb<=51) - return 20; - if (nb_rb<=65) - return 25; - if (nb_rb<=78) - return 30; - if (nb_rb<=106) - return 40; - if (nb_rb<=133) - return 50; - if (nb_rb<=162) - return 60; - if (nb_rb<=189) - return 70; - if (nb_rb<=217) - return 80; - if (nb_rb<=245) - return 90; - if (nb_rb<=273) - return 100; - AssertFatal(1==0,"Number of DL resource blocks %d undefined for mu %d and band %d\n", nb_rb, mu, nr_band); - break; - case 2 : - if (nb_rb<=11) - return 10; - if (nb_rb<=18) - return 15; - if (nb_rb<=24) - return 20; - if (nb_rb<=31) - return 25; - if (nb_rb<=38) - return 30; - if (nb_rb<=51) - return 40; - if (nb_rb<=65) - return 50; - if (nb_rb<=79) - return 60; - if (nb_rb<=93) - return 70; - if (nb_rb<=107) - return 80; - if (nb_rb<=121) - return 90; - if (nb_rb<=135) - return 100; - AssertFatal(1==0,"Number of DL resource blocks %d undefined for mu %d and band %d\n", nb_rb, mu, nr_band); - break; - default: - AssertFatal(1==0,"Numerology %d undefined for band %d in FR1\n", mu,nr_band); - } - } - else { - switch(mu) { - case 2 : - if (nb_rb<=66) - return 50; - if (nb_rb<=132) - return 100; - if (nb_rb<=264) - return 200; - AssertFatal(1==0,"Number of DL resource blocks %d undefined for mu %d and band %d\n", nb_rb, mu, nr_band); - break; - case 3 : - if (nb_rb<=32) - return 50; - if (nb_rb<=66) - return 100; - if (nb_rb<=132) - return 200; - if (nb_rb<=264) - return 400; - AssertFatal(1==0,"Number of DL resource blocks %d undefined for mu %d and band %d\n", nb_rb, mu, nr_band); - break; - default: - AssertFatal(1==0,"Numerology %d undefined for band %d in FR1\n", mu,nr_band); - } - } - -} void get_delta_arfcn(int i, uint32_t nrarfcn, uint64_t N_OFFs){ @@ -2154,7 +1973,7 @@ uint32_t to_nrarfcn(int nr_bandP, uint32_t nrarfcn; int i = get_nr_table_idx(nr_bandP, scs_index); - LOG_I(MAC,"Searching for nr band %d DL Carrier frequency %llu bw %u\n",nr_bandP,(long long unsigned int)dl_CarrierFreq,bw); + LOG_I(NR_MAC,"Searching for nr band %d DL Carrier frequency %llu bw %u\n",nr_bandP,(long long unsigned int)dl_CarrierFreq,bw); AssertFatal(dl_CarrierFreq_by_1k >= nr_bandtable[i].dl_min, "Band %d, bw %u : DL carrier frequency %llu kHz < %llu\n", @@ -2231,14 +2050,14 @@ uint64_t from_nrarfcn(int nr_bandP, } } - LOG_D(MAC, "Frequency from NR-ARFCN for N_OFFs %lu, duplex spacing %d KHz, deltaFglobal %d KHz\n", N_OFFs, delta_duplex, deltaFglobal); + LOG_D(NR_MAC, "Frequency from NR-ARFCN for N_OFFs %lu, duplex spacing %d KHz, deltaFglobal %d KHz\n", N_OFFs, delta_duplex, deltaFglobal); AssertFatal(nrarfcn >= N_OFFs,"nrarfcn %u < N_OFFs[%d] %llu\n", nrarfcn, nr_bandtable[i].band, (long long unsigned int)N_OFFs); get_delta_arfcn(i, nrarfcn, N_OFFs); frequency = 1000*(F_REF_Offs_khz + (nrarfcn - N_REF_Offs) * deltaFglobal); - LOG_I(MAC, "Computing frequency (pointA %llu => %llu KHz (freq_min %llu KHz, NR band %d N_OFFs %llu))\n", + LOG_I(NR_MAC, "Computing frequency (pointA %llu => %llu KHz (freq_min %llu KHz, NR band %d N_OFFs %llu))\n", (unsigned long long)nrarfcn, (unsigned long long)frequency/1000, (unsigned long long)freq_min, @@ -2505,13 +2324,7 @@ static inline uint8_t get_table_idx(uint8_t mcs_table, uint8_t dci_format, uint8 return 1; } -int get_num_dmrs(uint16_t dmrs_mask ) { - int num_dmrs=0; - - for (int i=0;i<16;i++) num_dmrs+=((dmrs_mask>>i)&1); - return(num_dmrs); -} /* returns the total DMRS symbols in a slot*/ uint8_t get_num_dmrs_symbols(NR_PDSCH_Config_t *pdsch_Config,int dmrs_TypeA_Position,int NrOfSymbols, int startSymbol, int mappingtype){ return get_num_dmrs(fill_dmrs_mask(pdsch_Config,dmrs_TypeA_Position,NrOfSymbols, startSymbol, mappingtype)); @@ -2583,7 +2396,7 @@ int32_t get_l_prime(uint8_t duration_in_symbols, uint8_t mapping_type, pusch_dmr uint8_t row, colomn; int32_t l_prime; - LOG_D(MAC, "PUSCH: NrofSymbols:%d, startSymbol:%d, mappingtype:%d, dmrs_TypeA_Position:%d\n", duration_in_symbols, start_symbol, mapping_type, dmrs_typeA_position); + LOG_D(NR_MAC, "PUSCH: NrofSymbols:%d, startSymbol:%d, mappingtype:%d, dmrs_TypeA_Position:%d\n", duration_in_symbols, start_symbol, mapping_type, dmrs_typeA_position); // Section 6.4.1.1.3 in Spec 38.211 // For PDSCH Mapping TypeA, ld is duration between first OFDM of the slot and last OFDM symbol of the scheduled PUSCH resources @@ -2610,7 +2423,7 @@ int32_t get_l_prime(uint8_t duration_in_symbols, uint8_t mapping_type, pusch_dmr l0 = 1<=0,"invalid l_prime < 0\n"); l_prime = (mapping_type == typeA) ? (l_prime | l0) : (l_prime << start_symbol); @@ -2653,7 +2466,7 @@ uint8_t get_L_ptrs(uint8_t mcs1, uint8_t mcs2, uint8_t mcs3, uint8_t I_mcs, uint else if (I_mcs >= mcs3 && I_mcs < mcs4) return 0; else { - LOG_I(PHY, "PT-RS time-density determination is obtained from the DCI for the same transport block in the initial transmission\n"); + LOG_D(NR_MAC, "PT-RS time-density determination is obtained from the DCI for the same transport block in the initial transmission\n"); return -1; } } @@ -2686,22 +2499,22 @@ uint8_t get_K_ptrs(uint16_t nrb0, uint16_t nrb1, uint16_t N_RB) { // - "UE procedure for applying transform precoding on PUSCH" uint8_t get_transformPrecoding(const NR_BWP_UplinkCommon_t *initialUplinkBWP, const NR_PUSCH_Config_t *pusch_config, - const NR_BWP_Uplink_t *ubwp, + const NR_BWP_UplinkDedicated_t *ubwp, uint8_t *dci_format, int rnti_type, uint8_t configuredGrant){ if (configuredGrant) { - if (ubwp->bwp_Dedicated->configuredGrantConfig) { - if (ubwp->bwp_Dedicated->configuredGrantConfig->choice.setup->transformPrecoder) { - return *ubwp->bwp_Dedicated->configuredGrantConfig->choice.setup->transformPrecoder; + if (ubwp->configuredGrantConfig) { + if (ubwp->configuredGrantConfig->choice.setup->transformPrecoder) { + return *ubwp->configuredGrantConfig->choice.setup->transformPrecoder; } } } if (rnti_type != NR_RNTI_RA && rnti_type != NR_RNTI_TC) { if (*dci_format != NR_UL_DCI_FORMAT_0_0) { - if (pusch_config->transformPrecoder != NULL) { + if (pusch_config && pusch_config->transformPrecoder != NULL) { return *pusch_config->transformPrecoder; } } @@ -2718,7 +2531,8 @@ uint8_t get_transformPrecoding(const NR_BWP_UplinkCommon_t *initialUplinkBWP, return -1; } -uint16_t nr_dci_size(const NR_BWP_UplinkCommon_t *initialUplinkBWP, +uint16_t nr_dci_size(const NR_BWP_DownlinkCommon_t *initialDownlinkBWP, + const NR_BWP_UplinkCommon_t *initialUplinkBWP, const NR_CellGroupConfig_t *cg, dci_pdu_rel15_t *dci_pdu, nr_dci_format_t format, @@ -2732,27 +2546,47 @@ uint16_t nr_dci_size(const NR_BWP_UplinkCommon_t *initialUplinkBWP, int num_entries = 0; int pusch_antenna_ports = 1; // TODO hardcoded number of antenna ports for pusch - NR_BWP_Downlink_t *bwp = NULL; - NR_BWP_Uplink_t *ubwp = NULL; - NR_PDSCH_Config_t *pdsch_config = NULL; - NR_PUSCH_Config_t *pusch_Config = NULL; - NR_SRS_Config_t *srs_config = NULL; + const NR_BWP_DownlinkDedicated_t *bwpd = NULL; + const NR_BWP_UplinkDedicated_t *ubwpd = NULL; + const NR_BWP_DownlinkCommon_t *bwpc = NULL; + const NR_BWP_UplinkCommon_t *ubwpc = NULL; + const NR_PDSCH_Config_t *pdsch_Config = NULL; + const NR_PUSCH_Config_t *pusch_Config = NULL; + const NR_PUCCH_Config_t *pucch_Config = NULL; + const NR_PDCCH_Config_t *pdcch_Config = NULL; + const NR_SRS_Config_t *srs_config = NULL; if(bwp_id > 0) { AssertFatal(cg!=NULL,"Cellgroup is null and bwp_id!=0"); - bwp=cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]; - ubwp=cg->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1]; - pdsch_config = bwp->bwp_Dedicated->pdsch_Config->choice.setup; - pusch_Config = ubwp->bwp_Dedicated->pusch_Config->choice.setup; - srs_config = ubwp->bwp_Dedicated->srs_Config->choice.setup; + bwpd=cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Dedicated; + bwpc=cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Common; + ubwpd=cg->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Dedicated; + ubwpc=cg->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Common; + pdsch_Config = (bwpd->pdsch_Config) ? bwpd->pdsch_Config->choice.setup : NULL; + pdcch_Config = (bwpd->pdcch_Config) ? bwpd->pdcch_Config->choice.setup : NULL; + pucch_Config = (ubwpd->pucch_Config) ? ubwpd->pucch_Config->choice.setup : NULL; + pusch_Config = (ubwpd->pusch_Config) ? ubwpd->pusch_Config->choice.setup : NULL; + srs_config = (ubwpd->srs_Config) ? ubwpd->srs_Config->choice.setup : NULL; + } + else if (cg){ + bwpd=cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP; + bwpc=initialDownlinkBWP; + ubwpd=cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; + ubwpc=initialUplinkBWP; + pdsch_Config = (bwpd->pdsch_Config) ? bwpd->pdsch_Config->choice.setup : NULL; + pdcch_Config = (bwpd->pdcch_Config) ? bwpd->pdcch_Config->choice.setup : NULL; + pucch_Config = (ubwpd->pucch_Config) ? ubwpd->pucch_Config->choice.setup : NULL; + pusch_Config = (ubwpd->pusch_Config) ? ubwpd->pusch_Config->choice.setup : NULL; + srs_config = (ubwpd->srs_Config) ? ubwpd->srs_Config->choice.setup: NULL; } + int n_ul_bwp=1,n_dl_bwp=1; switch(format) { /*Only sizes for 0_0 and 1_0 are correct at the moment*/ case NR_UL_DCI_FORMAT_0_0: /// fixed: Format identifier 1, Hop flag 1, MCS 5, NDI 1, RV 2, HARQ PID 4, PUSCH TPC 2 Time Domain assgnmt 4 --20 size += 20; size += (uint8_t)ceil( log2( (N_RB*(N_RB+1))>>1 ) ); // Freq domain assignment -- hopping scenario to be updated - size += nr_dci_size(initialUplinkBWP,cg,dci_pdu,NR_DL_DCI_FORMAT_1_0, rnti_type, N_RB, bwp_id) - size; // Padding to match 1_0 size + size += nr_dci_size(initialDownlinkBWP,initialUplinkBWP,cg,dci_pdu,NR_DL_DCI_FORMAT_1_0, rnti_type, N_RB, bwp_id) - size; // Padding to match 1_0 size // UL/SUL indicator assumed to be 0 break; @@ -2770,56 +2604,71 @@ uint16_t nr_dci_size(const NR_BWP_UplinkCommon_t *initialUplinkBWP, size += dci_pdu->ul_sul_indicator.nbits; } // BWP Indicator - uint8_t n_ul_bwp = cg->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count; + n_ul_bwp = 0; + if (cg->spCellConfig->spCellConfigDedicated->uplinkConfig && + cg->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList) + n_ul_bwp = cg->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count; if (n_ul_bwp < 2) dci_pdu->bwp_indicator.nbits = n_ul_bwp; else dci_pdu->bwp_indicator.nbits = 2; size += dci_pdu->bwp_indicator.nbits; // Freq domain assignment - if (cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pusch_Config->choice.setup->rbg_Size != NULL) - rbg_size_config = 1; - else - rbg_size_config = 0; - numRBG = getNRBG(NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE), - NRRIV2PRBOFFSET(ubwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE), - rbg_size_config); - if (pusch_Config->resourceAllocation == 0) - dci_pdu->frequency_domain_assignment.nbits = numRBG; - else if (pusch_Config->resourceAllocation == 1) - dci_pdu->frequency_domain_assignment.nbits = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) ); - else - dci_pdu->frequency_domain_assignment.nbits = ((int)ceil( log2( (N_RB*(N_RB+1))>>1 ) )>numRBG) ? (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) )+1 : numRBG+1; + if (pusch_Config) { + if (pusch_Config->rbg_Size != NULL) + rbg_size_config = 1; + else + rbg_size_config = 0; + numRBG = getNRBG(NRRIV2BW(ubwpc->genericParameters.locationAndBandwidth, MAX_BWP_SIZE), + NRRIV2PRBOFFSET(ubwpc->genericParameters.locationAndBandwidth, MAX_BWP_SIZE), + rbg_size_config); + if (pusch_Config->resourceAllocation == 0) + dci_pdu->frequency_domain_assignment.nbits = numRBG; + else if (pusch_Config->resourceAllocation == 1) + dci_pdu->frequency_domain_assignment.nbits = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) ); + else + dci_pdu->frequency_domain_assignment.nbits = ((int)ceil( log2( (N_RB*(N_RB+1))>>1 ) )>numRBG) ? (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) )+1 : numRBG+1; + } + else dci_pdu->frequency_domain_assignment.nbits = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) ); + LOG_D(NR_MAC,"PUSCH Frequency Domain Assignment nbits %d, N_RB %d\n",dci_pdu->frequency_domain_assignment.nbits,N_RB); size += dci_pdu->frequency_domain_assignment.nbits; // Time domain assignment - if (pusch_Config->pusch_TimeDomainAllocationList==NULL) { - if (ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList==NULL) + if (pusch_Config==NULL || pusch_Config->pusch_TimeDomainAllocationList==NULL) { + if (ubwpc->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList==NULL) num_entries = 16; // num of entries in default table else - num_entries = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.count; + num_entries = ubwpc->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.count; } else num_entries = pusch_Config->pusch_TimeDomainAllocationList->choice.setup->list.count; dci_pdu->time_domain_assignment.nbits = (int)ceil(log2(num_entries)); + LOG_D(NR_MAC,"PUSCH Time Domain Allocation nbits %d, pusch_Config %p\n",dci_pdu->time_domain_assignment.nbits,pusch_Config); size += dci_pdu->time_domain_assignment.nbits; // Frequency Hopping flag - if ((pusch_Config->frequencyHopping!=NULL) && (pusch_Config->resourceAllocation != NR_PUSCH_Config__resourceAllocation_resourceAllocationType0)) { + if (pusch_Config && + pusch_Config->frequencyHopping!=NULL && + pusch_Config->resourceAllocation != NR_PUSCH_Config__resourceAllocation_resourceAllocationType0) { dci_pdu->frequency_hopping_flag.nbits = 1; size += 1; } // 1st DAI - if (cg->physicalCellGroupConfig->pdsch_HARQ_ACK_Codebook==NR_PhysicalCellGroupConfig__pdsch_HARQ_ACK_Codebook_dynamic) + if (cg->physicalCellGroupConfig && + cg->physicalCellGroupConfig->pdsch_HARQ_ACK_Codebook==NR_PhysicalCellGroupConfig__pdsch_HARQ_ACK_Codebook_dynamic) dci_pdu->dai[0].nbits = 2; else dci_pdu->dai[0].nbits = 1; size += dci_pdu->dai[0].nbits; + LOG_D(NR_MAC,"DAI1 nbits %d\n",dci_pdu->dai[0].nbits); // 2nd DAI - if (cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup->codeBlockGroupTransmission != NULL) { //TODO not sure about that + if (cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig && + cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup->codeBlockGroupTransmission != NULL) { //TODO not sure about that dci_pdu->dai[1].nbits = 2; size += dci_pdu->dai[1].nbits; } // SRS resource indicator - if (pusch_Config->txConfig != NULL){ + if (srs_config && + pusch_Config && + pusch_Config->txConfig != NULL){ int count=0; if (*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook){ for (int i=0; isrs_ResourceSetToAddModList->list.count; i++) { @@ -2834,7 +2683,8 @@ uint16_t nr_dci_size(const NR_BWP_UplinkCommon_t *initialUplinkBWP, else { int lmin,Lmax = 0; int lsum = 0; - if ( cg->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig != NULL) { + if ( cg->spCellConfig->spCellConfigDedicated->uplinkConfig && + cg->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig != NULL) { if ( cg->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers != NULL) Lmax = *cg->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers; else @@ -2854,11 +2704,13 @@ uint16_t nr_dci_size(const NR_BWP_UplinkCommon_t *initialUplinkBWP, dci_pdu->srs_resource_indicator.nbits = (int)ceil(log2(lsum)); size += dci_pdu->srs_resource_indicator.nbits; } - } + } else dci_pdu->srs_resource_indicator.nbits = 0; + LOG_D(NR_MAC,"dci_pdu->srs_resource_indicator.nbits %d\n",dci_pdu->srs_resource_indicator.nbits); // Precoding info and number of layers - long transformPrecoder = get_transformPrecoding(initialUplinkBWP, pusch_Config, ubwp, (uint8_t*)&format, rnti_type, 0); - - if (pusch_Config->txConfig != NULL){ + long transformPrecoder = get_transformPrecoding(initialUplinkBWP, pusch_Config, ubwpd, (uint8_t*)&format, rnti_type, 0); + dci_pdu->precoding_information.nbits=0; + if (pusch_Config && + pusch_Config->txConfig != NULL){ if (*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook){ if (pusch_antenna_ports > 1) { if (pusch_antenna_ports == 4) { @@ -2882,15 +2734,18 @@ uint16_t nr_dci_size(const NR_BWP_UplinkCommon_t *initialUplinkBWP, } } size += dci_pdu->precoding_information.nbits; + LOG_D(NR_MAC,"dci_pdu->precoding_informaiton.nbits=%d\n",dci_pdu->precoding_information.nbits); // Antenna ports NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = NULL; int xa=0; int xb=0; - if(pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA != NULL){ + if(pusch_Config && + pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA != NULL){ NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup; xa = ul_ant_bits(NR_DMRS_UplinkConfig,transformPrecoder); } - if(pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB != NULL){ + if(pusch_Config && + pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB != NULL){ NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup; xb = ul_ant_bits(NR_DMRS_UplinkConfig,transformPrecoder); } @@ -2899,6 +2754,7 @@ uint16_t nr_dci_size(const NR_BWP_UplinkCommon_t *initialUplinkBWP, else dci_pdu->antenna_ports.nbits = xb; size += dci_pdu->antenna_ports.nbits; + LOG_D(NR_MAC,"dci_pdu->antenna_ports.nbits = %d\n",dci_pdu->antenna_ports.nbits); // SRS request if (cg->spCellConfig->spCellConfigDedicated->supplementaryUplink==NULL) dci_pdu->srs_request.nbits = 2; @@ -2913,20 +2769,26 @@ uint16_t nr_dci_size(const NR_BWP_UplinkCommon_t *initialUplinkBWP, } } // CBGTI - if (cg->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->codeBlockGroupTransmission != NULL) { + if (cg->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig && + cg->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->codeBlockGroupTransmission != NULL) { int num = cg->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->codeBlockGroupTransmission->choice.setup->maxCodeBlockGroupsPerTransportBlock; dci_pdu->cbgti.nbits = 2 + (num<<1); size += dci_pdu->cbgti.nbits; } // PTRS - DMRS association - if ( (NR_DMRS_UplinkConfig->phaseTrackingRS == NULL && transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) || - transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled || (*pusch_Config->maxRank==1) ) + if ( (NR_DMRS_UplinkConfig && + NR_DMRS_UplinkConfig->phaseTrackingRS == NULL && + transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) || + transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled || + (pusch_Config && pusch_Config->maxRank && + *pusch_Config->maxRank==1) ) dci_pdu->ptrs_dmrs_association.nbits = 0; else dci_pdu->ptrs_dmrs_association.nbits = 2; size += dci_pdu->ptrs_dmrs_association.nbits; // beta offset indicator - if (pusch_Config->uci_OnPUSCH!=NULL){ + if (pusch_Config && + pusch_Config->uci_OnPUSCH!=NULL){ if (pusch_Config->uci_OnPUSCH->choice.setup->betaOffsets->present == NR_UCI_OnPUSCH__betaOffsets_PR_dynamic) { dci_pdu->beta_offset_indicator.nbits = 2; size += dci_pdu->beta_offset_indicator.nbits; @@ -2950,6 +2812,7 @@ uint16_t nr_dci_size(const NR_BWP_UplinkCommon_t *initialUplinkBWP, break; case NR_DL_DCI_FORMAT_1_1: + LOG_D(NR_MAC,"DCI_FORMAT 1_1 : pdsch_Config %p, pucch_Config %p\n",pdsch_Config,pucch_Config); // General note: 0 bits condition is ignored as default nbits is 0. // Format identifier size = 1; @@ -2958,89 +2821,105 @@ uint16_t nr_dci_size(const NR_BWP_UplinkCommon_t *initialUplinkBWP, dci_pdu->carrier_indicator.nbits=3; size += dci_pdu->carrier_indicator.nbits; } + // BWP Indicator - uint8_t n_dl_bwp = cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count; + n_dl_bwp = 0; + if (cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList) + n_dl_bwp = cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count; if (n_dl_bwp < 2) dci_pdu->bwp_indicator.nbits = n_dl_bwp; else dci_pdu->bwp_indicator.nbits = 2; size += dci_pdu->bwp_indicator.nbits; // Freq domain assignment - rbg_size_config = cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->rbg_Size; - numRBG = getNRBG(NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE), - NRRIV2PRBOFFSET(bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE), + if (pdsch_Config) rbg_size_config = pdsch_Config->rbg_Size; + else rbg_size_config = 0; + + numRBG = getNRBG(NRRIV2BW(bwpc->genericParameters.locationAndBandwidth, MAX_BWP_SIZE), + NRRIV2PRBOFFSET(bwpc->genericParameters.locationAndBandwidth, MAX_BWP_SIZE), rbg_size_config); - if (pdsch_config->resourceAllocation == 0) - dci_pdu->frequency_domain_assignment.nbits = numRBG; - else if (pdsch_config->resourceAllocation == 1) - dci_pdu->frequency_domain_assignment.nbits = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) ); + if (pdsch_Config && pdsch_Config->resourceAllocation == 0) + dci_pdu->frequency_domain_assignment.nbits = numRBG; + else if (pdsch_Config == NULL || pdsch_Config->resourceAllocation == 1) + dci_pdu->frequency_domain_assignment.nbits = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) ); else - dci_pdu->frequency_domain_assignment.nbits = ((int)ceil( log2( (N_RB*(N_RB+1))>>1 ) )>numRBG) ? (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) )+1 : numRBG+1; + dci_pdu->frequency_domain_assignment.nbits = ((int)ceil( log2( (N_RB*(N_RB+1))>>1 ) )>numRBG) ? (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) )+1 : numRBG+1; size += dci_pdu->frequency_domain_assignment.nbits; + LOG_D(NR_MAC,"dci_pdu->frequency_domain_assignment.nbits %d (N_RB %d)\n",dci_pdu->frequency_domain_assignment.nbits,N_RB); // Time domain assignment (see table 5.1.2.1.1-1 in 38.214 - if (pdsch_config->pdsch_TimeDomainAllocationList==NULL) { - if (bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList==NULL) + if (pdsch_Config == NULL || pdsch_Config->pdsch_TimeDomainAllocationList==NULL) { + if (bwpc->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList==NULL) num_entries = 16; // num of entries in default table else - num_entries = bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.count; + num_entries = bwpc->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.count; } else - num_entries = pdsch_config->pdsch_TimeDomainAllocationList->choice.setup->list.count; + num_entries = pdsch_Config->pdsch_TimeDomainAllocationList->choice.setup->list.count; dci_pdu->time_domain_assignment.nbits = (int)ceil(log2(num_entries)); + LOG_D(NR_MAC,"pdsch tda.nbits= %d\n",dci_pdu->time_domain_assignment.nbits); size += dci_pdu->time_domain_assignment.nbits; // VRB to PRB mapping - if ((pdsch_config->resourceAllocation == 1) && (bwp->bwp_Dedicated->pdsch_Config->choice.setup->vrb_ToPRB_Interleaver != NULL)) { + if (pdsch_Config && + pdsch_Config->resourceAllocation == 1 && + pdsch_Config->vrb_ToPRB_Interleaver != NULL) { dci_pdu->vrb_to_prb_mapping.nbits = 1; size += dci_pdu->vrb_to_prb_mapping.nbits; } // PRB bundling size indicator - if (pdsch_config->prb_BundlingType.present == NR_PDSCH_Config__prb_BundlingType_PR_dynamicBundling) { + if (pdsch_Config && + pdsch_Config->prb_BundlingType.present == NR_PDSCH_Config__prb_BundlingType_PR_dynamicBundling) { dci_pdu->prb_bundling_size_indicator.nbits = 1; size += dci_pdu->prb_bundling_size_indicator.nbits; } // Rate matching indicator - NR_RateMatchPatternGroup_t *group1 = pdsch_config->rateMatchPatternGroup1; - NR_RateMatchPatternGroup_t *group2 = pdsch_config->rateMatchPatternGroup2; + NR_RateMatchPatternGroup_t *group1 = pdsch_Config ? pdsch_Config->rateMatchPatternGroup1 : NULL; + NR_RateMatchPatternGroup_t *group2 = pdsch_Config ? pdsch_Config->rateMatchPatternGroup2 : NULL; if ((group1 != NULL) && (group2 != NULL)) dci_pdu->rate_matching_indicator.nbits = 2; if ((group1 != NULL) != (group2 != NULL)) dci_pdu->rate_matching_indicator.nbits = 1; size += dci_pdu->rate_matching_indicator.nbits; // ZP CSI-RS trigger - if (pdsch_config->aperiodic_ZP_CSI_RS_ResourceSetsToAddModList != NULL) { - uint8_t nZP = pdsch_config->aperiodic_ZP_CSI_RS_ResourceSetsToAddModList->list.count; + if (pdsch_Config && + pdsch_Config->aperiodic_ZP_CSI_RS_ResourceSetsToAddModList != NULL) { + uint8_t nZP = pdsch_Config->aperiodic_ZP_CSI_RS_ResourceSetsToAddModList->list.count; dci_pdu->zp_csi_rs_trigger.nbits = (int)ceil(log2(nZP+1)); } size += dci_pdu->zp_csi_rs_trigger.nbits; // TB1- MCS 5, NDI 1, RV 2 size += 8; // TB2 - long *maxCWperDCI = pdsch_config->maxNrofCodeWordsScheduledByDCI; + long *maxCWperDCI = pdsch_Config ? pdsch_Config->maxNrofCodeWordsScheduledByDCI : NULL; if ((maxCWperDCI != NULL) && (*maxCWperDCI == 2)) { size += 8; } // HARQ PID size += 4; // DAI - if (cg->physicalCellGroupConfig->pdsch_HARQ_ACK_Codebook == NR_PhysicalCellGroupConfig__pdsch_HARQ_ACK_Codebook_dynamic) { // FIXME in case of more than one serving cell + if (cg->physicalCellGroupConfig && + cg->physicalCellGroupConfig->pdsch_HARQ_ACK_Codebook == NR_PhysicalCellGroupConfig__pdsch_HARQ_ACK_Codebook_dynamic) { // FIXME in case of more than one serving cell dci_pdu->dai[0].nbits = 2; size += dci_pdu->dai[0].nbits; } + LOG_D(NR_MAC,"dci_pdu->dai[0].nbits %d\n",dci_pdu->dai[0].nbits); // TPC PUCCH size += 2; // PUCCH resource indicator size += 3; // PDSCH to HARQ timing indicator - uint8_t I = ubwp->bwp_Dedicated->pucch_Config->choice.setup->dl_DataToUL_ACK->list.count; + uint8_t I = pucch_Config->dl_DataToUL_ACK ? pucch_Config->dl_DataToUL_ACK->list.count : 8; dci_pdu->pdsch_to_harq_feedback_timing_indicator.nbits = (int)ceil(log2(I)); size += dci_pdu->pdsch_to_harq_feedback_timing_indicator.nbits; + LOG_D(NR_MAC,"dci_pdu->pdsch_to_harq_feedback_timing_indicator.nbits %d\n",dci_pdu->pdsch_to_harq_feedback_timing_indicator.nbits); // Antenna ports - NR_SetupRelease_DMRS_DownlinkConfig_t *typeA = pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA; - NR_SetupRelease_DMRS_DownlinkConfig_t *typeB = pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeB; + NR_SetupRelease_DMRS_DownlinkConfig_t *typeA = pdsch_Config ? pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA : NULL; + NR_SetupRelease_DMRS_DownlinkConfig_t *typeB = pdsch_Config ? pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB : NULL; + AssertFatal(typeA!=NULL || typeB!=NULL, "either dmrs_typeA or typeB must be configured\n"); dci_pdu->antenna_ports.nbits = getAntPortBitWidth(typeA,typeB); size += dci_pdu->antenna_ports.nbits; + LOG_D(NR_MAC,"dci_pdu->antenna_ports.nbits %d\n",dci_pdu->antenna_ports.nbits); // Tx Config Indication - long *isTciEnable = bwp->bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.array[bwp_id-1]->tci_PresentInDCI; + long *isTciEnable = pdcch_Config->controlResourceSetToAddModList->list.array[0]->tci_PresentInDCI; if (isTciEnable != NULL) { dci_pdu->transmission_configuration_indication.nbits = 3; size += dci_pdu->transmission_configuration_indication.nbits; @@ -3052,9 +2931,10 @@ uint16_t nr_dci_size(const NR_BWP_UplinkCommon_t *initialUplinkBWP, dci_pdu->srs_request.nbits = 3; size += dci_pdu->srs_request.nbits; // CBGTI - if (cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup->codeBlockGroupTransmission != NULL) { + if (cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig&& + cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup->codeBlockGroupTransmission != NULL) { uint8_t maxCBGperTB = (cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup->codeBlockGroupTransmission->choice.setup->maxCodeBlockGroupsPerTransportBlock + 1) * 2; - long *maxCWperDCI_rrc = pdsch_config->maxNrofCodeWordsScheduledByDCI; + long *maxCWperDCI_rrc = pdsch_Config->maxNrofCodeWordsScheduledByDCI; uint8_t maxCW = (maxCWperDCI_rrc == NULL) ? 1 : *maxCWperDCI_rrc; dci_pdu->cbgti.nbits = maxCBGperTB * maxCW; size += dci_pdu->cbgti.nbits; @@ -3528,13 +3408,23 @@ void get_type0_PDCCH_CSS_config_parameters(NR_Type0_PDCCH_CSS_config_t *type0_PD uint16_t ssb_start_symbol, NR_SubcarrierSpacing_t scs_ssb, frequency_range_t frequency_range, + int nr_band, uint32_t ssb_index, uint32_t ssb_period, uint32_t ssb_offset_point_a) { NR_SubcarrierSpacing_t scs_pdcch; - channel_bandwidth_t min_channel_bw = bw_10MHz; // TODO remove hardcoding and implement Table 5.3.5-1 in 38.104 + channel_bandwidth_t min_channel_bw; + + // according to Table 5.3.5-1 in 38.104 + // band 79 is the only one which minimum is 40 + // for all the other channels it is either 10 or 5 + // and there is no difference between the two for this implementation so it is set it to 10 + if (nr_band == 79) + min_channel_bw = bw_40MHz; + else + min_channel_bw = bw_10MHz; if (frequency_range == FR2) { if(mib->subCarrierSpacingCommon == NR_MIB__subCarrierSpacingCommon_scs15or60) @@ -3562,9 +3452,10 @@ void get_type0_PDCCH_CSS_config_parameters(NR_Type0_PDCCH_CSS_config_t *type0_PD type0_PDCCH_CSS_config->num_rbs = -1; type0_PDCCH_CSS_config->num_symbols = -1; type0_PDCCH_CSS_config->rb_offset = -1; + LOG_D(NR_MAC,"NR_SubcarrierSpacing_kHz30 %d, scs_ssb %d, scs_pdcch %d, min_chan_bw %d\n",(int)NR_SubcarrierSpacing_kHz30,(int)scs_ssb,(int)scs_pdcch,min_channel_bw); // type0-pdcch coreset - switch( (scs_ssb << 3) | scs_pdcch ){ + switch( ((int)scs_ssb << 3) | (int)scs_pdcch ){ case (NR_SubcarrierSpacing_kHz15 << 5) | NR_SubcarrierSpacing_kHz15: AssertFatal(index_4msb < 15, "38.213 Table 13-1 4 MSB out of range\n"); type0_PDCCH_CSS_config->type0_pdcch_ss_mux_pattern = 1; @@ -3597,7 +3488,7 @@ void get_type0_PDCCH_CSS_config_parameters(NR_Type0_PDCCH_CSS_config_t *type0_PD }else{ ; } break; - + case (NR_SubcarrierSpacing_kHz30 << 3) | NR_SubcarrierSpacing_kHz30: if((min_channel_bw & bw_5MHz) | (min_channel_bw & bw_10MHz)){ type0_PDCCH_CSS_config->type0_pdcch_ss_mux_pattern = 1; @@ -3674,13 +3565,14 @@ void get_type0_PDCCH_CSS_config_parameters(NR_Type0_PDCCH_CSS_config_t *type0_PD break; default: + LOG_E(NR_MAC,"NR_SubcarrierSpacing_kHz30 %d, scs_ssb %d, scs_pdcch %d, min_chan_bw %d\n",NR_SubcarrierSpacing_kHz30,(int)scs_ssb,(int)scs_pdcch,min_channel_bw); break; } - LOG_D(MAC,"Coreset0: index_4msb=%d, num_rbs=%d, num_symb=%d, rb_offset=%d\n", + LOG_D(NR_MAC,"Coreset0: index_4msb=%d, num_rbs=%d, num_symb=%d, rb_offset=%d\n", index_4msb,type0_PDCCH_CSS_config->num_rbs,type0_PDCCH_CSS_config->num_symbols,type0_PDCCH_CSS_config->rb_offset ); - AssertFatal(type0_PDCCH_CSS_config->num_rbs != -1, "Type0 PDCCH coreset num_rbs undefined"); + AssertFatal(type0_PDCCH_CSS_config->num_rbs != -1, "Type0 PDCCH coreset num_rbs undefined, index_4msb=%d, min_channel_bw %d, scs_ssb %d, scs_pdcch %d\n",index_4msb,min_channel_bw,(int)scs_ssb,(int)scs_pdcch); AssertFatal(type0_PDCCH_CSS_config->num_symbols != -1, "Type0 PDCCH coreset num_symbols undefined"); AssertFatal(type0_PDCCH_CSS_config->rb_offset != -1, "Type0 PDCCH coreset rb_offset undefined"); @@ -3935,7 +3827,7 @@ void fill_coresetZero(NR_ControlResourceSet_t *coreset0, NR_Type0_PDCCH_CSS_conf } -uint8_t fill_searchSpaceZero(NR_SearchSpace_t *ss0, NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config, int L) { +void fill_searchSpaceZero(NR_SearchSpace_t *ss0, NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config) { if(ss0 == NULL) ss0=calloc(1,sizeof(*ss0)); if(ss0->controlResourceSetId == NULL) ss0->controlResourceSetId=calloc(1,sizeof(*ss0->controlResourceSetId)); @@ -3953,7 +3845,6 @@ uint8_t fill_searchSpaceZero(NR_SearchSpace_t *ss0, NR_Type0_PDCCH_CSS_config_t AssertFatal(type0_PDCCH_CSS_config!=NULL,"No type0 CSS configuration\n"); max_agg = (type0_PDCCH_CSS_config->num_symbols*type0_PDCCH_CSS_config->num_rbs)/6; - if (L>max_agg) return 0; symbols = (1-(1<num_symbols))<first_symbol_index; duration = type0_PDCCH_CSS_config->search_space_duration; @@ -3986,28 +3877,11 @@ uint8_t fill_searchSpaceZero(NR_SearchSpace_t *ss0, NR_Type0_PDCCH_CSS_config_t // max values are set according to TS38.213 Section 10.1 Table 10.1-1 ss0->nrofCandidates->aggregationLevel1 = NR_SearchSpace__nrofCandidates__aggregationLevel1_n0; ss0->nrofCandidates->aggregationLevel2 = NR_SearchSpace__nrofCandidates__aggregationLevel2_n0; - switch(L){ - case 4: - ss0->nrofCandidates->aggregationLevel4 = (((max_agg>>2) > 4)? 4 : max_agg>>2); - ss0->nrofCandidates->aggregationLevel8 = NR_SearchSpace__nrofCandidates__aggregationLevel8_n0; - ss0->nrofCandidates->aggregationLevel8 = NR_SearchSpace__nrofCandidates__aggregationLevel16_n0; - break; - case 8: - ss0->nrofCandidates->aggregationLevel8 = NR_SearchSpace__nrofCandidates__aggregationLevel4_n0; - ss0->nrofCandidates->aggregationLevel8 = (((max_agg>>3) > 2)? 2 : max_agg>>3); - ss0->nrofCandidates->aggregationLevel8 = NR_SearchSpace__nrofCandidates__aggregationLevel16_n0; - break; - case 16: - ss0->nrofCandidates->aggregationLevel8 = NR_SearchSpace__nrofCandidates__aggregationLevel4_n0; - ss0->nrofCandidates->aggregationLevel8 = NR_SearchSpace__nrofCandidates__aggregationLevel8_n0; - ss0->nrofCandidates->aggregationLevel16 = (((max_agg>>4) > 1)? 1 : max_agg>>4); - break; - default: - AssertFatal(1==0,"Invalid aggregation level %d for SS0\n",L); - } + ss0->nrofCandidates->aggregationLevel4 = (((max_agg>>2) > 4)? 4 : max_agg>>2); + ss0->nrofCandidates->aggregationLevel8 = (((max_agg>>3) > 2)? 2 : max_agg>>3); + ss0->nrofCandidates->aggregationLevel16 = (((max_agg>>4) > 1)? 1 : max_agg>>4); ss0->searchSpaceType->present = NR_SearchSpace__searchSpaceType_PR_common; - return 1; } diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index 0a185157ef..ced29f066f 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -37,12 +37,6 @@ #include "nr_mac.h" #include "openair1/PHY/impl_defs_nr.h" -uint16_t config_bandwidth(int mu, int nb_rb, int nr_band); - -lte_frame_type_t get_frame_type(uint16_t nr_bandP, uint8_t scs_index); - -int32_t get_delta_duplex(int nr_bandP, uint8_t scs_index); - uint64_t from_nrarfcn(int nr_bandP, uint8_t scs_index, uint32_t dl_nrarfcn); uint32_t to_nrarfcn(int nr_bandP, uint64_t dl_CarrierFreq, uint8_t scs_index, uint32_t bw); @@ -53,7 +47,8 @@ int is_nr_DL_slot(NR_TDD_UL_DL_ConfigCommon_t *tdd_UL_DL_ConfigurationCommon,slo int is_nr_UL_slot(NR_TDD_UL_DL_ConfigCommon_t *tdd_UL_DL_ConfigurationCommon, slot_t slotP, lte_frame_type_t frame_type); -uint16_t nr_dci_size(const NR_BWP_UplinkCommon_t *initialULBWP, +uint16_t nr_dci_size(const NR_BWP_DownlinkCommon_t *initialDLBWP, + const NR_BWP_UplinkCommon_t *initialULBWP, const NR_CellGroupConfig_t *cg, dci_pdu_rel15_t *dci_pdu, nr_dci_format_t format, @@ -63,7 +58,8 @@ uint16_t nr_dci_size(const NR_BWP_UplinkCommon_t *initialULBWP, void find_aggregation_candidates(uint8_t *aggregation_level, uint8_t *nr_of_candidates, - NR_SearchSpace_t *ss); + NR_SearchSpace_t *ss, + int maxL); void find_monitoring_periodicity_offset_common(NR_SearchSpace_t *ss, uint16_t *slot_period, @@ -95,8 +91,6 @@ int get_nr_prach_occasion_info_from_index(uint8_t index, uint16_t *N_RA_sfn, uint8_t *max_association_period); -uint8_t get_nr_prach_duration(uint8_t prach_format); - uint8_t get_pusch_mcs_table(long *mcs_Table, int is_tp, int dci_format, @@ -119,7 +113,6 @@ int64_t *get_prach_config_info(frequency_range_t freq_range, uint16_t get_NCS(uint8_t index, uint16_t format, uint8_t restricted_set_config); -int get_num_dmrs(uint16_t dmrs_mask ); uint8_t get_l0_ul(uint8_t mapping_type, uint8_t dmrs_typeA_position); int32_t get_l_prime(uint8_t duration_in_symbols, uint8_t mapping_type, pusch_dmrs_AdditionalPosition_t additional_pos, pusch_maxLength_t pusch_maxLength, uint8_t start_symbolt, uint8_t dmrs_typeA_position); @@ -134,6 +127,7 @@ void get_type0_PDCCH_CSS_config_parameters(NR_Type0_PDCCH_CSS_config_t *type0_PD uint16_t ssb_start_symbol, NR_SubcarrierSpacing_t scs_ssb, frequency_range_t frequency_range, + int nr_band, uint32_t ssb_index, uint32_t ssb_period, uint32_t ssb_offset_point_a); @@ -148,7 +142,7 @@ void get_info_from_tda_tables(int default_abc, int *nrOfSymbols); void fill_coresetZero(NR_ControlResourceSet_t *coreset0, NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config); -uint8_t fill_searchSpaceZero(NR_SearchSpace_t *ss0, NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config, int L); +void fill_searchSpaceZero(NR_SearchSpace_t *ss0, NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config); uint16_t compute_pucch_prb_size(uint8_t format, uint8_t nr_prbs, @@ -192,7 +186,7 @@ uint8_t get_num_dmrs_symbols(NR_PDSCH_Config_t *pdsch_Config,int dmrs_TypeA_Posi @returns transformPrecoding value */ uint8_t get_transformPrecoding(const NR_BWP_UplinkCommon_t *initialUplinkBWP, const NR_PUSCH_Config_t *pusch_config, - const NR_BWP_Uplink_t *ubwp, + const NR_BWP_UplinkDedicated_t *ubwp, uint8_t *dci_format, int rnti_type, uint8_t configuredGrant); diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h index 5b4ebe2397..5def748d42 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h @@ -76,6 +76,9 @@ extern boolean_t pre_scd_activeUE[NUMBER_OF_UE_MAX]; extern eNB_UE_STATS pre_scd_eNB_UE_stats[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; #endif*/ +extern const uint32_t NR_SHORT_BSR_TABLE[NR_SHORT_BSR_TABLE_SIZE]; +extern const uint32_t NR_LONG_BSR_TABLE[NR_LONG_BSR_TABLE_SIZE]; + // Type0-PDCCH search space extern const int32_t table_38213_13_1_c1[16]; extern const int32_t table_38213_13_1_c2[16]; diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c old mode 100755 new mode 100644 index 6f9e36d047..cef13b87fb --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -516,12 +516,12 @@ void config_bwp_ue(NR_UE_MAC_INST_t *mac, uint16_t *bwp_ind, uint8_t *dci_format else if (scd->defaultDownlinkBWP_Id) mac->DL_BWP_Id = *scd->defaultDownlinkBWP_Id; else - mac->DL_BWP_Id = 1; + mac->DL_BWP_Id = 0; if (scd->uplinkConfig && scd->uplinkConfig->firstActiveUplinkBWP_Id) mac->UL_BWP_Id = *scd->uplinkConfig->firstActiveUplinkBWP_Id; else - mac->UL_BWP_Id = 1; + mac->UL_BWP_Id = 0; } @@ -537,20 +537,22 @@ void config_bwp_ue(NR_UE_MAC_INST_t *mac, uint16_t *bwp_ind, uint8_t *dci_format void config_control_ue(NR_UE_MAC_INST_t *mac){ uint8_t coreset_id = 1, ss_id; - - NR_ServingCellConfig_t *scd = mac->cg->spCellConfig->spCellConfigDedicated; - AssertFatal(scd->downlinkBWP_ToAddModList != NULL, "downlinkBWP_ToAddModList is null\n"); - AssertFatal(scd->downlinkBWP_ToAddModList->list.count == 1, "downlinkBWP_ToAddModList->list->count is %d\n", scd->downlinkBWP_ToAddModList->list.count); - - config_bwp_ue(mac, NULL, NULL); NR_BWP_Id_t dl_bwp_id = mac->DL_BWP_Id; - AssertFatal(dl_bwp_id != 0, "DL_BWP_Id is 0!"); + NR_BWP_Id_t ul_bwp_id = mac->UL_BWP_Id; + NR_ServingCellConfig_t *scd = mac->cg->spCellConfig->spCellConfigDedicated; + if (dl_bwp_id==0) AssertFatal(mac->scc_SIB,"dl_bwp_id 0 (DL %d,UL %d) means mac->scc_SIB should exist here!\n",(int)mac->DL_BWP_Id,(int)mac->UL_BWP_Id); + NR_BWP_DownlinkCommon_t *bwp_Common = dl_bwp_id>0 ? scd->downlinkBWP_ToAddModList->list.array[dl_bwp_id - 1]->bwp_Common : + &mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP; - NR_BWP_DownlinkCommon_t *bwp_Common = scd->downlinkBWP_ToAddModList->list.array[dl_bwp_id - 1]->bwp_Common; - AssertFatal(bwp_Common != NULL, "bwp_Common is null\n"); - NR_BWP_DownlinkDedicated_t *dl_bwp_Dedicated = scd->downlinkBWP_ToAddModList->list.array[dl_bwp_id - 1]->bwp_Dedicated; + if (dl_bwp_id > 0 ) { + AssertFatal(scd->downlinkBWP_ToAddModList != NULL, "downlinkBWP_ToAddModList is null\n"); + AssertFatal(scd->downlinkBWP_ToAddModList->list.count == 1, "downlinkBWP_ToAddModList->list->count is %d\n", scd->downlinkBWP_ToAddModList->list.count); + } + NR_BWP_DownlinkDedicated_t *dl_bwp_Dedicated = dl_bwp_id>0 ? scd->downlinkBWP_ToAddModList->list.array[dl_bwp_id - 1]->bwp_Dedicated: + scd->initialDownlinkBWP; AssertFatal(dl_bwp_Dedicated != NULL, "dl_bwp_Dedicated is null\n"); + config_bwp_ue(mac, NULL, NULL); NR_SetupRelease_PDCCH_Config_t *pdcch_Config = dl_bwp_Dedicated->pdcch_Config; AssertFatal(pdcch_Config != NULL, "pdcch_Config is null\n"); @@ -574,16 +576,17 @@ void config_control_ue(NR_UE_MAC_INST_t *mac){ AssertFatal(searchSpacesToAddModList->list.count < FAPI_NR_MAX_SS_PER_CORESET, "too many searchpaces per coreset %d\n", searchSpacesToAddModList->list.count); struct NR_UplinkConfig__uplinkBWP_ToAddModList *uplinkBWP_ToAddModList = scd->uplinkConfig->uplinkBWP_ToAddModList; - AssertFatal(uplinkBWP_ToAddModList != NULL, "uplinkBWP_ToAddModList is null\n"); - AssertFatal(uplinkBWP_ToAddModList->list.count == 1, "uplinkBWP_ToAddModList->list->count is %d\n", uplinkBWP_ToAddModList->list.count); - + if (ul_bwp_id > 0) { + AssertFatal(uplinkBWP_ToAddModList != NULL, "uplinkBWP_ToAddModList is null\n"); + AssertFatal(uplinkBWP_ToAddModList->list.count == 1, "uplinkBWP_ToAddModList->list->count is %d\n", uplinkBWP_ToAddModList->list.count); + } // check pdcch_Config, pdcch_ConfigCommon and DL BWP - mac->DLbwp[0] = scd->downlinkBWP_ToAddModList->list.array[dl_bwp_id - 1]; - mac->coreset[dl_bwp_id - 1][coreset_id - 1] = controlResourceSetToAddModList->list.array[0]; + mac->DLbwp[0] = dl_bwp_id>0?scd->downlinkBWP_ToAddModList->list.array[dl_bwp_id - 1]:NULL; + mac->coreset[dl_bwp_id][coreset_id - 1] = controlResourceSetToAddModList->list.array[0]; // Check dedicated UL BWP and pass to MAC - mac->ULbwp[0] = uplinkBWP_ToAddModList->list.array[0]; - AssertFatal(mac->ULbwp[0]->bwp_Dedicated != NULL, "UL bwp_Dedicated is null\n"); + mac->ULbwp[0] = ul_bwp_id>0?uplinkBWP_ToAddModList->list.array[0]:NULL; + if (mac->ULbwp[0]) AssertFatal(mac->ULbwp[0]->bwp_Dedicated != NULL, "UL bwp_Dedicated is null\n"); // check available Search Spaces in the searchSpacesToAddModList and pass to MAC // note: the network configures at most 10 Search Spaces per BWP per cell (including UE-specific and common Search Spaces). @@ -591,10 +594,10 @@ void config_control_ue(NR_UE_MAC_INST_t *mac){ NR_SearchSpace_t *ss = searchSpacesToAddModList->list.array[ss_id]; AssertFatal(ss->controlResourceSetId != NULL, "ss->controlResourceSetId is null\n"); AssertFatal(ss->searchSpaceType != NULL, "ss->searchSpaceType is null\n"); - AssertFatal(*ss->controlResourceSetId == mac->coreset[dl_bwp_id - 1][coreset_id - 1]->controlResourceSetId, "ss->controlResourceSetId is unknown\n"); + AssertFatal(*ss->controlResourceSetId == mac->coreset[dl_bwp_id][coreset_id - 1]->controlResourceSetId, "ss->controlResourceSetId is unknown\n"); AssertFatal(ss->monitoringSymbolsWithinSlot != NULL, "NR_SearchSpace->monitoringSymbolsWithinSlot is null\n"); AssertFatal(ss->monitoringSymbolsWithinSlot->buf != NULL, "NR_SearchSpace->monitoringSymbolsWithinSlot->buf is null\n"); - mac->SSpace[0][0][ss_id] = ss; + mac->SSpace[dl_bwp_id][0][ss_id] = ss; } // Check available CSSs in the commonSearchSpaceList (list of additional common search spaces) @@ -602,15 +605,28 @@ void config_control_ue(NR_UE_MAC_INST_t *mac){ for (int css_id = 0; css_id < commonSearchSpaceList->list.count; css_id++) { NR_SearchSpace_t *css = commonSearchSpaceList->list.array[css_id]; AssertFatal(css->controlResourceSetId != NULL, "ss->controlResourceSetId is null\n"); - AssertFatal(*css->controlResourceSetId == mac->coreset[dl_bwp_id - 1][coreset_id - 1]->controlResourceSetId, "ss->controlResourceSetId is unknown\n"); + AssertFatal(*css->controlResourceSetId == 0 || *css->controlResourceSetId == mac->coreset[dl_bwp_id][coreset_id - 1]->controlResourceSetId, "css->controlResourceSetId %ld is unknown, mac->coreset[%ld][%d]->controlResourceSetId %ld\n",*css->controlResourceSetId,dl_bwp_id,coreset_id-1,mac->coreset[dl_bwp_id][coreset_id - 1]->controlResourceSetId); + AssertFatal(css->searchSpaceType != NULL, "css->searchSpaceType is null\n"); AssertFatal(css->monitoringSymbolsWithinSlot != NULL, "css->monitoringSymbolsWithinSlot is null\n"); AssertFatal(css->monitoringSymbolsWithinSlot->buf != NULL, "css->monitoringSymbolsWithinSlot->buf is null\n"); - mac->SSpace[0][0][ss_id] = css; + mac->SSpace[dl_bwp_id][0][ss_id] = css; ss_id++; } } +// todo handle mac_LogicalChannelConfig +int nr_rrc_mac_config_req_ue_logicalChannelBearer( + module_id_t module_id, + int cc_idP, + uint8_t gNB_index, + long logicalChannelIdentity, + boolean_t status){ + NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); + mac->logicalChannelBearer_exist[logicalChannelIdentity] = status; + return 0; +} + int nr_rrc_mac_config_req_ue( module_id_t module_id, int cc_idP, @@ -652,6 +668,9 @@ int nr_rrc_mac_config_req_ue( if(scell_group_config != NULL ){ mac->cg = scell_group_config; mac->servCellIndex = *scell_group_config->spCellConfig->servCellIndex; + mac->DL_BWP_Id=mac->cg->spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id ? *mac->cg->spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id : 0; + mac->UL_BWP_Id=mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id ? *mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id : 0; + config_control_ue(mac); if (scell_group_config->spCellConfig->reconfigurationWithSync) { if (scell_group_config->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated) { @@ -671,8 +690,19 @@ int nr_rrc_mac_config_req_ue( LOG_I(MAC,"Applying CellGroupConfig from gNodeB\n"); mac->cg = cell_group_config; mac->servCellIndex = cell_group_config->spCellConfig->servCellIndex ? *cell_group_config->spCellConfig->servCellIndex : 0; - // config_control_ue(mac); - // config_common_ue(mac,module_id,cc_idP); + + mac->scheduling_info.periodicBSR_SF = + MAC_UE_BSR_TIMER_NOT_RUNNING; + mac->scheduling_info.retxBSR_SF = + MAC_UE_BSR_TIMER_NOT_RUNNING; + mac->BSR_reporting_active = NR_BSR_TRIGGER_NONE; + LOG_D(MAC, "[UE %d]: periodic BSR %d (SF), retx BSR %d (SF)\n", + module_id, + mac->scheduling_info.periodicBSR_SF, + mac->scheduling_info.retxBSR_SF); + + config_control_ue(mac); + //config_common_ue(mac,module_id,cc_idP); /* if(mac_cell_group_configP != NULL){ if(mac_cell_group_configP->drx_Config != NULL ){ diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h old mode 100755 new mode 100644 index 8a59b3599e..d076f2c59e --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -182,9 +182,9 @@ typedef struct { uint16_t All_lcid_buffer_size_lastTTI; /// buffer status for each lcid uint8_t LCID_status[NR_MAX_NUM_LCID]; - /// SR pending as defined in 36.321 + /// SR pending as defined in 38.321 uint8_t SR_pending; - /// SR_COUNTER as defined in 36.321 + /// SR_COUNTER as defined in 38.321 uint16_t SR_COUNTER; /// logical channel group ide for each LCID uint8_t LCGID[NR_MAX_NUM_LCID]; @@ -309,6 +309,7 @@ typedef struct { bool ack_received; uint8_t pucch_resource_indicator; uint16_t feedback_to_ul; + int is_common; frame_t dl_frame; int dl_slot; uint8_t ack; @@ -327,15 +328,6 @@ typedef struct { } RAR_grant_t; -typedef struct { - - uint8_t phr_reporting; - uint16_t truncated_bsr; - uint16_t short_bsr; - uint16_t long_bsr; - -} NR_UE_MAC_CE_t; - typedef struct { int n_HARQ_ACK; uint32_t ack_payload; @@ -344,6 +336,7 @@ typedef struct { uint32_t csi_part2_payload; int resource_indicator; int resource_set_id; + int is_common; int initial_pucch_id; NR_PUCCH_Resource_t *pucch_resource; int n_CCE; @@ -351,6 +344,7 @@ typedef struct { int8_t delta_pucch; } PUCCH_sched_t; + /*!\brief Top level UE MAC structure */ typedef struct { @@ -417,8 +411,15 @@ typedef struct { nr_ue_if_module_t *if_module; nr_phy_config_t phy_config; + /// BSR report flag management + uint8_t BSR_reporting_active; + + /// LogicalChannelConfig has bearer. + boolean_t logicalChannelBearer_exist[NR_MAX_NUM_LCID]; NR_UE_SCHEDULING_INFO scheduling_info; - NR_UE_MAC_CE_t nr_ue_mac_ce; + + /// PHR + uint8_t PHR_reporting_active; NR_Type0_PDCCH_CSS_config_t type0_PDCCH_CSS_config; NR_SearchSpace_t *search_space_zero; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h old mode 100755 new mode 100644 index 83ff1d3a9e..a9632fb330 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -40,6 +40,10 @@ #define NR_DL_MAX_DAI (4) /* TS 38.213 table 9.1.3-1 Value of counter DAI for DCI format 1_0 and 1_1 */ #define NR_DL_MAX_NB_CW (2) /* number of downlink code word */ +/**\brief initialize the field in nr_mac instance + \param module_id module id */ +void nr_ue_init_mac(module_id_t module_idP); + /**\brief decode mib pdu in NR_UE, from if_module ul_ind with P7 tx_ind message \param module_id module id \param cc_id component carrier id @@ -74,6 +78,20 @@ int8_t nr_ue_decode_BCCH_DL_SCH(module_id_t module_id, uint8_t *pduP, uint32_t pdu_len); +/**\brief primitive from RRC layer to MAC layer to set if bearer exists for a logical channel. todo handle mac_LogicalChannelConfig + \param module_id module id + \param cc_id component carrier id + \param gNB_index gNB index + \param long logicalChannelIdentity + \param boolean_t status*/ +int nr_rrc_mac_config_req_ue_logicalChannelBearer( + module_id_t module_id, + int cc_idP, + uint8_t gNB_index, + long logicalChannelIdentity, + boolean_t status +); + /**\brief primitive from RRC layer to MAC layer for configuration L1/L2, now supported 4 rrc messages: MIB, cell_group_config for MAC/PHY, spcell_config(serving cell config) \param module_id module id \param cc_id component carrier id @@ -125,7 +143,53 @@ void fill_scheduled_response(nr_scheduled_response_t *scheduled_response, int slot, int thread_id); -int8_t nr_ue_get_SR(module_id_t module_idP, frame_t frameP, int slotP); +/*! \fn int8_t nr_ue_get_SR(module_id_t module_idP, frame_t frameP, slot_t slotP); + \brief Called by PHY to get sdu for PUSCH transmission. It performs the following operations: Checks BSR for DCCH, DCCH1 and DTCH corresponding to previous values computed either in SR or BSR procedures. It gets rlc status indications on DCCH,DCCH1 and DTCH and forms BSR elements and PHR in MAC header. CRNTI element is not supported yet. It computes transport block for up to 3 SDUs and generates header and forms the complete MAC SDU. +\param[in] Mod_id Instance id of UE in machine +\param[in] frameP subframe number +\param[in] slotP slot number +*/ +int8_t nr_ue_get_SR(module_id_t module_idP, frame_t frameP, slot_t slotP); + +/*! \fn boolean_t update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t gNB_index) + \brief get the rlc stats and update the bsr level for each lcid +\param[in] Mod_id instance of the UE +\param[in] frameP Frame index +\param[in] slot slotP number +\param[in] uint8_t gNB_index +*/ +boolean_t nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t gNB_index); + +/*! \fn nr_locate_BsrIndexByBufferSize (int *table, int size, int value) + \brief locate the BSR level in the table as defined in 38.321. This function requires that he values in table to be monotonic, either increasing or decreasing. The returned value is not less than 0, nor greater than n-1, where n is the size of table. +\param[in] *table Pointer to BSR table +\param[in] size Size of the table +\param[in] value Value of the buffer +\return the index in the BSR_LEVEL table +*/ +uint8_t nr_locate_BsrIndexByBufferSize(const uint32_t *table, int size, + int value); + +/*! \fn int nr_get_sf_periodicBSRTimer(uint8_t periodicBSR_Timer) + \brief get the number of subframe from the periodic BSR timer configured by the higher layers +\param[in] periodicBSR_Timer timer for periodic BSR +\return the number of subframe +*/ +int nr_get_sf_periodicBSRTimer(uint8_t bucketSize); + +/*! \fn int nr_get_ms_bucketsizeduration(uint8_t bucketSize) + \brief get the time in ms form the bucket size duration configured by the higher layer +\param[in] bucketSize the bucket size duration +\return the time in ms +*/ +int nr_get_ms_bucketsizeduration(uint8_t bucketsizeduration); + +/*! \fn int nr_get_sf_retxBSRTimer(uint8_t retxBSR_Timer) + \brief get the number of subframe form the bucket size duration configured by the higher layer +\param[in] retxBSR_Timer timer for regular BSR +\return the time in sf +*/ +int nr_get_sf_retxBSRTimer(uint8_t retxBSR_Timer); int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, frame_t frame, int slot, dci_pdu_rel15_t *dci, fapi_nr_dci_indication_pdu_t *dci_ind); int nr_ue_process_dci_indication_pdu(module_id_t module_id, int cc_id, int gNB_index, frame_t frame, int slot, fapi_nr_dci_indication_pdu_t *dci); @@ -170,7 +234,13 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info, int pdu_id); int nr_write_ce_ulsch_pdu(uint8_t *mac_ce, - NR_UE_MAC_INST_t *mac); + NR_UE_MAC_INST_t *mac, + uint8_t power_headroom, // todo: NR_POWER_HEADROOM_CMD *power_headroom, + uint16_t *crnti, + NR_BSR_SHORT *truncated_bsr, + NR_BSR_SHORT *short_bsr, + NR_BSR_LONG *long_bsr + ); void fill_dci_search_candidates(NR_SearchSpace_t *ss,fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15); @@ -178,6 +248,14 @@ void config_dci_pdu(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_dci_dl_pdu_rel15_t void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl_config, frame_t frame, int slot); +void get_bwp_info(NR_UE_MAC_INST_t *mac, + int dl_bwp_id, + int ul_bwp_id, + NR_BWP_DownlinkDedicated_t **bwpd, + NR_BWP_DownlinkCommon_t **bwpc, + NR_BWP_UplinkDedicated_t **ubwpd, + NR_BWP_UplinkCommon_t **ubwpc); + uint8_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac, uint8_t dci_format, uint8_t dci_length, @@ -185,15 +263,20 @@ uint8_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac, uint64_t *dci_pdu, dci_pdu_rel15_t *nr_pdci_info_extracted); +NR_PUSCH_TimeDomainResourceAllocationList_t *choose_ul_tda_list(NR_PUSCH_Config_t *pusch_Config,NR_PUSCH_ConfigCommon_t *pusch_ConfigCommon); +NR_PDSCH_TimeDomainResourceAllocationList_t *choose_dl_tda_list(NR_PDSCH_Config_t *pdsch_Config,NR_PDSCH_ConfigCommon_t *pdsch_ConfigCommon); + int8_t nr_ue_process_dci_time_dom_resource_assignment(NR_UE_MAC_INST_t *mac, + NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList, + NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList, nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu, fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config_pdu, uint8_t time_domain_ind, int default_abc, bool use_default); - uint8_t nr_ue_get_sdu(module_id_t module_idP, + int cc_id, frame_t frameP, sub_frame_t subframe, uint8_t gNB_index, @@ -212,6 +295,7 @@ void set_harq_status(NR_UE_MAC_INST_t *mac, uint8_t dai, int n_CCE, int N_CCE, + int is_common, frame_t frame, int slot); @@ -256,23 +340,6 @@ void nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, fapi_nr_ul_config_pucch_pdu *pucch_pdu, int O_SR, int O_ACK, int O_CSI); -/** \brief Function for UE/PHY to compute PUSCH transmit power in power-control procedure. - @param Mod_id Module id of UE - @returns Po_NOMINAL_PUSCH (PREAMBLE_RECEIVED_TARGET_POWER+DELTA_PREAMBLE -*/ -int nr_get_Po_NOMINAL_PUSCH(NR_PRACH_RESOURCES_t *prach_resources, module_id_t module_idP, uint8_t CC_id); - -/** \brief Function to compute DELTA_PREAMBLE from 38.321 subclause 7.3 - (for RA power ramping procedure and Msg3 PUSCH power control policy) - @param Mod_id Module id of UE - @returns DELTA_PREAMBLE -*/ -int8_t nr_get_DELTA_PREAMBLE(module_id_t mod_id, int CC_id, uint16_t prach_format); - -/** \brief Function to compute configured maximum output power according to clause 6.2.4 of 3GPP TS 38.101-1 version 16.5.0 Release 16 - @param Mod_id Module id of UE -*/ -long nr_get_Pcmax(module_id_t mod_id); /* Random Access */ @@ -333,7 +400,7 @@ void nr_ra_succeeded(module_id_t mod_id, frame_t frame, int slot); If the UE is not in PUSCH mode for a particular eNB index, this is assumed to be an Msg3 and MAC attempts to retrieves the CCCH message from RRC. If the UE is in PUSCH mode for a particular eNB index and PUCCH format 0 (Scheduling Request) is not activated, the MAC may use this resource for -andom-access to transmit a BSR along with the C-RNTI control element (see 5.1.4 from 36.321) +andom-access to transmit a BSR along with the C-RNTI control element (see 5.1.4 from 38.321) @param mod_id Index of UE instance @param CC_id Component Carrier Index @param frame @@ -376,10 +443,6 @@ int8_t nr_ue_process_dci_freq_dom_resource_assignment(nfapi_nr_ue_pusch_pdu_t *p void config_dci_pdu(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15, fapi_nr_dl_config_request_t *dl_config, int rnti_type, int ss_id); void fill_dci_search_candidates(NR_SearchSpace_t *ss,fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15); -void get_num_re_dmrs(nfapi_nr_ue_pusch_pdu_t *pusch_pdu, - uint8_t *nb_dmrs_re_per_rb, - uint16_t *number_dmrs_symbols); - void build_ssb_to_ro_map(NR_UE_MAC_INST_t *mac); void config_bwp_ue(NR_UE_MAC_INST_t *mac, uint16_t *bwp_ind, uint8_t *dci_format); diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index b27837043f..af0c84dc4b 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -52,8 +52,9 @@ NR_UE_MAC_INST_t * nr_l2_init_ue(NR_UE_RRC_INST_t* rrc_inst) { //init mac here nr_ue_mac_inst = (NR_UE_MAC_INST_t *)calloc(sizeof(NR_UE_MAC_INST_t),NB_NR_UE_MAC_INST); - for (int j=0;jscell_group_config) { diff --git a/openair2/LAYER2/NR_MAC_UE/nr_l1_helpers.c b/openair2/LAYER2/NR_MAC_UE/nr_l1_helpers.c index 7f1011fb28..eaaa5f5f72 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_l1_helpers.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_l1_helpers.c @@ -35,150 +35,9 @@ #include "mac_defs.h" #include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" #include "LAYER2/NR_MAC_UE/mac_proto.h" +#include "LAYER2/NR_MAC_UE/nr_l1_helpers.h" #include "NR_P-Max.h" -/* TS 38.321 subclause 7.3 - return DELTA_PREAMBLE values in dB */ -int8_t nr_get_DELTA_PREAMBLE(module_id_t mod_id, int CC_id, uint16_t prach_format){ - - NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id); - NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = (mac->scc!=NULL) ? - mac->scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup: - mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.rach_ConfigCommon->choice.setup; - NR_SubcarrierSpacing_t scs = *nr_rach_ConfigCommon->msg1_SubcarrierSpacing; - int prach_sequence_length = (mac->scc!=NULL)?(mac->scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->prach_RootSequenceIndex.present - 1) : (mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.rach_ConfigCommon->choice.setup->prach_RootSequenceIndex.present-1); - uint8_t prachConfigIndex, mu; - - AssertFatal(CC_id == 0, "Transmission on secondary CCs is not supported yet\n"); - - // SCS configuration from msg1_SubcarrierSpacing and table 4.2-1 in TS 38.211 - - switch (scs){ - case NR_SubcarrierSpacing_kHz15: - mu = 0; - break; - - case NR_SubcarrierSpacing_kHz30: - mu = 1; - break; - - case NR_SubcarrierSpacing_kHz60: - mu = 2; - break; - - case NR_SubcarrierSpacing_kHz120: - mu = 3; - break; - - case NR_SubcarrierSpacing_kHz240: - mu = 4; - break; - - case NR_SubcarrierSpacing_spare3: - mu = 5; - break; - - case NR_SubcarrierSpacing_spare2: - mu = 6; - break; - - case NR_SubcarrierSpacing_spare1: - mu = 7; - break; - - default: - AssertFatal(1 == 0,"Unknown msg1_SubcarrierSpacing %lu\n", scs); - } - - // Preamble formats given by prach_ConfigurationIndex and tables 6.3.3.2-2 and 6.3.3.2-2 in TS 38.211 - - prachConfigIndex = nr_rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex; - - if (prach_sequence_length == 0) { - AssertFatal(prach_format < 4, "Illegal PRACH format %d for sequence length 839\n", prach_format); - switch (prach_format) { - - // long preamble formats - case 0: - case 3: - return 0; - - case 1: - return -3; - - case 2: - return -6; - } - } else { - switch (prach_format) { // short preamble formats - case 0: - case 3: - return 8 + 3*mu; - - case 1: - case 4: - case 8: - return 5 + 3*mu; - - case 2: - case 5: - return 3 + 3*mu; - - case 6: - return 3*mu; - - case 7: - return 5 + 3*mu; - - default: - AssertFatal(1 == 0, "[UE %d] ue_procedures.c: FATAL, Illegal preambleFormat %d, prachConfigIndex %d\n", mod_id, prach_format, prachConfigIndex); - } - } - return 0; -} - -// TS 38.321 subclause 5.1.3 - RA preamble transmission - ra_PREAMBLE_RECEIVED_TARGET_POWER configuration -// Measurement units: -// - preambleReceivedTargetPower dBm (-202..-60, 2 dBm granularity) -// - delta_preamble dB -// - RA_PREAMBLE_POWER_RAMPING_STEP dB -// - POWER_OFFSET_2STEP_RA dB -// returns receivedTargerPower in dBm -int nr_get_Po_NOMINAL_PUSCH(NR_PRACH_RESOURCES_t *prach_resources, module_id_t mod_id, uint8_t CC_id){ - - NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id); - int8_t receivedTargerPower; - int8_t delta_preamble; - - NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = (mac->scc != NULL) ? mac->scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup: mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.rach_ConfigCommon->choice.setup; - long preambleReceivedTargetPower = nr_rach_ConfigCommon->rach_ConfigGeneric.preambleReceivedTargetPower; - delta_preamble = nr_get_DELTA_PREAMBLE(mod_id, CC_id, prach_resources->prach_format); - - receivedTargerPower = preambleReceivedTargetPower + delta_preamble + (prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER - 1) * prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP + prach_resources->POWER_OFFSET_2STEP_RA; - - LOG_D(MAC, "In %s: receivedTargerPower is %d dBm \n", __FUNCTION__, receivedTargerPower); - - return receivedTargerPower; -} - -void get_num_re_dmrs(nfapi_nr_ue_pusch_pdu_t *pusch_pdu, - uint8_t *nb_dmrs_re_per_rb, - uint16_t *number_dmrs_symbols){ - - int start_symbol = pusch_pdu->start_symbol_index; - uint8_t number_of_symbols = pusch_pdu->nr_of_symbols; - uint16_t ul_dmrs_symb_pos = pusch_pdu->ul_dmrs_symb_pos; - uint8_t dmrs_type = pusch_pdu->dmrs_config_type; - uint8_t cdm_grps_no_data = pusch_pdu->num_dmrs_cdm_grps_no_data; - - *number_dmrs_symbols = 0; - for (int i = start_symbol; i < start_symbol + number_of_symbols; i++) { - if((ul_dmrs_symb_pos >> i) & 0x01) - *number_dmrs_symbols += 1; - } - - *nb_dmrs_re_per_rb = ((dmrs_type == pusch_dmrs_type1) ? 6:4)*cdm_grps_no_data; - -} // Implementation of 6.2.4 Configured ransmitted power // 3GPP TS 38.101-1 version 16.5.0 Release 16 diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_srb.h b/openair2/LAYER2/NR_MAC_UE/nr_l1_helpers.h old mode 100644 new mode 100755 similarity index 65% rename from openair2/LAYER2/nr_pdcp/nr_pdcp_entity_srb.h rename to openair2/LAYER2/NR_MAC_UE/nr_l1_helpers.h index f0f9d3e28f..8b3f00af43 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_srb.h +++ b/openair2/LAYER2/NR_MAC_UE/nr_l1_helpers.h @@ -1,4 +1,4 @@ - /* +/* * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. @@ -19,20 +19,8 @@ * contact@openairinterface.org */ -#ifndef _NR_PDCP_ENTITY_SRB_H_ -#define _NR_PDCP_ENTITY_SRB_H_ - -#include "nr_pdcp_entity.h" - -typedef struct { - nr_pdcp_entity_t common; - int srb_id; -} nr_pdcp_entity_srb_t; - -void nr_pdcp_entity_srb_recv_pdu(nr_pdcp_entity_t *_entity, char *buffer, int size); -void nr_pdcp_entity_srb_recv_sdu(nr_pdcp_entity_t *_entity, char *buffer, int size, int sdu_id); -void nr_pdcp_entity_srb_set_integrity_key(nr_pdcp_entity_t *_entity, char *key); -void nr_pdcp_entity_srb_delete(nr_pdcp_entity_t *_entity); - - -#endif /* _NR_PDCP_ENTITY_SRB_H_ */ +/** \brief Function to compute configured maximum output power according to clause 6.2.4 of 3GPP TS 38.101-1 version 16.5.0 Release 16 + @param Mod_id Module id of UE +*/ +long nr_get_Pcmax(module_id_t mod_id); +/** @}*/ diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index 83784634fc..2d059783fe 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -30,23 +30,18 @@ * \warning */ -/* Tools */ -#include "SIMULATION/TOOLS/sim.h" // for taus - /* RRC */ #include "NR_RACH-ConfigCommon.h" #include "RRC/NR_UE/rrc_proto.h" /* PHY */ -#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" -#include "PHY/defs_common.h" -#include "PHY/defs_nr_common.h" #include "PHY/NR_UE_ESTIMATION/nr_estimation.h" /* MAC */ #include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" #include "NR_MAC_COMMON/nr_mac.h" #include "LAYER2/NR_MAC_UE/mac_proto.h" +#include "LAYER2/NR_MAC_UE/nr_l1_helpers.h" #include @@ -198,6 +193,130 @@ void init_RA(module_id_t mod_id, } } + +/* TS 38.321 subclause 7.3 - return DELTA_PREAMBLE values in dB */ +int8_t nr_get_DELTA_PREAMBLE(module_id_t mod_id, int CC_id, uint16_t prach_format){ + + NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id); + NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = (mac->scc!=NULL) ? + mac->scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup: + mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.rach_ConfigCommon->choice.setup; + NR_SubcarrierSpacing_t scs = *nr_rach_ConfigCommon->msg1_SubcarrierSpacing; + int prach_sequence_length = (mac->scc!=NULL)?(mac->scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->prach_RootSequenceIndex.present - 1) : (mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.rach_ConfigCommon->choice.setup->prach_RootSequenceIndex.present-1); + uint8_t prachConfigIndex, mu; + + AssertFatal(CC_id == 0, "Transmission on secondary CCs is not supported yet\n"); + + // SCS configuration from msg1_SubcarrierSpacing and table 4.2-1 in TS 38.211 + + switch (scs){ + case NR_SubcarrierSpacing_kHz15: + mu = 0; + break; + + case NR_SubcarrierSpacing_kHz30: + mu = 1; + break; + + case NR_SubcarrierSpacing_kHz60: + mu = 2; + break; + + case NR_SubcarrierSpacing_kHz120: + mu = 3; + break; + + case NR_SubcarrierSpacing_kHz240: + mu = 4; + break; + + case NR_SubcarrierSpacing_spare3: + mu = 5; + break; + + case NR_SubcarrierSpacing_spare2: + mu = 6; + break; + + case NR_SubcarrierSpacing_spare1: + mu = 7; + break; + + default: + AssertFatal(1 == 0,"Unknown msg1_SubcarrierSpacing %lu\n", scs); + } + + // Preamble formats given by prach_ConfigurationIndex and tables 6.3.3.2-2 and 6.3.3.2-2 in TS 38.211 + + prachConfigIndex = nr_rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex; + + if (prach_sequence_length == 0) { + AssertFatal(prach_format < 4, "Illegal PRACH format %d for sequence length 839\n", prach_format); + switch (prach_format) { + + // long preamble formats + case 0: + case 3: + return 0; + + case 1: + return -3; + + case 2: + return -6; + } + } else { + switch (prach_format) { // short preamble formats + case 0: + case 3: + return 8 + 3*mu; + + case 1: + case 4: + case 8: + return 5 + 3*mu; + + case 2: + case 5: + return 3 + 3*mu; + + case 6: + return 3*mu; + + case 7: + return 5 + 3*mu; + + default: + AssertFatal(1 == 0, "[UE %d] ue_procedures.c: FATAL, Illegal preambleFormat %d, prachConfigIndex %d\n", mod_id, prach_format, prachConfigIndex); + } + } + return 0; +} + +// TS 38.321 subclause 5.1.3 - RA preamble transmission - ra_PREAMBLE_RECEIVED_TARGET_POWER configuration +// Measurement units: +// - preambleReceivedTargetPower dBm (-202..-60, 2 dBm granularity) +// - delta_preamble dB +// - RA_PREAMBLE_POWER_RAMPING_STEP dB +// - POWER_OFFSET_2STEP_RA dB +// returns receivedTargerPower in dBm +int nr_get_Po_NOMINAL_PUSCH(NR_PRACH_RESOURCES_t *prach_resources, module_id_t mod_id, uint8_t CC_id){ + + NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id); + int8_t receivedTargerPower; + int8_t delta_preamble; + + NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = (mac->scc != NULL) ? mac->scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup: mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.rach_ConfigCommon->choice.setup; + long preambleReceivedTargetPower = nr_rach_ConfigCommon->rach_ConfigGeneric.preambleReceivedTargetPower; + delta_preamble = nr_get_DELTA_PREAMBLE(mod_id, CC_id, prach_resources->prach_format); + + receivedTargerPower = preambleReceivedTargetPower + delta_preamble + (prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER - 1) * prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP + prach_resources->POWER_OFFSET_2STEP_RA; + + LOG_D(MAC, "In %s: receivedTargerPower is %d dBm \n", __FUNCTION__, receivedTargerPower); + + return receivedTargerPower; +} + void ssb_rach_config(RA_config_t *ra, NR_PRACH_RESOURCES_t *prach_resources, NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon, fapi_nr_ul_config_prach_pdu *prach_pdu){ // Determine the SSB to RACH mapping ratio @@ -280,6 +399,10 @@ void ra_preambles_config(NR_PRACH_RESOURCES_t *prach_resources, NR_UE_MAC_INST_t int PLThreshold = 0; long deltaPreamble_Msg3 = 0; uint8_t noGroupB = 0; + // Random seed generation + long long tmp = rdtsc_oai(); + unsigned short int *seed = (unsigned short int*)&tmp; + RA_config_t *ra = &mac->ra; NR_RACH_ConfigCommon_t *setup; if (mac->scc) setup = mac->scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup; @@ -378,28 +501,28 @@ void ra_preambles_config(NR_PRACH_RESOURCES_t *prach_resources, NR_UE_MAC_INST_t if(ra->ra_PreambleIndex < 0 || ra->ra_PreambleIndex > 63) { if (noGroupB) { // use Group A preamble - ra->ra_PreambleIndex = ra->starting_preamble_nb + ((taus()) % ra->cb_preambles_per_ssb); + ra->ra_PreambleIndex = ra->starting_preamble_nb + (nrand48(seed) % ra->cb_preambles_per_ssb); ra->RA_usedGroupA = 1; } else if ((ra->Msg3_size < messageSizeGroupA) && (dl_pathloss > PLThreshold)) { // Group B is configured and RA preamble Group A is used // - todo add condition on CCCH_sdu_size for initiation by CCCH - ra->ra_PreambleIndex = ra->starting_preamble_nb + ((taus()) % sizeOfRA_PreamblesGroupA); + ra->ra_PreambleIndex = ra->starting_preamble_nb + (nrand48(seed) % sizeOfRA_PreamblesGroupA); ra->RA_usedGroupA = 1; } else { // Group B preamble is configured and used // the first sizeOfRA_PreamblesGroupA RA preambles belong to RA Preambles Group A // the remaining belong to RA Preambles Group B - ra->ra_PreambleIndex = ra->starting_preamble_nb + sizeOfRA_PreamblesGroupA + ((taus()) % (ra->cb_preambles_per_ssb - sizeOfRA_PreamblesGroupA)); + ra->ra_PreambleIndex = ra->starting_preamble_nb + sizeOfRA_PreamblesGroupA + (nrand48(seed) % (ra->cb_preambles_per_ssb - sizeOfRA_PreamblesGroupA)); ra->RA_usedGroupA = 0; } } } else { // Msg3 is being retransmitted if (ra->RA_usedGroupA && noGroupB) { - ra->ra_PreambleIndex = ra->starting_preamble_nb + ((taus()) % ra->cb_preambles_per_ssb); + ra->ra_PreambleIndex = ra->starting_preamble_nb + (nrand48(seed) % ra->cb_preambles_per_ssb); } else if (ra->RA_usedGroupA && !noGroupB){ - ra->ra_PreambleIndex = ra->starting_preamble_nb + ((taus()) % sizeOfRA_PreamblesGroupA); + ra->ra_PreambleIndex = ra->starting_preamble_nb + (nrand48(seed) % sizeOfRA_PreamblesGroupA); } else { - ra->ra_PreambleIndex = ra->starting_preamble_nb + sizeOfRA_PreamblesGroupA + ((taus()) % (ra->cb_preambles_per_ssb - sizeOfRA_PreamblesGroupA)); + ra->ra_PreambleIndex = ra->starting_preamble_nb + sizeOfRA_PreamblesGroupA + (nrand48(seed) % (ra->cb_preambles_per_ssb - sizeOfRA_PreamblesGroupA)); } } prach_resources->ra_PreambleIndex = ra->ra_PreambleIndex; @@ -467,7 +590,8 @@ void nr_get_prach_resources(module_id_t mod_id, if (rach_ConfigDedicated) { if (rach_ConfigDedicated->cfra){ uint8_t cfra_ssb_resource_idx = 0; - prach_resources->ra_PreambleIndex = rach_ConfigDedicated->cfra->resources.choice.ssb->ssb_ResourceList.list.array[cfra_ssb_resource_idx]->ra_PreambleIndex; + ra->ra_PreambleIndex = rach_ConfigDedicated->cfra->resources.choice.ssb->ssb_ResourceList.list.array[cfra_ssb_resource_idx]->ra_PreambleIndex; + prach_resources->ra_PreambleIndex = ra->ra_PreambleIndex; LOG_D(MAC, "In %s: selected RA preamble index %d for contention-free random access procedure for SSB with Id %d\n", __FUNCTION__, prach_resources->ra_PreambleIndex, cfra_ssb_resource_idx); } } else { @@ -616,7 +740,7 @@ uint8_t nr_ue_get_rach(NR_PRACH_RESOURCES_t *prach_resources, } else { - size_sdu = nr_write_ce_ulsch_pdu(pdu, mac); + size_sdu = nr_write_ce_ulsch_pdu(pdu, mac, 0, &(mac->crnti), NULL, NULL, NULL); pdu += size_sdu; ra->Msg3_size = size_sdu; @@ -837,6 +961,9 @@ void nr_ra_failed(uint8_t mod_id, uint8_t CC_id, NR_PRACH_RESOURCES_t *prach_res NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id); RA_config_t *ra = &mac->ra; + // Random seed generation + long long tmp = rdtsc_oai(); + unsigned short int *seed = (unsigned short int*)&tmp; ra->first_Msg3 = 1; ra->ra_PreambleIndex = -1; @@ -850,7 +977,7 @@ void nr_ra_failed(uint8_t mod_id, uint8_t CC_id, NR_PRACH_RESOURCES_t *prach_res LOG_D(MAC, "In %s: [UE %d][%d.%d] Maximum number of RACH attempts (%d) reached, selecting backoff time...\n", __FUNCTION__, mod_id, frame, slot, ra->preambleTransMax); - ra->RA_backoff_cnt = rand() % (prach_resources->RA_PREAMBLE_BACKOFF + 1); + ra->RA_backoff_cnt = nrand48(seed) % (prach_resources->RA_PREAMBLE_BACKOFF + 1); prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER = 1; prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP += 2; // 2 dB increment prach_resources->ra_PREAMBLE_RECEIVED_TARGET_POWER = nr_get_Po_NOMINAL_PUSCH(prach_resources, mod_id, CC_id); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c index 7f62ee9b3e..2abcb60e91 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c @@ -51,16 +51,25 @@ void fill_dci_search_candidates(NR_SearchSpace_t *ss,fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15) { - LOG_D(MAC,"Filling search candidates for DCI\n"); + LOG_D(NR_MAC,"Filling search candidates for DCI\n"); uint8_t aggregation; - find_aggregation_candidates(&aggregation, - &rel15->number_of_candidates, - ss); + uint8_t number_of_candidates=0; + rel15->number_of_candidates=0; + int i=0; + for (int maxL=16;maxL>0;maxL>>=1) { + find_aggregation_candidates(&aggregation, + &number_of_candidates, + ss,maxL); - for (int i=0; inumber_of_candidates; i++) { - rel15->CCE[i] = i*aggregation; - rel15->L[i] = aggregation; + if (number_of_candidates>0) { + LOG_D(NR_MAC,"L %d, number of candidates %d, aggregation %d\n",maxL,number_of_candidates,aggregation); + rel15->number_of_candidates += number_of_candidates; + for (int j=0; jCCE[i] = j*aggregation; + rel15->L[i] = aggregation; + } + } } } @@ -82,18 +91,14 @@ void config_dci_pdu(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_dci_dl_pdu_rel15_t if (scc!=NULL || scc_SIB != NULL) { initialDownlinkBWP = scc!=NULL ? scc->downlinkConfigCommon->initialDownlinkBWP : &scc_SIB->downlinkConfigCommon.initialDownlinkBWP; initialUplinkBWP = scc!=NULL ? scc->uplinkConfigCommon->initialUplinkBWP : &scc_SIB->uplinkConfigCommon->initialUplinkBWP; - - bwp_Common = bwp_id>0 ? mac->DLbwp[bwp_id-1]->bwp_Common : NULL; } + bwp_Common = bwp_id>0 ? mac->DLbwp[bwp_id-1]->bwp_Common : NULL; NR_SearchSpace_t *ss; NR_ControlResourceSet_t *coreset; if(ss_id>=0) { - AssertFatal(mac->scc != NULL, "scc is null\n"); - initialDownlinkBWP = scc->downlinkConfigCommon->initialDownlinkBWP; - bwp_Common = mac->DLbwp[bwp_id - 1]->bwp_Common; - ss = mac->SSpace[bwp_id - 1][coreset_id - 1][ss_id]; - coreset = mac->coreset[bwp_id - 1][coreset_id - 1]; + ss = mac->SSpace[bwp_id][coreset_id - 1][ss_id]; + coreset = mac->coreset[bwp_id][coreset_id - 1]; rel15->coreset.CoreSetType = NFAPI_NR_CSET_CONFIG_PDCCH_CONFIG; } else { ss = mac->search_space_zero; @@ -153,7 +158,7 @@ void config_dci_pdu(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_dci_dl_pdu_rel15_t rel15->SubcarrierSpacing = bwp_Common->genericParameters.subcarrierSpacing; } for (int i = 0; i < rel15->num_dci_options; i++) { - rel15->dci_length_options[i] = nr_dci_size(initialUplinkBWP, mac->cg, &mac->def_dci_pdu_rel15[rel15->dci_format_options[i]], rel15->dci_format_options[i], NR_RNTI_C, rel15->BWPSize, bwp_id); + rel15->dci_length_options[i] = nr_dci_size(initialDownlinkBWP,initialUplinkBWP, mac->cg, &mac->def_dci_pdu_rel15[rel15->dci_format_options[i]], rel15->dci_format_options[i], NR_RNTI_C, rel15->BWPSize, bwp_id); } break; case NR_RNTI_RA: @@ -161,14 +166,15 @@ void config_dci_pdu(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_dci_dl_pdu_rel15_t sps = initialDownlinkBWP->genericParameters.cyclicPrefix == NULL ? 14 : 12; monitoringSymbolsWithinSlot = (ss->monitoringSymbolsWithinSlot->buf[0]<<(sps-8)) | (ss->monitoringSymbolsWithinSlot->buf[1]>>(16-sps)); rel15->rnti = mac->ra.ra_rnti; - rel15->BWPSize = NRRIV2BW(initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); if (get_softmodem_params()->sa) { - rel15->BWPStart = NRRIV2PRBOFFSET(initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + rel15->BWPSize = mac->type0_PDCCH_CSS_config.num_rbs; + rel15->BWPStart = mac->type0_PDCCH_CSS_config.cset_start_rb; } else { // NSA mode is not using the Initial BWP + rel15->BWPSize = NRRIV2BW(initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); rel15->BWPStart = NRRIV2PRBOFFSET(bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); } rel15->SubcarrierSpacing = initialDownlinkBWP->genericParameters.subcarrierSpacing; - rel15->dci_length_options[0] = nr_dci_size(initialUplinkBWP, mac->cg, &mac->def_dci_pdu_rel15[rel15->dci_format_options[0]], rel15->dci_format_options[0], NR_RNTI_RA, rel15->BWPSize, bwp_id); + rel15->dci_length_options[0] = nr_dci_size(initialDownlinkBWP,initialUplinkBWP, mac->cg, &mac->def_dci_pdu_rel15[rel15->dci_format_options[0]], rel15->dci_format_options[0], NR_RNTI_RA, rel15->BWPSize, bwp_id); break; case NR_RNTI_P: break; @@ -179,11 +185,12 @@ void config_dci_pdu(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_dci_dl_pdu_rel15_t sps = initialDownlinkBWP->genericParameters.cyclicPrefix == NULL ? 14 : 12; monitoringSymbolsWithinSlot = (ss->monitoringSymbolsWithinSlot->buf[0]<<(sps-8)) | (ss->monitoringSymbolsWithinSlot->buf[1]>>(16-sps)); rel15->rnti = mac->ra.t_crnti; - rel15->BWPSize = NRRIV2BW(initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - rel15->BWPStart = NRRIV2PRBOFFSET(initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + rel15->BWPSize = mac->type0_PDCCH_CSS_config.num_rbs; + rel15->BWPStart = mac->type0_PDCCH_CSS_config.cset_start_rb; rel15->SubcarrierSpacing = initialDownlinkBWP->genericParameters.subcarrierSpacing; - for (int i = 0; i < rel15->num_dci_options; i++) - rel15->dci_length_options[i] = nr_dci_size(initialUplinkBWP, mac->cg, &mac->def_dci_pdu_rel15[rel15->dci_format_options[i]], rel15->dci_format_options[i], NR_RNTI_TC, rel15->BWPSize, bwp_id); + for (int i = 0; i < rel15->num_dci_options; i++) { + rel15->dci_length_options[i] = nr_dci_size(initialDownlinkBWP,initialUplinkBWP, mac->cg, &mac->def_dci_pdu_rel15[rel15->dci_format_options[i]], rel15->dci_format_options[i], NR_RNTI_TC, rel15->BWPSize, bwp_id); + } break; case NR_RNTI_SP_CSI: break; @@ -205,7 +212,7 @@ void config_dci_pdu(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_dci_dl_pdu_rel15_t rel15->SubcarrierSpacing = mac->mib->subCarrierSpacingCommon + 2; for (int i = 0; i < rel15->num_dci_options; i++) { - rel15->dci_length_options[i] = nr_dci_size(initialUplinkBWP, mac->cg, &mac->def_dci_pdu_rel15[rel15->dci_format_options[i]], rel15->dci_format_options[i], NR_RNTI_SI, rel15->BWPSize, 0); + rel15->dci_length_options[i] = nr_dci_size(initialDownlinkBWP,initialUplinkBWP, mac->cg, &mac->def_dci_pdu_rel15[rel15->dci_format_options[i]], rel15->dci_format_options[i], NR_RNTI_SI, rel15->BWPSize, 0); } break; case NR_RNTI_SFI: @@ -248,20 +255,19 @@ void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl RA_config_t *ra = &mac->ra; int ss_id; - uint8_t bwp_id = (mac->cg) ? 1 : 0, coreset_id = (mac->cg) ? 1 : 0; + uint8_t bwp_id = (mac->cg) ? mac->DL_BWP_Id : 0, coreset_id = (mac->cg) ? 1 : 0; //NR_ServingCellConfig_t *scd = mac->scg->spCellConfig->spCellConfigDedicated; - NR_BWP_Downlink_t *bwp = (mac->cg) ? mac->DLbwp[bwp_id - 1] : NULL; + NR_BWP_DownlinkDedicated_t *bwpd = (bwp_id>0) ? mac->DLbwp[bwp_id-1]->bwp_Dedicated : mac->cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP; + NR_BWP_DownlinkCommon_t *bwp_Common = (bwp_id>0) ? mac->DLbwp[bwp_id-1]->bwp_Common : &mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP; - LOG_D(MAC, "[DCI_CONFIG] ra_rnti %p (%x) crnti %p (%x) t_crnti %p (%x)\n", &ra->ra_rnti, ra->ra_rnti, &mac->crnti, mac->crnti, &ra->t_crnti, ra->t_crnti); + LOG_D(NR_MAC, "[DCI_CONFIG] ra_rnti %p (%x) crnti %p (%x) t_crnti %p (%x)\n", &ra->ra_rnti, ra->ra_rnti, &mac->crnti, mac->crnti, &ra->t_crnti, ra->t_crnti); - if (mac->cg) { // do this only after we have a Master or Secondary Cell group - // loop over all available SS for BWP ID 1, CORESET ID 1 - if (bwp) { - for (ss_id = 0; ss_id < FAPI_NR_MAX_SS_PER_CORESET && mac->SSpace[bwp_id - 1][coreset_id - 1][ss_id] != NULL; ss_id++){ - LOG_D(MAC, "[DCI_CONFIG] ss_id %d\n",ss_id); - NR_SearchSpace_t *ss = mac->SSpace[bwp_id - 1][coreset_id - 1][ss_id]; + // loop over all available SS for CORESET ID 1 + if (bwpd) { + for (ss_id = 0; ss_id < FAPI_NR_MAX_SS_PER_CORESET && mac->SSpace[bwp_id][coreset_id - 1][ss_id] != NULL; ss_id++){ + LOG_D(NR_MAC, "[DCI_CONFIG] ss_id %d\n",ss_id); + NR_SearchSpace_t *ss = mac->SSpace[bwp_id][coreset_id - 1][ss_id]; fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15 = &dl_config->dl_config_list[dl_config->number_pdus].dci_config_pdu.dci_config_rel15; - NR_BWP_DownlinkCommon_t *bwp_Common = bwp->bwp_Common; NR_SetupRelease_PDCCH_ConfigCommon_t *pdcch_ConfigCommon = bwp_Common->pdcch_ConfigCommon; struct NR_PhysicalCellGroupConfig *phy_cgc = mac->cg->physicalCellGroupConfig; switch (ss->searchSpaceType->present){ @@ -275,7 +281,7 @@ void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl pdcch_ConfigCommon->choice.setup->searchSpaceSIB1=calloc(1,sizeof(*pdcch_ConfigCommon->choice.setup->searchSpaceSIB1)); } *pdcch_ConfigCommon->choice.setup->searchSpaceSIB1 = 0; - LOG_D(MAC, "[DCI_CONFIG] Configure SearchSpace#0 of the initial BWP\n"); + LOG_D(NR_MAC, "[DCI_CONFIG] Configure SearchSpace#0 of the initial BWP\n"); } if (ss->searchSpaceType->choice.common->dci_Format0_0_AndFormat1_0){ // check available SS IDs @@ -308,30 +314,30 @@ void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl if (pdcch_ConfigCommon->choice.setup->searchSpaceSIB1){ if (ss->searchSpaceId == *pdcch_ConfigCommon->choice.setup->searchSpaceSIB1){ // Configure monitoring of PDCCH candidates in Type0-PDCCH common search space on the MCG - LOG_W(MAC, "[DCI_CONFIG] This seach space should not be configured yet..."); + //LOG_W(MAC, "[DCI_CONFIG] This seach space should not be configured yet..."); } } if (pdcch_ConfigCommon->choice.setup->searchSpaceOtherSystemInformation){ if (ss->searchSpaceId == *pdcch_ConfigCommon->choice.setup->searchSpaceOtherSystemInformation){ // Configure monitoring of PDCCH candidates in Type0-PDCCH common search space on the MCG - LOG_W(MAC, "[DCI_CONFIG] This seach space should not be configured yet..."); + //LOG_W(MAC, "[DCI_CONFIG] This seach space should not be configured yet..."); } } if (pdcch_ConfigCommon->choice.setup->pagingSearchSpace){ if (ss->searchSpaceId == *pdcch_ConfigCommon->choice.setup->pagingSearchSpace){ // Configure monitoring of PDCCH candidates in Type2-PDCCH common search space on the MCG - LOG_W(MAC, "[DCI_CONFIG] This seach space should not be configured yet..."); + //LOG_W(MAC, "[DCI_CONFIG] This seach space should not be configured yet..."); } } if (phy_cgc){ if (phy_cgc->cs_RNTI){ LOG_D(MAC, "[DCI_CONFIG] Configure monitoring of PDCCH candidates in Type3-PDCCH common search space for dci_Format0_0_AndFormat1_0 with CRC scrambled by CS-RNTI...\n"); - LOG_W(MAC, "[DCI_CONFIG] This RNTI should not be configured yet..."); + LOG_W(MAC, "[DCI_CONFIG] This RNTI should not be configured yet...\n"); } if (phy_cgc->ext1){ if (phy_cgc->ext1->mcs_C_RNTI){ LOG_D(MAC, "[DCI_CONFIG] Configure monitoring of PDCCH candidates in user specific search space for dci_Format0_0_AndFormat1_0 with CRC scrambled by MCS-C-RNTI...\n"); - LOG_W(MAC, "[DCI_CONFIG] This RNTI should not be configured yet..."); + LOG_W(MAC, "[DCI_CONFIG] This RNTI should not be configured yet...\n"); } } } @@ -339,71 +345,68 @@ void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl // DCI 2_0 if (ss->searchSpaceType->choice.common->dci_Format2_0){ LOG_D(MAC, "[DCI_CONFIG] Configure monitoring of PDCCH candidates in Type3-PDCCH common search space for DCI format 2_0 with CRC scrambled by SFI-RNTI \n"); - LOG_W(MAC, "[DCI_CONFIG] This format should not be configured yet..."); + LOG_W(MAC, "[DCI_CONFIG] This format should not be configured yet...\n"); } // DCI 2_1 if (ss->searchSpaceType->choice.common->dci_Format2_1){ LOG_D(MAC, "[DCI_CONFIG] Configure monitoring of PDCCH candidates in Type3-PDCCH common search space for DCI format 2_1 with CRC scrambled by INT-RNTI \n"); - LOG_W(MAC, "[DCI_CONFIG] This format should not be configured yet..."); + LOG_W(MAC, "[DCI_CONFIG] This format should not be configured yet...\n"); } // DCI 2_2 if (ss->searchSpaceType->choice.common->dci_Format2_2){ LOG_D(MAC, "[DCI_CONFIG] Configure monitoring of PDCCH candidates in Type3-PDCCH common search space for DCI format 2_2 with CRC scrambled by TPC-RNTI \n"); - LOG_W(MAC, "[DCI_CONFIG] This format should not be configured yet..."); + LOG_W(MAC, "[DCI_CONFIG] This format should not be configured yet...\n"); } // DCI 2_3 if (ss->searchSpaceType->choice.common->dci_Format2_3){ LOG_D(MAC, "[DCI_CONFIG] Configure monitoring of PDCCH candidates in Type3-PDCCH common search space for DCI format 2_3 with CRC scrambled by TPC-SRS-RNTI \n"); - LOG_W(MAC, "[DCI_CONFIG] This format should not be configured yet..."); + LOG_W(MAC, "[DCI_CONFIG] This format should not be configured yet...\n"); } break; case NR_SearchSpace__searchSpaceType_PR_ue_Specific: // this is an USS - if (ss->searchSpaceType->choice.ue_Specific){ - if(ss->searchSpaceType->choice.ue_Specific->dci_Formats == NR_SearchSpace__searchSpaceType__ue_Specific__dci_Formats_formats0_1_And_1_1){ + if (ss->searchSpaceType->choice.ue_Specific && + ss->searchSpaceType->choice.ue_Specific->dci_Formats == NR_SearchSpace__searchSpaceType__ue_Specific__dci_Formats_formats0_1_And_1_1 && + (ra->ra_state == RA_SUCCEEDED || get_softmodem_params()->phy_test) && + mac->crnti > 0) { // Monitors DCI 01 and 11 scrambled with C-RNTI, or CS-RNTI(s), or SP-CSI-RNTI - if ((ra->ra_state == RA_SUCCEEDED || get_softmodem_params()->phy_test) && mac->crnti > 0) { - LOG_D(MAC, "[DCI_CONFIG] Configure monitoring of PDCCH candidates in the user specific search space\n"); - rel15->num_dci_options = 2; - rel15->dci_format_options[0] = NR_DL_DCI_FORMAT_1_1; - rel15->dci_format_options[1] = NR_UL_DCI_FORMAT_0_1; - config_dci_pdu(mac, rel15, dl_config, NR_RNTI_C, ss_id); - fill_dci_search_candidates(ss, rel15); + LOG_D(NR_MAC, "[DCI_CONFIG] Configure monitoring of PDCCH candidates in the user specific search space\n"); + rel15->num_dci_options = 2; + rel15->dci_format_options[0] = NR_DL_DCI_FORMAT_1_1; + rel15->dci_format_options[1] = NR_UL_DCI_FORMAT_0_1; + config_dci_pdu(mac, rel15, dl_config, NR_RNTI_C, ss_id); + fill_dci_search_candidates(ss, rel15); -#ifdef DEBUG_DCI - LOG_D(MAC, "[DCI_CONFIG] ss %d ue_Specific %p searchSpaceType->present %d dci_Formats %d\n", +//#ifdef DEBUG_DCI + LOG_D(NR_MAC, "[DCI_CONFIG] ss %d ue_Specific %p searchSpaceType->present %d dci_Formats %d\n", ss_id, ss->searchSpaceType->choice.ue_Specific, - ss->searchSpaceType->present, - ss->searchSpaceType->choice.ue_Specific->dci_Formats); -#endif - } - if (phy_cgc){ - if (phy_cgc->cs_RNTI){ + (int)ss->searchSpaceType->present, + (int)ss->searchSpaceType->choice.ue_Specific->dci_Formats); +//#endif + } + if (phy_cgc){ + if (phy_cgc->cs_RNTI){ LOG_D(MAC, "[DCI_CONFIG] Configure monitoring of PDCCH candidates in user specific search space for dci_Format0_0_AndFormat1_0 with CRC scrambled by CS-RNTI...\n"); LOG_W(MAC, "[DCI_CONFIG] This RNTI should not be configured yet..."); - } - if (phy_cgc->sp_CSI_RNTI){ + } + if (phy_cgc->sp_CSI_RNTI){ LOG_D(MAC, "[DCI_CONFIG] Configure monitoring of PDCCH candidates in user specific search space for dci_Format0_0_AndFormat1_0 with CRC scrambled by SP-CSI-RNTI...\n"); LOG_W(MAC, "[DCI_CONFIG] This RNTI should not be configured yet..."); - } - if (phy_cgc->ext1){ - if (phy_cgc->ext1->mcs_C_RNTI){ + } + if (phy_cgc->ext1 && + phy_cgc->ext1->mcs_C_RNTI){ LOG_D(MAC, "[DCI_CONFIG] Configure monitoring of PDCCH candidates in user specific search space for dci_Format0_0_AndFormat1_0 with CRC scrambled by MCS-C-RNTI...\n"); LOG_W(MAC, "[DCI_CONFIG] This RNTI should not be configured yet..."); - } - } - } - } + } } break; default: AssertFatal(1 == 0, "[DCI_CONFIG] Unrecognized search space type..."); break; - } - } - } + } // switch searchspace + } // for ss_id } else { @@ -411,8 +414,7 @@ void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl } // Search space 0, CORESET ID 0 - NR_BWP_DownlinkCommon_t *bwp_Common = bwp ? bwp->bwp_Common : NULL; - NR_SetupRelease_PDCCH_ConfigCommon_t *pdcch_ConfigCommon = bwp?bwp_Common->pdcch_ConfigCommon:NULL; + NR_SetupRelease_PDCCH_ConfigCommon_t *pdcch_ConfigCommon = bwp_Common->pdcch_ConfigCommon; if (pdcch_ConfigCommon && pdcch_ConfigCommon->choice.setup->searchSpaceSIB1){ diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 6e22a05b17..d555014bc8 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -54,7 +54,6 @@ /* PHY */ #include "PHY/NR_TRANSPORT/nr_dci.h" #include "executables/softmodem-common.h" -#include "SCHED_NR_UE/defs.h" /* utils */ #include "assertions.h" @@ -135,6 +134,131 @@ const initial_pucch_resource_t initial_pucch_resource[16] = { }; +void nr_ue_init_mac(module_id_t module_idP) { + int i; + + NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP); + // default values as deined in 38.331 sec 9.2.2 + LOG_I(NR_MAC, "[UE%d] Applying default macMainConfig\n", module_idP); + //mac->scheduling_info.macConfig=NULL; + mac->scheduling_info.retxBSR_Timer = NR_BSR_Config__retxBSR_Timer_sf10240; + mac->scheduling_info.periodicBSR_Timer = NR_BSR_Config__periodicBSR_Timer_infinity; +// mac->scheduling_info.periodicPHR_Timer = NR_MAC_MainConfig__phr_Config__setup__periodicPHR_Timer_sf20; +// mac->scheduling_info.prohibitPHR_Timer = NR_MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf20; +// mac->scheduling_info.PathlossChange_db = NR_MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB1; +// mac->PHR_state = NR_MAC_MainConfig__phr_Config_PR_setup; + mac->scheduling_info.SR_COUNTER = 0; + mac->scheduling_info.sr_ProhibitTimer = 0; + mac->scheduling_info.sr_ProhibitTimer_Running = 0; +// mac->scheduling_info.maxHARQ_Tx = NR_MAC_MainConfig__ul_SCH_Config__maxHARQ_Tx_n5; +// mac->scheduling_info.ttiBundling = 0; +// mac->scheduling_info.extendedBSR_Sizes_r10 = 0; +// mac->scheduling_info.extendedPHR_r10 = 0; +// mac->scheduling_info.drx_config = NULL; +// mac->scheduling_info.phr_config = NULL; + // set init value 0xFFFF, make sure periodic timer and retx time counters are NOT active, after bsr transmission set the value configured by the NW. + mac->scheduling_info.periodicBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING; + mac->scheduling_info.retxBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING; + mac->BSR_reporting_active = BSR_TRIGGER_NONE; +// mac->scheduling_info.periodicPHR_SF = nr_get_sf_perioidicPHR_Timer(mac->scheduling_info.periodicPHR_Timer); +// mac->scheduling_info.prohibitPHR_SF = nr_get_sf_prohibitPHR_Timer(mac->scheduling_info.prohibitPHR_Timer); +// mac->scheduling_info.PathlossChange_db = nr_get_db_dl_PathlossChange(mac->scheduling_info.PathlossChange); +// mac->PHR_reporting_active = 0; + + for (i = 0; i < NR_MAX_NUM_LCID; i++) { + LOG_D(NR_MAC, "[UE%d] Applying default logical channel config for LCGID %d\n", + module_idP, i); + mac->scheduling_info.Bj[i] = -1; + mac->scheduling_info.bucket_size[i] = -1; + + if (i < UL_SCH_LCID_DTCH) { // initialize all control channels lcgid to 0 + mac->scheduling_info.LCGID[i] = 0; + } else { // initialize all the data channels lcgid to 1 + mac->scheduling_info.LCGID[i] = 1; + } + + mac->scheduling_info.LCID_status[i] = LCID_EMPTY; + mac->scheduling_info.LCID_buffer_remain[i] = 0; + for (int i=0;ifirst_ul_tx[i]=1; + } +} + +void get_bwp_info(NR_UE_MAC_INST_t *mac, + int dl_bwp_id, + int ul_bwp_id, + NR_BWP_DownlinkDedicated_t **bwpd, + NR_BWP_DownlinkCommon_t **bwpc, + NR_BWP_UplinkDedicated_t **ubwpd, + NR_BWP_UplinkCommon_t **ubwpc) { + + if (dl_bwp_id > 0) { + AssertFatal(mac->DLbwp[dl_bwp_id-1]!=NULL,"mac->DLbwp[%d] is null, shouldn't be\n", + (int)dl_bwp_id-1); + *bwpd = mac->DLbwp[dl_bwp_id-1]->bwp_Dedicated; + if (mac->DLbwp[dl_bwp_id-1]->bwp_Common) *bwpc = mac->DLbwp[dl_bwp_id-1]->bwp_Common; + else if (mac->scc_SIB) *bwpc = &mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP; + else if (mac->scc) *bwpc = mac->scc->downlinkConfigCommon->initialDownlinkBWP; + AssertFatal(*bwpc!=NULL,"bwpc shouldn't be null\n"); + } else { + if (mac->cg && + mac->cg->spCellConfig && + mac->cg->spCellConfig->spCellConfigDedicated && + mac->cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP) + *bwpd = mac->cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP; + if (mac->scc_SIB) *bwpc = &mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP; + else if (mac->scc) *bwpc = mac->scc->downlinkConfigCommon->initialDownlinkBWP; + AssertFatal(*bwpc!=NULL,"bwpc shouldn't be null\n"); + } + + if (ul_bwp_id > 0) { + AssertFatal(mac->ULbwp[ul_bwp_id-1]!=NULL,"mac->ULbwp[%d] is null, shouldn't be\n", + ul_bwp_id-1); + *ubwpd = mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated; + if (mac->ULbwp[ul_bwp_id-1]->bwp_Common) *ubwpc = mac->ULbwp[ul_bwp_id-1]->bwp_Common; + else if (mac->scc_SIB) *ubwpc = &mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP; + else if (mac->scc) *ubwpc = mac->scc->uplinkConfigCommon->initialUplinkBWP; + AssertFatal(*bwpc!=NULL,"bwpc shouldn't be null\n"); + + } + else { + if (mac->cg && + mac->cg->spCellConfig && + mac->cg->spCellConfig->spCellConfigDedicated && + mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig && + mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) + *ubwpd = mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; + if (mac->scc_SIB) *ubwpc = &mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP; + else if (mac->scc) *ubwpc = mac->scc->uplinkConfigCommon->initialUplinkBWP; + AssertFatal(*ubwpc!=NULL,"ubwpc shouldn't be null\n"); + } +} + +NR_PDSCH_TimeDomainResourceAllocationList_t *choose_dl_tda_list(NR_PDSCH_Config_t *pdsch_Config,NR_PDSCH_ConfigCommon_t *pdsch_ConfigCommon) { + + NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList=NULL; + + if (pdsch_Config && + pdsch_Config->pdsch_TimeDomainAllocationList) + pdsch_TimeDomainAllocationList = pdsch_Config->pdsch_TimeDomainAllocationList->choice.setup; + else if (pdsch_ConfigCommon->pdsch_TimeDomainAllocationList) + pdsch_TimeDomainAllocationList = pdsch_ConfigCommon->pdsch_TimeDomainAllocationList; + + return(pdsch_TimeDomainAllocationList); +} + +NR_PUSCH_TimeDomainResourceAllocationList_t *choose_ul_tda_list(NR_PUSCH_Config_t *pusch_Config,NR_PUSCH_ConfigCommon_t *pusch_ConfigCommon) { + + NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList=NULL; + + if (pusch_Config && + pusch_Config->pusch_TimeDomainAllocationList) + pusch_TimeDomainAllocationList = pusch_Config->pusch_TimeDomainAllocationList->choice.setup; + else if (pusch_ConfigCommon->pusch_TimeDomainAllocationList) + pusch_TimeDomainAllocationList = pusch_ConfigCommon->pusch_TimeDomainAllocationList; + + return(pusch_TimeDomainAllocationList); +} + int get_rnti_type(NR_UE_MAC_INST_t *mac, uint16_t rnti){ RA_config_t *ra = &mac->ra; @@ -171,7 +295,7 @@ int8_t nr_ue_decode_mib(module_id_t module_id, uint16_t ssb_start_subcarrier, uint16_t cell_id) { - LOG_I(MAC,"[L2][MAC] decode mib\n"); + LOG_D(MAC,"[L2][MAC] decode mib\n"); NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); mac->physCellId = cell_id; @@ -342,6 +466,8 @@ int8_t nr_ue_process_dci_freq_dom_resource_assignment(nfapi_nr_ue_pusch_pdu_t *p } int8_t nr_ue_process_dci_time_dom_resource_assignment(NR_UE_MAC_INST_t *mac, + NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList, + NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList, nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu, fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config_pdu, uint8_t time_domain_ind, @@ -398,17 +524,6 @@ int8_t nr_ue_process_dci_time_dom_resource_assignment(NR_UE_MAC_INST_t *mac, * TS 38.214 subclause 5.1.2.1 Resource allocation in time domain (downlink) */ if(dlsch_config_pdu != NULL){ - NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList = NULL; - if (mac->DLbwp[0] && - mac->DLbwp[0]->bwp_Dedicated && - mac->DLbwp[0]->bwp_Dedicated->pdsch_Config && - mac->DLbwp[0]->bwp_Dedicated->pdsch_Config->choice.setup->pdsch_TimeDomainAllocationList) - pdsch_TimeDomainAllocationList = mac->DLbwp[0]->bwp_Dedicated->pdsch_Config->choice.setup->pdsch_TimeDomainAllocationList->choice.setup; - else if (mac->DLbwp[0] && mac->DLbwp[0]->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList) - pdsch_TimeDomainAllocationList = mac->DLbwp[0]->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; - else if (mac->scc_SIB && mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP.pdsch_ConfigCommon->choice.setup) - pdsch_TimeDomainAllocationList = mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP.pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; - if (pdsch_TimeDomainAllocationList && use_default==false) { if (time_domain_ind >= pdsch_TimeDomainAllocationList->list.count) { @@ -446,23 +561,6 @@ int8_t nr_ue_process_dci_time_dom_resource_assignment(NR_UE_MAC_INST_t *mac, * TS 38.214 subclause 6.1.2.1 Resource allocation in time domain (uplink) */ if(pusch_config_pdu != NULL){ - NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = NULL; - if (mac->ULbwp[0] && - mac->ULbwp[0]->bwp_Dedicated && - mac->ULbwp[0]->bwp_Dedicated->pusch_Config && - mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup && - mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup->pusch_TimeDomainAllocationList) { - pusch_TimeDomainAllocationList = mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup->pusch_TimeDomainAllocationList->choice.setup; - } - else if (mac->ULbwp[0] && - mac->ULbwp[0]->bwp_Common && - mac->ULbwp[0]->bwp_Common->pusch_ConfigCommon && - mac->ULbwp[0]->bwp_Common->pusch_ConfigCommon->choice.setup && - mac->ULbwp[0]->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList) { - pusch_TimeDomainAllocationList = mac->ULbwp[0]->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; - } - else pusch_TimeDomainAllocationList = mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; - if (pusch_TimeDomainAllocationList && use_default==false) { if (time_domain_ind >= pusch_TimeDomainAllocationList->list.count) { LOG_E(MAC, "time_domain_ind %d >= pusch->TimeDomainAllocationList->list.count %d\n", @@ -638,7 +736,7 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr // Config PUSCH PDU ret = nr_config_pusch_pdu(mac, pusch_config_pdu, dci, NULL, rnti, &dci_format); - } + } else AssertFatal(1==0,"Cannot schedule PUSCH\n"); break; } @@ -698,8 +796,7 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config_pdu_1_0 = &dl_config->dl_config_list[dl_config->number_pdus].dlsch_config_pdu.dlsch_config_rel15; NR_PDSCH_Config_t *pdsch_config= (mac->DLbwp[0]) ? mac->DLbwp[0]->bwp_Dedicated->pdsch_Config->choice.setup : NULL; - uint16_t BWPSize = n_RB_DLBWP; - + int is_common=0; if(rnti == SI_RNTI) { NR_Type0_PDCCH_CSS_config_t type0_PDCCH_CSS_config = mac->type0_PDCCH_CSS_config; default_abc = type0_PDCCH_CSS_config.type0_pdcch_ss_mux_pattern; @@ -708,7 +805,6 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr dlsch_config_pdu_1_0->BWPStart = mac->type0_PDCCH_CSS_config.cset_start_rb; dlsch_config_pdu_1_0->SubcarrierSpacing = mac->mib->subCarrierSpacingCommon; if (pdsch_config) pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = NULL; // For PDSCH with mapping type A, the UE shall assume dmrs-AdditionalPosition='pos2' - BWPSize = dlsch_config_pdu_1_0->BWPSize; } else { if (ra->RA_window_cnt >= 0 && rnti == ra->ra_rnti){ dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_RA_DLSCH; @@ -716,9 +812,10 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_DLSCH; } if( (ra->RA_window_cnt >= 0 && rnti == ra->ra_rnti) || (rnti == ra->t_crnti) ) { - if (mac->scc == NULL) { - dlsch_config_pdu_1_0->BWPSize = NRRIV2BW(mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP.genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - dlsch_config_pdu_1_0->BWPStart = NRRIV2PRBOFFSET(mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP.genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + if (mac->scc == NULL) { // use coreset0 + dlsch_config_pdu_1_0->BWPSize = mac->type0_PDCCH_CSS_config.num_rbs; + dlsch_config_pdu_1_0->BWPStart = mac->type0_PDCCH_CSS_config.cset_start_rb; + is_common=1; } else { dlsch_config_pdu_1_0->BWPSize = NRRIV2BW(mac->scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); @@ -727,7 +824,6 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr if (!get_softmodem_params()->sa) { // NSA mode is not using the Initial BWP dlsch_config_pdu_1_0->BWPStart = NRRIV2PRBOFFSET(mac->DLbwp[0]->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); pdsch_config = mac->DLbwp[0]->bwp_Dedicated->pdsch_Config->choice.setup; - BWPSize = dlsch_config_pdu_1_0->BWPSize; } } else if (mac->DLbwp[0]) { dlsch_config_pdu_1_0->BWPSize = NRRIV2BW(mac->DLbwp[0]->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); @@ -744,15 +840,11 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr /* IDENTIFIER_DCI_FORMATS */ /* FREQ_DOM_RESOURCE_ASSIGNMENT_DL */ - if (nr_ue_process_dci_freq_dom_resource_assignment(NULL,dlsch_config_pdu_1_0,0,BWPSize,dci->frequency_domain_assignment.val) < 0) { + if (nr_ue_process_dci_freq_dom_resource_assignment(NULL,dlsch_config_pdu_1_0,0,dlsch_config_pdu_1_0->BWPSize,dci->frequency_domain_assignment.val) < 0) { LOG_W(MAC, "[%d.%d] Invalid frequency_domain_assignment. Possibly due to false DCI. Ignoring DCI!\n", frame, slot); return -1; } - /* TIME_DOM_RESOURCE_ASSIGNMENT */ - if (nr_ue_process_dci_time_dom_resource_assignment(mac,NULL,dlsch_config_pdu_1_0,dci->time_domain_assignment.val,default_abc,rnti==SI_RNTI) < 0) { - LOG_W(MAC, "[%d.%d] Invalid time_domain_assignment. Possibly due to false DCI. Ignoring DCI!\n", frame, slot); - return -1; - } + NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList = NULL; if (mac->DLbwp[0] && @@ -765,6 +857,11 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr else if (mac->scc_SIB && mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP.pdsch_ConfigCommon->choice.setup) pdsch_TimeDomainAllocationList = mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP.pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; + /* TIME_DOM_RESOURCE_ASSIGNMENT */ + if (nr_ue_process_dci_time_dom_resource_assignment(mac,NULL,pdsch_TimeDomainAllocationList,NULL,dlsch_config_pdu_1_0,dci->time_domain_assignment.val,default_abc,rnti==SI_RNTI) < 0) { + LOG_W(MAC, "[%d.%d] Invalid time_domain_assignment. Possibly due to false DCI. Ignoring DCI!\n", frame, slot); + return -1; + } int mappingtype = pdsch_TimeDomainAllocationList ? pdsch_TimeDomainAllocationList->list.array[dci->time_domain_assignment.val]->mappingType : ((dlsch_config_pdu_1_0->start_symbol <= 3)? typeA: typeB); /* dmrs symbol positions*/ @@ -851,7 +948,7 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr dlsch_config_pdu_1_0->accumulated_delta_PUCCH, 1+dci->pdsch_to_harq_feedback_timing_indicator.val, dci->dai[0].val, - dci_ind->n_CCE,dci_ind->N_CCE, + dci_ind->n_CCE,dci_ind->N_CCE,is_common, frame,slot); LOG_D(MAC,"(nr_ue_procedures.c) rnti = %x dl_config->number_pdus = %d\n", @@ -917,22 +1014,29 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr * 47 DMRS_SEQ_INI: */ - if (dci->bwp_indicator.val != 1) { - LOG_W(MAC, "[%d.%d] bwp_indicator != 1! Possibly due to false DCI. Ignoring DCI!\n", frame, slot); + if (dci->bwp_indicator.val > 1) { + LOG_W(NR_MAC,"[%d.%d] bwp_indicator %d > 1 Possibly due to false DCI. Ignoring DCI!\n", frame, slot,dci->bwp_indicator.val); return -1; } config_bwp_ue(mac, &dci->bwp_indicator.val, &dci_format); NR_BWP_Id_t dl_bwp_id = mac->DL_BWP_Id; - NR_PDSCH_Config_t *pdsch_config=mac->DLbwp[dl_bwp_id-1]->bwp_Dedicated->pdsch_Config->choice.setup; + NR_BWP_Id_t ul_bwp_id = mac->UL_BWP_Id; + NR_PDSCH_Config_t *pdsch_Config=NULL; + NR_BWP_DownlinkDedicated_t *bwpd=NULL; + NR_BWP_DownlinkCommon_t *bwpc=NULL; + NR_BWP_UplinkDedicated_t *ubwpd=NULL; + NR_BWP_UplinkCommon_t *ubwpc=NULL; + get_bwp_info(mac,dl_bwp_id,ul_bwp_id,&bwpd,&bwpc,&ubwpd,&ubwpc); + pdsch_Config = bwpd->pdsch_Config->choice.setup; dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_DLSCH; dl_config->dl_config_list[dl_config->number_pdus].dlsch_config_pdu.rnti = rnti; fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config_pdu_1_1 = &dl_config->dl_config_list[dl_config->number_pdus].dlsch_config_pdu.dlsch_config_rel15; - dlsch_config_pdu_1_1->BWPSize = NRRIV2BW(mac->DLbwp[0]->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - dlsch_config_pdu_1_1->BWPStart = NRRIV2PRBOFFSET(mac->DLbwp[0]->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - dlsch_config_pdu_1_1->SubcarrierSpacing = mac->DLbwp[0]->bwp_Common->genericParameters.subcarrierSpacing; + dlsch_config_pdu_1_1->BWPSize = NRRIV2BW(bwpc->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + dlsch_config_pdu_1_1->BWPStart = NRRIV2PRBOFFSET(bwpc->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + dlsch_config_pdu_1_1->SubcarrierSpacing = bwpc->genericParameters.subcarrierSpacing; /* IDENTIFIER_DCI_FORMATS */ /* CARRIER_IND */ @@ -944,38 +1048,28 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr return -1; } /* TIME_DOM_RESOURCE_ASSIGNMENT */ - if (nr_ue_process_dci_time_dom_resource_assignment(mac,NULL,dlsch_config_pdu_1_1,dci->time_domain_assignment.val,0,false) < 0) { + NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList = choose_dl_tda_list(pdsch_Config,bwpc->pdsch_ConfigCommon->choice.setup); + if (nr_ue_process_dci_time_dom_resource_assignment(mac,NULL,pdsch_TimeDomainAllocationList,NULL,dlsch_config_pdu_1_1,dci->time_domain_assignment.val,0,false) < 0) { LOG_W(MAC, "[%d.%d] Invalid time_domain_assignment. Possibly due to false DCI. Ignoring DCI!\n", frame, slot); return -1; } - NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList = NULL; - if (mac->DLbwp[0] && - mac->DLbwp[0]->bwp_Dedicated && - mac->DLbwp[0]->bwp_Dedicated->pdsch_Config && - mac->DLbwp[0]->bwp_Dedicated->pdsch_Config->choice.setup->pdsch_TimeDomainAllocationList) - pdsch_TimeDomainAllocationList = mac->DLbwp[0]->bwp_Dedicated->pdsch_Config->choice.setup->pdsch_TimeDomainAllocationList->choice.setup; - else if (mac->DLbwp[0] && mac->DLbwp[0]->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList) - pdsch_TimeDomainAllocationList = mac->DLbwp[0]->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; - else if (mac->scc_SIB && mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP.pdsch_ConfigCommon->choice.setup) - pdsch_TimeDomainAllocationList = mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP.pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; - int mappingtype = pdsch_TimeDomainAllocationList ? pdsch_TimeDomainAllocationList->list.array[dci->time_domain_assignment.val]->mappingType : ((dlsch_config_pdu_1_1->start_symbol <= 3)? typeA: typeB); /* dmrs symbol positions*/ - dlsch_config_pdu_1_1->dlDmrsSymbPos = fill_dmrs_mask(pdsch_config, - mac->scc->dmrs_TypeA_Position, + dlsch_config_pdu_1_1->dlDmrsSymbPos = fill_dmrs_mask(pdsch_Config, + mac->scc? mac->scc->dmrs_TypeA_Position:mac->mib->dmrs_TypeA_Position, dlsch_config_pdu_1_1->number_symbols, dlsch_config_pdu_1_1->start_symbol, mappingtype); - dlsch_config_pdu_1_1->dmrsConfigType = mac->DLbwp[dl_bwp_id-1]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type == NULL ? NFAPI_NR_DMRS_TYPE1 : NFAPI_NR_DMRS_TYPE2; + dlsch_config_pdu_1_1->dmrsConfigType = pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type == NULL ? NFAPI_NR_DMRS_TYPE1 : NFAPI_NR_DMRS_TYPE2; /* TODO: fix number of DM-RS CDM groups without data according to subclause 5.1.6.2 of 3GPP TS 38.214, using tables 7.3.1.2.2-1, 7.3.1.2.2-2, 7.3.1.2.2-3, 7.3.1.2.2-4 of 3GPP TS 38.212 */ dlsch_config_pdu_1_1->n_dmrs_cdm_groups = 1; /* VRB_TO_PRB_MAPPING */ - if ((pdsch_config->resourceAllocation == 1) && (pdsch_config->vrb_ToPRB_Interleaver != NULL)) + if ((pdsch_Config->resourceAllocation == 1) && (pdsch_Config->vrb_ToPRB_Interleaver != NULL)) dlsch_config_pdu_1_1->vrb_to_prb_mapping = (dci->vrb_to_prb_mapping.val == 0) ? vrb_to_prb_mapping_non_interleaved:vrb_to_prb_mapping_interleaved; /* PRB_BUNDLING_SIZE_IND */ dlsch_config_pdu_1_1->prb_bundling_size_ind = dci->prb_bundling_size_indicator.val; @@ -1016,9 +1110,9 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr // Sanity check for pucch_resource_indicator value received to check for false DCI. valid = 0; - pucch_res_set_cnt = mac->ULbwp[0]->bwp_Dedicated->pucch_Config->choice.setup->resourceSetToAddModList->list.count; + pucch_res_set_cnt = ubwpd->pucch_Config->choice.setup->resourceSetToAddModList->list.count; for (int id = 0; id < pucch_res_set_cnt; id++) { - if (dci->pucch_resource_indicator < mac->ULbwp[0]->bwp_Dedicated->pucch_Config->choice.setup->resourceSetToAddModList->list.array[id]->resourceList.list.count) { + if (dci->pucch_resource_indicator < ubwpd->pucch_Config->choice.setup->resourceSetToAddModList->list.array[id]->resourceList.list.count) { valid = 1; break; } @@ -1032,13 +1126,13 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr uint8_t n_codewords = 1; // FIXME!!! long *max_length = NULL; long *dmrs_type = NULL; - if (pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA) { - max_length = pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->maxLength; - dmrs_type = pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type; + if (pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA) { + max_length = pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->maxLength; + dmrs_type = pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type; } - if (pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeB) { - max_length = pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup->maxLength; - dmrs_type = pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup->dmrs_Type; + if (pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB) { + max_length = pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup->maxLength; + dmrs_type = pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup->dmrs_Type; } if ((dmrs_type == NULL) && (max_length == NULL)){ // Table 7.3.1.2.2-1: Antenna port(s) (1000 + DMRS port), dmrs-Type=1, maxLength=1 @@ -1133,9 +1227,8 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr /* PDSCH_TO_HARQ_FEEDBACK_TIME_IND */ // according to TS 38.213 Table 9.2.3-1 - NR_BWP_Id_t ul_bwp_id = mac->UL_BWP_Id; uint8_t feedback_ti = - mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pucch_Config->choice.setup->dl_DataToUL_ACK->list.array[dci->pdsch_to_harq_feedback_timing_indicator.val][0]; + ubwpd->pucch_Config->choice.setup->dl_DataToUL_ACK->list.array[dci->pdsch_to_harq_feedback_timing_indicator.val][0]; // set the harq status at MAC for feedback set_harq_status(mac,dci->pucch_resource_indicator, @@ -1143,7 +1236,7 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr dlsch_config_pdu_1_1->accumulated_delta_PUCCH, feedback_ti, dci->dai[0].val, - dci_ind->n_CCE,dci_ind->N_CCE, + dci_ind->n_CCE,dci_ind->N_CCE,0, frame,slot); dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_DLSCH; @@ -1151,10 +1244,10 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr dl_config->number_pdus = dl_config->number_pdus + 1; /* TODO same calculation for MCS table as done in UL */ - dlsch_config_pdu_1_1->mcs_table = (pdsch_config->mcs_Table) ? (*pdsch_config->mcs_Table + 1) : 0; + dlsch_config_pdu_1_1->mcs_table = (pdsch_Config->mcs_Table) ? (*pdsch_Config->mcs_Table + 1) : 0; /*PTRS configuration */ - if(mac->DLbwp[dl_bwp_id-1]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS != NULL) { - valid_ptrs_setup = set_dl_ptrs_values(mac->DLbwp[dl_bwp_id-1]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup, + if(pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS != NULL) { + valid_ptrs_setup = set_dl_ptrs_values(pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup, dlsch_config_pdu_1_1->number_rbs, dlsch_config_pdu_1_1->mcs, dlsch_config_pdu_1_1->mcs_table, &dlsch_config_pdu_1_1->PTRSFreqDensity,&dlsch_config_pdu_1_1->PTRSTimeDensity, &dlsch_config_pdu_1_1->PTRSPortIndex,&dlsch_config_pdu_1_1->nEpreRatioOfPDSCHToPTRS, @@ -1213,6 +1306,7 @@ void set_harq_status(NR_UE_MAC_INST_t *mac, uint8_t dai, int n_CCE, int N_CCE, + int is_common, frame_t frame, int slot) { @@ -1222,6 +1316,7 @@ void set_harq_status(NR_UE_MAC_INST_t *mac, current_harq->ack_received = false; current_harq->pucch_resource_indicator = pucch_id; current_harq->feedback_to_ul = data_toul_fb; + current_harq->is_common = is_common; current_harq->dai = dai; current_harq->n_CCE = n_CCE; current_harq->N_CCE = N_CCE; @@ -1230,6 +1325,7 @@ void set_harq_status(NR_UE_MAC_INST_t *mac, current_harq->dl_frame = frame; current_harq->dl_slot = slot; + LOG_D(PHY,"Setting harq_status for harq_id %d, dl %d.%d\n",harq_id,frame,slot); } @@ -1242,6 +1338,8 @@ void update_harq_status(nr_downlink_indication_t *dl_info, int pdu_id) { if (current_harq->active) { current_harq->ack = dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.ack_nack; current_harq->ack_received = true; + LOG_D(PHY,"Updating harq_status for harq_id %d,ack/nak %d\n",harq_pid,current_harq->ack); + } else { //shouldn't get here @@ -1283,6 +1381,7 @@ void nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, pucch_pdu->rnti = rnti; + LOG_D(NR_MAC,"initial_pucch_id %d, pucch_resource %p\n",pucch->initial_pucch_id,pucch->pucch_resource); // configure pucch from Table 9.2.1-1 if (pucch->initial_pucch_id > -1 && pucch->pucch_resource == NULL) { @@ -1345,7 +1444,7 @@ void nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, mac->cg->physicalCellGroupConfig && (mac->cg->physicalCellGroupConfig->harq_ACK_SpatialBundlingPUCCH != NULL || mac->cg->physicalCellGroupConfig->pdsch_HARQ_ACK_Codebook != 1)) { - LOG_E(PHY,"PUCCH Unsupported cell group configuration : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); + LOG_E(MAC,"PUCCH Unsupported cell group configuration : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return; } else if (mac->cg && @@ -1388,33 +1487,6 @@ void nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, } else AssertFatal(1==0,"no pucch_Config\n"); - NR_PUCCH_ConfigCommon_t *pucch_ConfigCommon; - if (mac->scc) pucch_ConfigCommon = mac->scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup; - else pucch_ConfigCommon = mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.pucch_ConfigCommon->choice.setup; - if (pucch_ConfigCommon->hoppingId != NULL) - pucch_pdu->hopping_id = *pucch_ConfigCommon->hoppingId; - else - pucch_pdu->hopping_id = mac->physCellId; - - switch (pucch_ConfigCommon->pucch_GroupHopping){ - case 0 : - // if neither, both disabled - pucch_pdu->group_hop_flag = 0; - pucch_pdu->sequence_hop_flag = 0; - break; - case 1 : - // if enable, group enabled - pucch_pdu->group_hop_flag = 1; - pucch_pdu->sequence_hop_flag = 0; - break; - case 2 : - // if disable, sequence disabled - pucch_pdu->group_hop_flag = 0; - pucch_pdu->sequence_hop_flag = 1; - break; - default: - AssertFatal(1==0,"Group hopping flag undefined (0,1,2) \n"); - } pucch_pdu->prb_start = pucchres->startingPRB; pucch_pdu->freq_hop_flag = pucchres->intraSlotFrequencyHopping!= NULL ? 1 : 0; @@ -1516,6 +1588,7 @@ void nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, default : AssertFatal(1==0,"Undefined PUCCH format \n"); } + pucch_pdu->pucch_tx_power = get_pucch_tx_power_ue(mac, pucch_Config, pucch, @@ -1523,11 +1596,47 @@ void nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, pucch_pdu->prb_size, pucch_pdu->freq_hop_flag, pucch_pdu->add_dmrs_flag, - pucch_pdu->nr_of_symbols, - subframe_number, - O_ACK, O_SR, - O_CSI, O_CRC); + pucch_pdu->nr_of_symbols, + subframe_number, + O_ACK, O_SR, + O_CSI, O_CRC); } + else AssertFatal(1==0,"problem with pucch configuration\n"); + + NR_PUCCH_ConfigCommon_t *pucch_ConfigCommon; + if (bwp_id>0 && + mac->ULbwp[bwp_id-1] && + mac->ULbwp[bwp_id-1]->bwp_Common && + mac->ULbwp[bwp_id-1]->bwp_Common->pucch_ConfigCommon) + pucch_ConfigCommon = mac->ULbwp[bwp_id-1]->bwp_Common->pucch_ConfigCommon->choice.setup; + else if (mac->scc) pucch_ConfigCommon = mac->scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup; + else pucch_ConfigCommon = mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.pucch_ConfigCommon->choice.setup; + if (pucch_ConfigCommon->hoppingId != NULL) + pucch_pdu->hopping_id = *pucch_ConfigCommon->hoppingId; + else + pucch_pdu->hopping_id = mac->physCellId; + + switch (pucch_ConfigCommon->pucch_GroupHopping){ + case 0 : + // if neither, both disabled + pucch_pdu->group_hop_flag = 0; + pucch_pdu->sequence_hop_flag = 0; + break; + case 1 : + // if enable, group enabled + pucch_pdu->group_hop_flag = 1; + pucch_pdu->sequence_hop_flag = 0; + break; + case 2 : + // if disable, sequence disabled + pucch_pdu->group_hop_flag = 0; + pucch_pdu->sequence_hop_flag = 1; + break; + default: + AssertFatal(1==0,"Group hopping flag undefined (0,1,2) \n"); + } + + } @@ -1761,7 +1870,8 @@ void select_pucch_resource(NR_UE_MAC_INST_t *mac, NR_BWP_Id_t bwp_id = mac->UL_BWP_Id; int n_list; - if ((bwp_id == 0 && + if (pucch->is_common == 1 || + (bwp_id == 0 && mac->cg == NULL) || (bwp_id == 0 && mac->cg && @@ -1881,33 +1991,26 @@ uint8_t get_downlink_ack(NR_UE_MAC_INST_t *mac, int V_DAI_m_DL = 0; NR_UE_HARQ_STATUS_t *current_harq; int sched_frame,sched_slot; - NR_BWP_UplinkCommon_t *initialUplinkBWP; - if (mac->scc) initialUplinkBWP = mac->scc->uplinkConfigCommon->initialUplinkBWP; - else initialUplinkBWP = &mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP; int slots_per_frame,scs; - if (mac->DLbwp[0] && - mac->DLbwp[0]->bwp_Dedicated && - mac->DLbwp[0]->bwp_Dedicated->pdsch_Config && - mac->DLbwp[0]->bwp_Dedicated->pdsch_Config->choice.setup && - mac->DLbwp[0]->bwp_Dedicated->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI[0] == 2) { + NR_BWP_Id_t dl_bwp_id = mac->DL_BWP_Id; + NR_BWP_Id_t ul_bwp_id = mac->UL_BWP_Id; + NR_BWP_DownlinkDedicated_t *bwpd=NULL; + NR_BWP_DownlinkCommon_t *bwpc=NULL; + NR_BWP_UplinkDedicated_t *ubwpd=NULL; + NR_BWP_UplinkCommon_t *ubwpc=NULL; + get_bwp_info(mac,dl_bwp_id,ul_bwp_id,&bwpd,&bwpc,&ubwpd,&ubwpc); + + if (bwpd && + bwpd->pdsch_Config && + bwpd->pdsch_Config->choice.setup && + bwpd->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI && + bwpd->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI[0] == 2) { two_transport_blocks = TRUE; number_of_code_word = 2; } - else { - number_of_code_word = 1; - } - NR_BWP_Uplink_t *ubwp = mac->ULbwp[0]; - if (mac->cg && ubwp && - mac->cg->spCellConfig && - mac->cg->spCellConfig->spCellConfigDedicated && - mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig && - mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { - scs = ubwp->bwp_Common->genericParameters.subcarrierSpacing; - } - else - scs = initialUplinkBWP->genericParameters.subcarrierSpacing; + scs = ubwpc->genericParameters.subcarrierSpacing; slots_per_frame = nr_slots_per_frame[scs]; @@ -1926,7 +2029,7 @@ uint8_t get_downlink_ack(NR_UE_MAC_INST_t *mac, sched_slot %= slots_per_frame; sched_frame++; } - + LOG_D(PHY,"HARQ pid %d is active for %d.%d (dl_slot %d, feedback_to_ul %d, is_common %d\n",dl_harq_pid, sched_frame,sched_slot,current_harq->dl_slot,current_harq->feedback_to_ul,current_harq->is_common); /* check if current tx slot should transmit downlink acknowlegment */ if (sched_frame == frame && sched_slot == slot) { @@ -1959,6 +2062,7 @@ uint8_t get_downlink_ack(NR_UE_MAC_INST_t *mac, pucch->n_CCE = current_harq->n_CCE; pucch->N_CCE = current_harq->N_CCE; pucch->delta_pucch = current_harq->delta_pucch; + pucch->is_common = current_harq->is_common; current_harq->active = false; current_harq->ack_received = false; } @@ -1986,7 +2090,7 @@ uint8_t get_downlink_ack(NR_UE_MAC_INST_t *mac, if (mac->cg != NULL && mac->cg->physicalCellGroupConfig != NULL && mac->cg->physicalCellGroupConfig->harq_ACK_SpatialBundlingPUCCH != NULL) { - int N_TB_max_DL = mac->DLbwp[0]->bwp_Dedicated->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI[0]; + int N_TB_max_DL = bwpd->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI[0]; pucch->n_HARQ_ACK = (((V_DAI_m_DL - U_DAI_c)%4) * N_TB_max_DL) + N_m_c_rx + N_SPS_c; NR_TST_PHY_PRINTF("PUCCH power n(%d) = ( V(%d) - U(%d) )mod4 * N_TB(%d) + N(%d) \n", pucch->n_HARQ_ACK, V_DAI_m_DL, U_DAI_c, N_TB_max_DL, N_m_c_rx); } @@ -2111,7 +2215,9 @@ bool trigger_periodic_scheduling_request(NR_UE_MAC_INST_t *mac, mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pucch_Config->choice.setup) { pucch_Config = mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pucch_Config->choice.setup; } - if(!pucch_Config || pucch_Config->schedulingRequestResourceToAddModList->list.count==0) + if(!pucch_Config || + !pucch_Config->schedulingRequestResourceToAddModList || + pucch_Config->schedulingRequestResourceToAddModList->list.count==0) return false; // SR not configured for (int SR_resource_id =0; SR_resource_id < pucch_Config->schedulingRequestResourceToAddModList->list.count;SR_resource_id++) { @@ -2145,9 +2251,54 @@ bool trigger_periodic_scheduling_request(NR_UE_MAC_INST_t *mac, return false; } +int8_t nr_ue_get_SR(module_id_t module_idP, frame_t frameP, slot_t slot){ + // no UL-SCH resources available for this tti && UE has a valid PUCCH resources for SR configuration for this tti + DevCheck(module_idP < (int) NB_UE_INST, module_idP, NB_NR_UE_MAC_INST, 0); + NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP); + DSR_TRANSMAX_t dsr_TransMax = sr_n64; // todo + LOG_D(NR_MAC, "[UE %d] Frame %d slot %d send SR indication (SR_COUNTER/dsr_TransMax %d/%d), SR_pending %d\n", + module_idP, frameP, slot, + mac->scheduling_info.SR_COUNTER, + (1 << (2 + dsr_TransMax)), + mac->scheduling_info.SR_pending); // todo -int8_t nr_ue_get_SR(module_id_t module_idP, frame_t frameP, int slotP){ - return 0; + if ((mac->scheduling_info.SR_pending == 1) && + (mac->scheduling_info.SR_COUNTER < (1 << (2 + dsr_TransMax)))) { + LOG_D(NR_MAC, "[UE %d] Frame %d slot %d PHY asks for SR (SR_COUNTER/dsr_TransMax %d/%d), SR_pending %d, increment SR_COUNTER\n", + module_idP, frameP, slot, + mac->scheduling_info.SR_COUNTER, + (1 << (2 + dsr_TransMax)), + mac->scheduling_info.SR_pending); // todo + mac->scheduling_info.SR_COUNTER++; + + // start the sr-prohibittimer : rel 9 and above + if (mac->scheduling_info.sr_ProhibitTimer > 0) { // timer configured + mac->scheduling_info.sr_ProhibitTimer--; + mac->scheduling_info. + sr_ProhibitTimer_Running = 1; + } else { + mac->scheduling_info. + sr_ProhibitTimer_Running = 0; + } + //mac->ul_active =1; + return (1); //instruct phy to signal SR + } else { + // notify RRC to relase PUCCH/SRS + // clear any configured dl/ul + // initiate RA + if (mac->scheduling_info.SR_pending) { + // release all pucch resource + //mac->physicalConfigDedicated = NULL; // todo + //mac->ul_active = 0; // todo + mac->BSR_reporting_active = + NR_BSR_TRIGGER_NONE; + LOG_I(NR_MAC, "[UE %d] Release all SRs \n", module_idP); + } + + mac->scheduling_info.SR_pending = 0; + mac->scheduling_info.SR_COUNTER = 0; + return (0); + } } @@ -2453,7 +2604,7 @@ uint8_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac, switch(rnti_type) { case NR_RNTI_RA: if(mac->scc_SIB) { - N_RB = NRRIV2BW(mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP.genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + N_RB = mac->type0_PDCCH_CSS_config.num_rbs; } else { N_RB = get_n_rb(mac, rnti_type); } @@ -2691,7 +2842,8 @@ uint8_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac, // check BWP id if (mac->DLbwp[0]) N_RB=NRRIV2BW(mac->DLbwp[0]->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - else N_RB=NRRIV2BW(mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP.genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + else N_RB=mac->type0_PDCCH_CSS_config.num_rbs; +; // indicating a DL DCI format 1bit pos++; @@ -3151,7 +3303,7 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info, frame_t frameP = dl_info->frame; int slot = dl_info->slot; uint8_t *pduP = (dl_info->rx_ind->rx_indication_body + pdu_id)->pdsch_pdu.pdu; - int16_t pdu_len = (int16_t)(dl_info->rx_ind->rx_indication_body + pdu_id)->pdsch_pdu.pdu_length; + int32_t pdu_len = (int32_t)(dl_info->rx_ind->rx_indication_body + pdu_id)->pdsch_pdu.pdu_length; uint8_t gNB_index = dl_info->gNB_index; uint8_t CC_id = dl_info->cc_id; uint8_t done = 0; @@ -3309,7 +3461,7 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info, #endif */ - LOG_D(MAC, "[%d.%d] Received TA_COMMAND %u TAGID %u CC_id %d\n", frameP, slot, ul_time_alignment->ta_command, ul_time_alignment->tag_id, CC_id); + LOG_I(NR_MAC, "[%d.%d] Received TA_COMMAND %u TAGID %u CC_id %d\n", frameP, slot, ul_time_alignment->ta_command, ul_time_alignment->tag_id, CC_id); break; case DL_SCH_LCID_CON_RES_ID: @@ -3408,13 +3560,17 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info, * Return: number of written bytes */ int nr_write_ce_ulsch_pdu(uint8_t *mac_ce, - NR_UE_MAC_INST_t *mac) { + NR_UE_MAC_INST_t *mac, + uint8_t power_headroom, // todo: NR_POWER_HEADROOM_CMD *power_headroom, + uint16_t *crnti, + NR_BSR_SHORT *truncated_bsr, + NR_BSR_SHORT *short_bsr, + NR_BSR_LONG *long_bsr) { int mac_ce_len = 0; uint8_t mac_ce_size = 0; - NR_UE_MAC_CE_t *nr_ue_mac_ce = &mac->nr_ue_mac_ce; - - if (nr_ue_mac_ce->phr_reporting && mac->phr_Config != NULL) { + uint8_t *pdu = mac_ce; + if (power_headroom) { // MAC CE fixed subheader ((NR_MAC_SUBHEADER_FIXED *) mac_ce)->R = 0; @@ -3422,21 +3578,22 @@ int nr_write_ce_ulsch_pdu(uint8_t *mac_ce, mac_ce++; // PHR MAC CE (1 octet) - ((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_ce)->PH = 0; + ((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_ce)->PH = power_headroom; ((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_ce)->R1 = 0; - ((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_ce)->PCMAX = 0; + ((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_ce)->PCMAX = 0; // todo ((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_ce)->R2 = 0; // update pointer and length mac_ce_size = sizeof(NR_SINGLE_ENTRY_PHR_MAC_CE); mac_ce += mac_ce_size; mac_ce_len += mac_ce_size + sizeof(NR_MAC_SUBHEADER_FIXED); - + LOG_D(NR_MAC, "[UE] Generating ULSCH PDU : power_headroom pdu %p mac_ce %p b\n", + pdu, mac_ce); } - if (!get_softmodem_params()->sa && get_softmodem_params()->do_ra && mac->ra.ra_state != RA_SUCCEEDED) { + if (crnti && (!get_softmodem_params()->sa && get_softmodem_params()->do_ra && mac->ra.ra_state != RA_SUCCEEDED)) { - LOG_D(NR_MAC, "In %s: generating C-RNTI MAC CE with C-RNTI %x\n", __FUNCTION__, mac->crnti); + LOG_D(NR_MAC, "In %s: generating C-RNTI MAC CE with C-RNTI %x\n", __FUNCTION__, (*crnti)); // MAC CE fixed subheader ((NR_MAC_SUBHEADER_FIXED *) mac_ce)->R = 0; @@ -3444,7 +3601,7 @@ int nr_write_ce_ulsch_pdu(uint8_t *mac_ce, mac_ce++; // C-RNTI MAC CE (2 octets) - *(uint16_t *) mac_ce = mac->crnti; + *(uint16_t *) mac_ce = (*crnti); // update pointer and length mac_ce_size = sizeof(uint16_t); @@ -3453,55 +3610,110 @@ int nr_write_ce_ulsch_pdu(uint8_t *mac_ce, } - if (nr_ue_mac_ce->truncated_bsr) { + if (truncated_bsr) { - LOG_D(NR_MAC, "In %s: generating short truncated BSR MAC CE with command %x\n", __FUNCTION__, nr_ue_mac_ce->truncated_bsr); - - // MAC CE fixed subheader + // MAC CE fixed subheader ((NR_MAC_SUBHEADER_FIXED *) mac_ce)->R = 0; ((NR_MAC_SUBHEADER_FIXED *) mac_ce)->LCID = UL_SCH_LCID_S_TRUNCATED_BSR; mac_ce++; // Short truncated BSR MAC CE (1 octet) - ((NR_BSR_SHORT_TRUNCATED *) mac_ce)-> Buffer_size = 0; - ((NR_BSR_SHORT_TRUNCATED *) mac_ce)-> LcgID = 0; + ((NR_BSR_SHORT_TRUNCATED *) mac_ce)-> Buffer_size = truncated_bsr->Buffer_size; + ((NR_BSR_SHORT_TRUNCATED *) mac_ce)-> LcgID = truncated_bsr->LcgID;; // update pointer and length mac_ce_size = sizeof(NR_BSR_SHORT_TRUNCATED); mac_ce += mac_ce_size; mac_ce_len += mac_ce_size + sizeof(NR_MAC_SUBHEADER_FIXED); + LOG_D(NR_MAC, "[UE] Generating ULSCH PDU : truncated_bsr Buffer_size %d LcgID %d pdu %p mac_ce %p\n", + truncated_bsr->Buffer_size, truncated_bsr->LcgID, pdu, mac_ce); - } else if (nr_ue_mac_ce->short_bsr) { + } else if (short_bsr) { - LOG_D(NR_MAC, "In %s: generating short BSR MAC CE with command %x\n", __FUNCTION__, nr_ue_mac_ce->short_bsr); - - // MAC CE fixed subheader + // MAC CE fixed subheader ((NR_MAC_SUBHEADER_FIXED *) mac_ce)->R = 0; ((NR_MAC_SUBHEADER_FIXED *) mac_ce)->LCID = UL_SCH_LCID_S_BSR; mac_ce++; // Short truncated BSR MAC CE (1 octet) - ((NR_BSR_SHORT *) mac_ce)->Buffer_size = nr_ue_mac_ce->short_bsr; - ((NR_BSR_SHORT *) mac_ce)->LcgID = 0; + ((NR_BSR_SHORT *) mac_ce)->Buffer_size = short_bsr->Buffer_size; + ((NR_BSR_SHORT *) mac_ce)->LcgID = short_bsr->LcgID; // update pointer and length mac_ce_size = sizeof(NR_BSR_SHORT); mac_ce += mac_ce_size; mac_ce_len += mac_ce_size + sizeof(NR_MAC_SUBHEADER_FIXED); + LOG_D(NR_MAC, "[UE] Generating ULSCH PDU : short_bsr Buffer_size %d LcgID %d pdu %p mac_ce %p\n", + short_bsr->Buffer_size, short_bsr->LcgID, pdu, mac_ce); + } else if (long_bsr) { - } else if (nr_ue_mac_ce->long_bsr) { - // MAC CE variable subheader - // todo ch 6.1.3.1. TS 38.321 - // ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->R = 0; - // ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->F = 0; - // ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->LCID = UL_SCH_LCID_L_BSR; - // ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->L = 0; - // sh_size = 2; + // MAC CE variable subheader + // ch 6.1.3.1. TS 38.321 + ((NR_MAC_SUBHEADER_SHORT *) mac_ce)->R = 0; + ((NR_MAC_SUBHEADER_SHORT *) mac_ce)->F = 0; + ((NR_MAC_SUBHEADER_SHORT *) mac_ce)->LCID = UL_SCH_LCID_L_BSR; - // Short truncated BSR MAC CE (1 octet) - // ((NR_BSR_LONG *) mac_ce)->Buffer_size0 = short_bsr; - // ((NR_BSR_LONG *) mac_ce)->LCGID0 = 0; - // mac_ce_size = sizeof(NR_BSR_LONG); // size is variable + NR_MAC_SUBHEADER_SHORT *mac_pdu_subheader_ptr = (NR_MAC_SUBHEADER_SHORT *) mac_ce; + mac_ce += 2; + + // Could move to nr_get_sdu() + uint8_t *Buffer_size_ptr= (uint8_t*) mac_ce + 1; + //int NR_BSR_LONG_SIZE = 1; + if (long_bsr->Buffer_size0 == 0) { + ((NR_BSR_LONG *) mac_ce)->LcgID0 = 0; + } else { + ((NR_BSR_LONG *) mac_ce)->LcgID0 = 1; + *Buffer_size_ptr++ = long_bsr->Buffer_size0; + } + if (long_bsr->Buffer_size1 == 0) { + ((NR_BSR_LONG *) mac_ce)->LcgID1 = 0; + } else { + ((NR_BSR_LONG *) mac_ce)->LcgID1 = 1; + *Buffer_size_ptr++ = long_bsr->Buffer_size1; + } + if (long_bsr->Buffer_size2 == 0) { + ((NR_BSR_LONG *) mac_ce)->LcgID2 = 0; + } else { + ((NR_BSR_LONG *) mac_ce)->LcgID2 = 1; + *Buffer_size_ptr++ = long_bsr->Buffer_size2; + } + if (long_bsr->Buffer_size3 == 0) { + ((NR_BSR_LONG *) mac_ce)->LcgID3 = 0; + } else { + ((NR_BSR_LONG *) mac_ce)->LcgID3 = 1; + *Buffer_size_ptr++ = long_bsr->Buffer_size3; + } + if (long_bsr->Buffer_size4 == 0) { + ((NR_BSR_LONG *) mac_ce)->LcgID4 = 0; + } else { + ((NR_BSR_LONG *) mac_ce)->LcgID4 = 1; + *Buffer_size_ptr++ = long_bsr->Buffer_size4; + } + if (long_bsr->Buffer_size5 == 0) { + ((NR_BSR_LONG *) mac_ce)->LcgID5 = 0; + } else { + ((NR_BSR_LONG *) mac_ce)->LcgID5 = 1; + *Buffer_size_ptr++ = long_bsr->Buffer_size5; + } + if (long_bsr->Buffer_size6 == 0) { + ((NR_BSR_LONG *) mac_ce)->LcgID6 = 0; + } else { + ((NR_BSR_LONG *) mac_ce)->LcgID6 = 1; + *Buffer_size_ptr++ = long_bsr->Buffer_size6; + } + if (long_bsr->Buffer_size7 == 0) { + ((NR_BSR_LONG *) mac_ce)->LcgID7 = 0; + } else { + ((NR_BSR_LONG *) mac_ce)->LcgID7 = 1; + *Buffer_size_ptr++ = long_bsr->Buffer_size7; + } + ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_subheader_ptr)->L = mac_ce_size = (uint8_t*) Buffer_size_ptr - (uint8_t*) mac_ce; + LOG_D(NR_MAC, "[UE] Generating ULSCH PDU : long_bsr size %d Lcgbit 0x%02x Buffer_size %d %d %d %d %d %d %d %d\n", mac_ce_size, *((uint8_t*) mac_ce), + ((NR_BSR_LONG *) mac_ce)->Buffer_size0, ((NR_BSR_LONG *) mac_ce)->Buffer_size1, ((NR_BSR_LONG *) mac_ce)->Buffer_size2, ((NR_BSR_LONG *) mac_ce)->Buffer_size3, + ((NR_BSR_LONG *) mac_ce)->Buffer_size4, ((NR_BSR_LONG *) mac_ce)->Buffer_size5, ((NR_BSR_LONG *) mac_ce)->Buffer_size6, ((NR_BSR_LONG *) mac_ce)->Buffer_size7); + // update pointer and length + mac_ce = Buffer_size_ptr; + mac_ce_len += mac_ce_size + sizeof(NR_MAC_SUBHEADER_SHORT); } return mac_ce_len; @@ -3553,8 +3765,6 @@ int nr_ue_process_rar(nr_downlink_indication_t *dl_info, NR_UL_TIME_ALIGNMENT_t return 0; } - int cc_id = dl_info->cc_id; - uint8_t gNB_id = dl_info->gNB_index; NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id); RA_config_t *ra = &mac->ra; uint8_t n_subPDUs = 0; // number of RAR payloads @@ -3566,7 +3776,7 @@ int nr_ue_process_rar(nr_downlink_indication_t *dl_info, NR_UL_TIME_ALIGNMENT_t int ret = 0; NR_RA_HEADER_RAPID *rarh = (NR_RA_HEADER_RAPID *) dlsch_buffer; // RAR subheader pointer NR_MAC_RAR *rar = (NR_MAC_RAR *) (dlsch_buffer + 1); // RAR subPDU pointer - uint8_t preamble_index = get_ra_PreambleIndex(mod_id, cc_id, gNB_id); //prach_resources->ra_PreambleIndex; + uint8_t preamble_index = ra->ra_PreambleIndex; LOG_D(NR_MAC, "In %s:[%d.%d]: [UE %d][RAPROC] invoking MAC for received RAR (current preamble %d)\n", __FUNCTION__, frame, slot, mod_id, preamble_index); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index f3a2496ce3..f813efad92 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -53,6 +53,8 @@ #include +#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" + static prach_association_pattern_t prach_assoc_pattern; static ssb_list_info_t ssb_list; @@ -164,13 +166,26 @@ fapi_nr_ul_config_request_t *get_ul_config_request(NR_UE_MAC_INST_t *mac, int sl void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu, dci_pdu_rel15_t *dci) { NR_ServingCellConfigCommon_t *scc = mac->scc; - NR_PUSCH_Config_t *pusch_Config = mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup; + NR_BWP_UplinkDedicated_t *ubwpd=NULL; + + if (mac->cg && + mac->cg->spCellConfig && + mac->cg->spCellConfig->spCellConfigDedicated && + mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig && + mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) + ubwpd = mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; + + NR_PUSCH_Config_t *pusch_Config = mac->ULbwp[0] ? + mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup : + (ubwpd? + ubwpd->pusch_Config->choice.setup: + NULL); long transformPrecoder; - if (pusch_Config->transformPrecoder) + if (pusch_Config && pusch_Config->transformPrecoder) transformPrecoder = *pusch_Config->transformPrecoder; else { - if(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder) + if(scc && scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder) transformPrecoder = NR_PUSCH_Config__transformPrecoder_enabled; else transformPrecoder = NR_PUSCH_Config__transformPrecoder_disabled; @@ -301,10 +316,20 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu, dci_pdu_rel15_t *dci) { /* ANTENNA_PORTS */ - uint8_t rank = 0; // We need to initialize rank FIXME!!! + uint8_t rank = 1; // We need to initialize rank FIXME!!! NR_ServingCellConfigCommon_t *scc = mac->scc; - NR_PUSCH_Config_t *pusch_Config = mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup; + NR_BWP_UplinkDedicated_t *ubwpd=NULL; + + if (mac->cg && + mac->cg->spCellConfig && + mac->cg->spCellConfig->spCellConfigDedicated && + mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig && + mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) + ubwpd = mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; + + NR_PUSCH_Config_t *pusch_Config = mac->ULbwp[0] ? mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup : (ubwpd?ubwpd->pusch_Config->choice.setup:NULL); + AssertFatal(pusch_Config!=NULL,"pusch_Config shouldn't be null\n"); long transformPrecoder; if (pusch_Config->transformPrecoder) @@ -317,6 +342,8 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf } long *max_length = NULL; long *dmrs_type = NULL; + LOG_D(NR_MAC,"transformPrecoder %s\n",transformPrecoder==NR_PUSCH_Config__transformPrecoder_disabled?"disabled":"enabled"); + if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA) { max_length = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->maxLength; dmrs_type = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->dmrs_Type; @@ -326,7 +353,7 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf dmrs_type = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->dmrs_Type; } - + LOG_D(NR_MAC,"MappingType%s max_length %s, dmrs_type %s, antenna_ports %d\n",pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA?"A":"B",max_length?"len2":"len1",dmrs_type?"type2":"type1",dci->antenna_ports.val); if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) && (dmrs_type == NULL) && (max_length == NULL)) { // tables 7.3.1.1.2-6 pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; //TBC @@ -481,6 +508,7 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf //pusch_config_pdu->n_front_load_symb = table_7_3_1_1_2_23[dci->antenna_ports.val][5]; //FIXME } } + LOG_D(NR_MAC,"num_dmrs_cdm_grps_no_data %d, dmrs_ports %d\n",pusch_config_pdu->num_dmrs_cdm_grps_no_data,pusch_config_pdu->dmrs_ports); } // Configuration of Msg3 PDU according to clauses: @@ -626,22 +654,23 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->pusch_data.num_cb = 0; } else if (dci) { + NR_BWP_Id_t dl_bwp_id = mac->DL_BWP_Id; + NR_BWP_Id_t ul_bwp_id = mac->UL_BWP_Id; + NR_BWP_DownlinkDedicated_t *bwpd=NULL; + NR_BWP_DownlinkCommon_t *bwpc=NULL; + NR_BWP_UplinkDedicated_t *ubwpd=NULL; + NR_BWP_UplinkCommon_t *ubwpc=NULL; + get_bwp_info(mac,dl_bwp_id,ul_bwp_id,&bwpd,&bwpc,&ubwpd,&ubwpc); int target_ss; bool valid_ptrs_setup = 0; uint16_t n_RB_ULBWP; - if (mac->ULbwp[0] && mac->ULbwp[0]->bwp_Common) { - n_RB_ULBWP = NRRIV2BW(mac->ULbwp[0]->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - pusch_config_pdu->bwp_start = NRRIV2PRBOFFSET(mac->ULbwp[0]->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - } - else { - pusch_config_pdu->bwp_start = NRRIV2PRBOFFSET(mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - n_RB_ULBWP = NRRIV2BW(mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - } - + n_RB_ULBWP = NRRIV2BW(ubwpc->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + pusch_config_pdu->bwp_start = NRRIV2PRBOFFSET(ubwpc->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); pusch_config_pdu->bwp_size = n_RB_ULBWP; - NR_PUSCH_Config_t *pusch_Config = mac->ULbwp[0] ? mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup : NULL; + AssertFatal(ubwpd->pusch_Config != NULL,"pusch_Config shouldn't be null\n"); + NR_PUSCH_Config_t *pusch_Config = ubwpd->pusch_Config->choice.setup; // Basic sanity check for MCS value to check for a false or erroneous DCI if (dci->mcs > 28) { @@ -661,12 +690,9 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, } else if (*dci_format == NR_UL_DCI_FORMAT_0_1) { - /* BANDWIDTH_PART_IND */ - if (dci->bwp_indicator.val != 1) { - LOG_W(NR_MAC, "bwp_indicator != 1! Possibly due to false DCI. Ignoring DCI!\n"); - return -1; - } config_bwp_ue(mac, &dci->bwp_indicator.val, dci_format); + get_bwp_info(mac,dl_bwp_id,ul_bwp_id,&bwpd,&bwpc,&ubwpd,&ubwpc); + target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; ul_layers_config(mac, pusch_config_pdu, dci); ul_ports_config(mac, pusch_config_pdu, dci); @@ -677,21 +703,8 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, return -1; } - - NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = NULL; - if (pusch_Config && pusch_Config->pusch_TimeDomainAllocationList) { - pusch_TimeDomainAllocationList = pusch_Config->pusch_TimeDomainAllocationList->choice.setup; - } - else if (mac->ULbwp[0] && - mac->ULbwp[0]->bwp_Common&& - mac->ULbwp[0]->bwp_Common->pusch_ConfigCommon&& - mac->ULbwp[0]->bwp_Common->pusch_ConfigCommon->choice.setup && - mac->ULbwp[0]->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList) { - pusch_TimeDomainAllocationList = mac->ULbwp[0]->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; - } - else if (mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList) - pusch_TimeDomainAllocationList=mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; - else AssertFatal(1==0,"need to fall back to default PUSCH time-domain allocations\n"); + NR_PUSCH_ConfigCommon_t *pusch_ConfigCommon = ubwpc->pusch_ConfigCommon->choice.setup; + NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = choose_ul_tda_list(pusch_Config,pusch_ConfigCommon); int mappingtype = pusch_TimeDomainAllocationList->list.array[dci->time_domain_assignment.val]->mappingType; @@ -735,7 +748,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, return -1; } /* TIME_DOM_RESOURCE_ASSIGNMENT */ - if (nr_ue_process_dci_time_dom_resource_assignment(mac, pusch_config_pdu, NULL, dci->time_domain_assignment.val,0,false) < 0) { + if (nr_ue_process_dci_time_dom_resource_assignment(mac, pusch_TimeDomainAllocationList, NULL, pusch_config_pdu, NULL, dci->time_domain_assignment.val,0,false) < 0) { return -1; } @@ -842,7 +855,14 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, return -1; } - get_num_re_dmrs(pusch_config_pdu, &nb_dmrs_re_per_rb, &number_dmrs_symbols); + int start_symbol = pusch_config_pdu->start_symbol_index; + int number_of_symbols = pusch_config_pdu->nr_of_symbols; + for (int i = start_symbol; i < start_symbol + number_of_symbols; i++) { + if((pusch_config_pdu->ul_dmrs_symb_pos >> i) & 0x01) + number_dmrs_symbols += 1; + } + + nb_dmrs_re_per_rb = ((pusch_config_pdu->dmrs_config_type == pusch_dmrs_type1) ? 6:4)*pusch_config_pdu->num_dmrs_cdm_grps_no_data; // Compute TBS pusch_config_pdu->pusch_data.tb_size = nr_compute_tbs(pusch_config_pdu->qam_mod_order, @@ -940,11 +960,11 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in if (ulcfg_pdu->pdu_type == FAPI_NR_UL_CONFIG_TYPE_PUSCH) { uint16_t TBS_bytes = ulcfg_pdu->pusch_config_pdu.pusch_data.tb_size; - LOG_D(NR_MAC,"harq_id %d, NDI %d NDI_DCI %d, TBS_bytes %d\n", + LOG_D(NR_MAC,"harq_id %d, NDI %d NDI_DCI %d, TBS_bytes %d (ra_state %d)\n", ulcfg_pdu->pusch_config_pdu.pusch_data.harq_process_id, mac->UL_ndi[ulcfg_pdu->pusch_config_pdu.pusch_data.harq_process_id], ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator, - TBS_bytes); + TBS_bytes,ra->ra_state); if (ra->ra_state == WAIT_RAR && !ra->cfra){ memcpy(ulsch_input_buffer, mac->ulsch_pdu.payload, TBS_bytes); LOG_D(NR_MAC,"[RAPROC] Msg3 to be transmitted:\n"); @@ -963,7 +983,7 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in (ra->ra_state == WAIT_RAR && ra->cfra))){ // Getting IP traffic to be transmitted - nr_ue_get_sdu(mod_id, frame_tx, slot_tx, gNB_index, ulsch_input_buffer, TBS_bytes); + nr_ue_get_sdu(mod_id, cc_id,frame_tx, slot_tx, gNB_index, ulsch_input_buffer, TBS_bytes); } LOG_D(NR_MAC,"Flipping NDI for harq_id %d\n",ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator); @@ -999,10 +1019,324 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in } } + if (dl_info) { + return (CONNECTION_OK); + } + module_id_t mod_id = ul_info->module_id; + frame_t txFrameP = ul_info->frame_tx; + slot_t txSlotP = ul_info->slot_tx; + + // Handle the SR/BSR procedures per subframe + NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id); + uint8_t gNB_indexP=0; + + // Call BSR procedure as described in Section 5.4.5 in 38.321 + + // First check ReTxBSR Timer because it is always configured + // Decrement ReTxBSR Timer if it is running and not null + if ((mac->scheduling_info.retxBSR_SF != MAC_UE_BSR_TIMER_NOT_RUNNING) && (mac->scheduling_info.retxBSR_SF != 0)) { + mac->scheduling_info.retxBSR_SF--; + } + + // Decrement Periodic Timer if it is running and not null + if ((mac->scheduling_info.periodicBSR_SF != MAC_UE_BSR_TIMER_NOT_RUNNING) && (mac->scheduling_info.periodicBSR_SF != 0)) { + mac->scheduling_info.periodicBSR_SF--; + } + + //Check whether Regular BSR is triggered + if (nr_update_bsr(mod_id, txFrameP, txSlotP, gNB_indexP) == TRUE) { + // call SR procedure to generate pending SR and BSR for next PUCCH/PUSCH TxOp. This should implement the procedures + // outlined in Sections 5.4.4 an 5.4.5 of 38.321 + mac->scheduling_info.SR_pending = 1; + // Regular BSR trigger + mac->BSR_reporting_active |= NR_BSR_TRIGGER_REGULAR; + LOG_D(NR_MAC, "[UE %d][BSR] Regular BSR Triggered Frame %d slot %d SR for PUSCH is pending\n", + mod_id, txFrameP, txSlotP); + } return UE_CONNECTION_OK; } +boolean_t +nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t gNB_index) { + mac_rlc_status_resp_t rlc_status; + boolean_t bsr_regular_triggered = FALSE; + uint8_t lcid; + uint8_t lcgid; + uint8_t num_lcid_with_data = 0; // for LCID with data only if LCGID is defined + uint32_t lcgid_buffer_remain[NR_MAX_NUM_LCGID] = {0,0,0,0,0,0,0,0}; + int32_t lcid_bytes_in_buffer[NR_MAX_NUM_LCID]; + /* Array for ordering LCID with data per decreasing priority order */ + uint8_t lcid_reordered_array[NR_MAX_NUM_LCID]= + {NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID, + NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID, + NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID, + NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID, + }; + uint8_t pos_next = 0; + //uint8_t highest_priority = 16; + uint8_t array_index = 0; + // Reset All BSR Infos + lcid_bytes_in_buffer[0] = 0; + NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP); + for (lcid=DCCH; lcid < NR_MAX_NUM_LCID; lcid++) { + // Reset transmission status + lcid_bytes_in_buffer[lcid] = 0; + mac->scheduling_info.LCID_status[lcid]=LCID_EMPTY; + } + + for (lcgid=0; lcgid < NR_MAX_NUM_LCGID; lcgid++) { + // Reset Buffer Info + mac->scheduling_info.BSR[lcgid]=0; + mac->scheduling_info.BSR_bytes[lcgid]=0; + } + + //Get Buffer Occupancy and fill lcid_reordered_array + for (lcid=DCCH; lcid < NR_MAX_NUM_LCID; lcid++) { + //if (mac->logicalChannelConfig[lcid]) { + if (mac->logicalChannelBearer_exist[lcid] ) { // todo + lcgid = mac->scheduling_info.LCGID[lcid]; + + // Store already available data to transmit per Group + if (lcgid < NR_MAX_NUM_LCGID) { + lcgid_buffer_remain[lcgid] += mac->scheduling_info.LCID_buffer_remain[lcid]; + } + + rlc_status = mac_rlc_status_ind(module_idP, mac->crnti,gNB_index,frameP,slotP,ENB_FLAG_NO,MBMS_FLAG_NO, lcid, 0, 0); + + lcid_bytes_in_buffer[lcid] = rlc_status.bytes_in_buffer; + + if (rlc_status.bytes_in_buffer > 0) { + LOG_D(NR_MAC,"[UE %d] PDCCH Tick : LCID%d LCGID%d has data to transmit =%d bytes at frame %d slot %d\n", + module_idP, lcid,lcgid,rlc_status.bytes_in_buffer,frameP,slotP); + mac->scheduling_info.LCID_status[lcid] = LCID_NOT_EMPTY; + + //Update BSR_bytes and position in lcid_reordered_array only if Group is defined + if (lcgid < NR_MAX_NUM_LCGID) { + num_lcid_with_data ++; + // sum lcid buffer which has same lcgid + mac->scheduling_info.BSR_bytes[lcgid] += rlc_status.bytes_in_buffer; + //Fill in the array + array_index = 0; + + do { + //if (mac->logicalChannelConfig[lcid]->ul_SpecificParameters->priority <= highest_priority) { + if (1) { // todo + //Insert if priority is higher or equal (lower or equal in value) + for (pos_next=num_lcid_with_data-1; pos_next > array_index; pos_next--) { + lcid_reordered_array[pos_next] = lcid_reordered_array[pos_next - 1]; + } + + lcid_reordered_array[array_index] = lcid; + break; + } + + array_index ++; + } while ((array_index < num_lcid_with_data) && (array_index < NR_MAX_NUM_LCID)); + } + } + } + } + + // Check whether a regular BSR can be triggered according to the first cases in 38.321 + if (num_lcid_with_data) { + LOG_D(NR_MAC, "[UE %d] PDCCH Tick at frame %d slot %d: NumLCID with data=%d Reordered LCID0=%d LCID1=%d LCID2=%d\n", + module_idP, frameP, slotP, num_lcid_with_data, + lcid_reordered_array[0], lcid_reordered_array[1], + lcid_reordered_array[2]); + + for (array_index = 0; array_index < num_lcid_with_data; array_index++) { + lcid = lcid_reordered_array[array_index]; + + /* UL data, for a logical channel which belongs to a LCG, becomes available for transmission in the RLC entity + either the data belongs to a logical channel with higher priority than the priorities of the logical channels + which belong to any LCG and for which data is already available for transmission + */ + { + bsr_regular_triggered = TRUE; + LOG_D(NR_MAC, "[UE %d] PDCCH Tick : MAC BSR Triggered LCID%d LCGID%d data become available at frame %d slot %d\n", + module_idP, lcid, + mac->scheduling_info.LCGID[lcid], + frameP, slotP); + break; + } + } + + // Trigger Regular BSR if ReTxBSR Timer has expired and UE has data for transmission + if (mac->scheduling_info.retxBSR_SF == 0) { + bsr_regular_triggered = TRUE; + + if ((mac->BSR_reporting_active & NR_BSR_TRIGGER_REGULAR) == 0) { + LOG_I(NR_MAC, "[UE %d] PDCCH Tick : MAC BSR Triggered ReTxBSR Timer expiry at frame %d slot %d\n", + module_idP, frameP, slotP); + } + } + } + + //Store Buffer Occupancy in remain buffers for next TTI + for (lcid = DCCH; lcid < NR_MAX_NUM_LCID; lcid++) { + mac->scheduling_info.LCID_buffer_remain[lcid] = lcid_bytes_in_buffer[lcid]; + } + + return bsr_regular_triggered; +} + +uint8_t +nr_locate_BsrIndexByBufferSize(const uint32_t *table, int size, int value) { + uint8_t ju, jm, jl; + int ascend; + //DevAssert(size > 0); + //DevAssert(size <= 256); + + if (value == 0) { + return 0; //elseif (value > 150000) return 63; + } + + jl = 0; // lower bound + ju = size - 1; // upper bound + ascend = (table[ju] >= table[jl]) ? 1 : 0; // determine the order of the the table: 1 if ascending order of table, 0 otherwise + + while (ju - jl > 1) { //If we are not yet done, + jm = (ju + jl) >> 1; //compute a midpoint, + + if ((value >= table[jm]) == ascend) { + jl = jm; // replace the lower limit + } else { + ju = jm; //replace the upper limit + } + + LOG_T(NR_MAC, "[UE] searching BSR index %d for (BSR TABLE %d < value %d)\n", + jm, table[jm], value); + } + + if (value == table[jl]) { + return jl; + } else { + return jl + 1; //equally ju + } +} + +int nr_get_sf_periodicBSRTimer(uint8_t sf_offset) { + switch (sf_offset) { + case NR_BSR_Config__periodicBSR_Timer_sf1: + return 1; + break; + + case NR_BSR_Config__periodicBSR_Timer_sf5: + return 5; + break; + + case NR_BSR_Config__periodicBSR_Timer_sf10: + return 10; + break; + + case NR_BSR_Config__periodicBSR_Timer_sf16: + return 16; + break; + + case NR_BSR_Config__periodicBSR_Timer_sf20: + return 20; + break; + + case NR_BSR_Config__periodicBSR_Timer_sf32: + return 32; + break; + + case NR_BSR_Config__periodicBSR_Timer_sf40: + return 40; + break; + + case NR_BSR_Config__periodicBSR_Timer_sf64: + return 64; + break; + + case NR_BSR_Config__periodicBSR_Timer_sf80: + return 80; + break; + + case NR_BSR_Config__periodicBSR_Timer_sf128: + return 128; + break; + + case NR_BSR_Config__periodicBSR_Timer_sf160: + return 160; + break; + + case NR_BSR_Config__periodicBSR_Timer_sf320: + return 320; + break; + + case NR_BSR_Config__periodicBSR_Timer_sf640: + return 640; + break; + + case NR_BSR_Config__periodicBSR_Timer_sf1280: + return 1280; + break; + + case NR_BSR_Config__periodicBSR_Timer_sf2560: + return 2560; + break; + + case NR_BSR_Config__periodicBSR_Timer_infinity: + default: + return 0xFFFF; + break; + } +} + +int nr_get_sf_retxBSRTimer(uint8_t sf_offset) { + switch (sf_offset) { + case NR_BSR_Config__retxBSR_Timer_sf10: + return 10; + break; + + case NR_BSR_Config__retxBSR_Timer_sf20: + return 20; + break; + + case NR_BSR_Config__retxBSR_Timer_sf40: + return 40; + break; + + case NR_BSR_Config__retxBSR_Timer_sf80: + return 80; + break; + + case NR_BSR_Config__retxBSR_Timer_sf160: + return 160; + break; + + case NR_BSR_Config__retxBSR_Timer_sf320: + return 320; + break; + + case NR_BSR_Config__retxBSR_Timer_sf640: + return 640; + break; + + case NR_BSR_Config__retxBSR_Timer_sf1280: + return 1280; + break; + + case NR_BSR_Config__retxBSR_Timer_sf2560: + return 2560; + break; + + case NR_BSR_Config__retxBSR_Timer_sf5120: + return 5120; + break; + + case NR_BSR_Config__retxBSR_Timer_sf10240: + return 10240; + break; + + default: + return -1; + break; + } +} + // PUSCH scheduler: // - Calculate the slot in which ULSCH should be scheduled. This is current slot + K2, // - where K2 is the offset between the slot in which UL DCI is received and the slot @@ -1066,6 +1400,7 @@ int nr_ue_pusch_scheduler(NR_UE_MAC_INST_t *mac, // Get slot offset K2 which will be used to calculate TX slot k2 = get_k2(mac, tda_id); if (k2 < 0) { // This can happen when a false DCI is received + LOG_W(PHY,"%d.%d. Received k2 %d, tda_id %d\n",current_frame,current_slot,k2,tda_id); return -1; } @@ -1816,6 +2151,7 @@ void nr_ue_pucch_scheduler(module_id_t module_idP, frame_t frameP, int slotP, in pucch, pucch_pdu, O_SR, O_ACK, O_CSI); + LOG_D(NR_MAC,"Configuring pucch, is_common = %d\n",pucch->is_common); fill_ul_config(ul_config, frameP, slotP, FAPI_NR_UL_CONFIG_TYPE_PUCCH); nr_scheduled_response_t scheduled_response; fill_scheduled_response(&scheduled_response, NULL, ul_config, NULL, module_idP, 0 /*TBR fix*/, frameP, slotP, thread_id); @@ -1978,7 +2314,7 @@ void nr_ue_sib1_scheduler(module_id_t module_idP, NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP); nr_scheduled_response_t scheduled_response; - int frame_s,slot_s,ret; + int frame_s,slot_s; fapi_nr_dl_config_request_t *dl_config = &mac->dl_config_request; fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15; @@ -1993,6 +2329,7 @@ void nr_ue_sib1_scheduler(module_id_t module_idP, ssb_start_symbol, scs_ssb, frequency_range, + mac->nr_band, ssb_index, 1, // If the UE is not configured with a periodicity, the UE assumes a periodicity of a half frame ssb_offset_point_a); @@ -2000,33 +2337,29 @@ void nr_ue_sib1_scheduler(module_id_t module_idP, if(mac->search_space_zero == NULL) mac->search_space_zero=calloc(1,sizeof(*mac->search_space_zero)); if(mac->coreset0 == NULL) mac->coreset0 = calloc(1,sizeof(*mac->coreset0)); - for (int i=0; i<3; i++) { // loop over possible aggregation levels + fill_coresetZero(mac->coreset0, &mac->type0_PDCCH_CSS_config); + fill_searchSpaceZero(mac->search_space_zero, &mac->type0_PDCCH_CSS_config); + rel15 = &dl_config->dl_config_list[dl_config->number_pdus].dci_config_pdu.dci_config_rel15; + rel15->num_dci_options = 1; + rel15->dci_format_options[0] = NR_DL_DCI_FORMAT_1_0; + config_dci_pdu(mac, rel15, dl_config, NR_RNTI_SI, -1); + fill_dci_search_candidates(mac->search_space_zero, rel15); - fill_coresetZero(mac->coreset0, &mac->type0_PDCCH_CSS_config); - ret = fill_searchSpaceZero(mac->search_space_zero, &mac->type0_PDCCH_CSS_config,4<dl_config_list[dl_config->number_pdus].dci_config_pdu.dci_config_rel15; - rel15->num_dci_options = 1; - rel15->dci_format_options[0] = NR_DL_DCI_FORMAT_1_0; - config_dci_pdu(mac, rel15, dl_config, NR_RNTI_SI, -1); - fill_dci_search_candidates(mac->search_space_zero, rel15); - - if(mac->type0_PDCCH_CSS_config.type0_pdcch_ss_mux_pattern == 1){ - // same frame as ssb - if ((mac->type0_PDCCH_CSS_config.frame & 0x1) == mac->type0_PDCCH_CSS_config.sfn_c) - frame_s = 0; - else - frame_s = 1; - slot_s = mac->type0_PDCCH_CSS_config.n_0; - } - else{ - frame_s = 0; // same frame as ssb - slot_s = mac->type0_PDCCH_CSS_config.n_c; - } - LOG_D(MAC,"Calling fill_scheduled_response, type0_pdcch, num_pdus %d\n",dl_config->number_pdus); - fill_scheduled_response(&scheduled_response, dl_config, NULL, NULL, module_idP, cc_id, frame_s, slot_s, 0); // TODO fix thread_id, for now assumed 0 - } + if(mac->type0_PDCCH_CSS_config.type0_pdcch_ss_mux_pattern == 1){ + // same frame as ssb + if ((mac->type0_PDCCH_CSS_config.frame & 0x1) == mac->type0_PDCCH_CSS_config.sfn_c) + frame_s = 0; + else + frame_s = 1; + slot_s = mac->type0_PDCCH_CSS_config.n_0; } + else{ + frame_s = 0; // same frame as ssb + slot_s = mac->type0_PDCCH_CSS_config.n_c; + } + LOG_D(MAC,"Calling fill_scheduled_response, type0_pdcch, num_pdus %d\n",dl_config->number_pdus); + fill_scheduled_response(&scheduled_response, dl_config, NULL, NULL, module_idP, cc_id, frame_s, slot_s, 0); // TODO fix thread_id, for now assumed 0 + if (dl_config->number_pdus) { if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL) mac->if_module->scheduled_response(&scheduled_response); @@ -2037,12 +2370,268 @@ void nr_ue_sib1_scheduler(module_id_t module_idP, #define MAX_LCID 8 // NR_MAX_NUM_LCID shall be used but the mac_rlc_data_req function can fetch data for max 8 LCID +typedef struct { + uint8_t bsr_len; + uint8_t bsr_ce_len; + uint8_t bsr_header_len; + uint8_t phr_len; + uint8_t phr_ce_len; + uint8_t phr_header_len; + uint16_t sdu_length_total; + NR_BSR_SHORT *bsr_s; + NR_BSR_LONG *bsr_l; + NR_BSR_SHORT *bsr_t; + //NR_POWER_HEADROOM_CMD *phr_pr; + int tot_mac_ce_len; + uint8_t total_mac_pdu_header_len; +} NR_UE_MAC_CE_INFO; + +/* +nr_ue_get_sdu_mac_ce_pre finds length in various mac_ce field +Need nothing from mac_ce_p: +Update the following in mac_ce_p: + bsr_len; + bsr_ce_len; + bsr_header_len; + phr_len; TBD + phr_ce_len; TBD + phr_header_len; TBD +*/ +int nr_ue_get_sdu_mac_ce_pre(module_id_t module_idP, + int CC_id, + frame_t frameP, + sub_frame_t subframe, + uint8_t gNB_index, + uint8_t *ulsch_buffer, + uint16_t buflen, + NR_UE_MAC_CE_INFO *mac_ce_p) { + NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP); + + int num_lcg_id_with_data = 0; + // Preparing the MAC CEs sub-PDUs and get the total size + mac_ce_p->bsr_header_len = 0; + mac_ce_p->phr_header_len = 0; //sizeof(SCH_SUBHEADER_FIXED); + int lcg_id = 0; + while (lcg_id < NR_MAX_NUM_LCGID) { + if (mac->scheduling_info.BSR_bytes[lcg_id]) { + num_lcg_id_with_data++; + } + + lcg_id++; + } + + //Restart ReTxBSR Timer at new grant indication (38.321) + if (mac->scheduling_info.retxBSR_SF != MAC_UE_BSR_TIMER_NOT_RUNNING) { + mac->scheduling_info.retxBSR_SF = nr_get_sf_retxBSRTimer(mac->scheduling_info.retxBSR_Timer); + } + + // periodicBSR-Timer expires, trigger BSR + if ((mac->scheduling_info.periodicBSR_Timer != NR_BSR_Config__periodicBSR_Timer_infinity) + && (mac->scheduling_info.periodicBSR_SF == 0)) { + // Trigger BSR Periodic + mac->BSR_reporting_active |= NR_BSR_TRIGGER_PERIODIC; + LOG_D(NR_MAC, "[UE %d] MAC BSR Triggered PeriodicBSR Timer expiry at frame%d subframe %d TBS=%d\n", + module_idP, frameP, subframe, buflen); + } + + //Compute BSR Length if Regular or Periodic BSR is triggered + //WARNING: if BSR long is computed, it may be changed to BSR short during or after multiplexing if there remains less than 1 LCGROUP with data after Tx + if (mac->BSR_reporting_active) { + AssertFatal((mac->BSR_reporting_active & NR_BSR_TRIGGER_PADDING) == 0, + "Inconsistent BSR Trigger=%d !\n", + mac->BSR_reporting_active); + + //A Regular or Periodic BSR can only be sent if TBS is sufficient as transmitting only a BSR is not allowed if UE has data to transmit + if (num_lcg_id_with_data <= 1) { + if (buflen >= (sizeof(NR_BSR_SHORT)+sizeof(NR_MAC_SUBHEADER_FIXED)+1)) { + mac_ce_p->bsr_ce_len = sizeof(NR_BSR_SHORT); //1 byte + mac_ce_p->bsr_header_len = sizeof(NR_MAC_SUBHEADER_FIXED); //1 byte + } + } else { + if (buflen >= (num_lcg_id_with_data+1+sizeof(NR_MAC_SUBHEADER_SHORT)+1)) { + mac_ce_p->bsr_ce_len = num_lcg_id_with_data + 1; //variable size + mac_ce_p->bsr_header_len = sizeof(NR_MAC_SUBHEADER_SHORT); //2 bytes + } + } + } + + mac_ce_p->bsr_len = mac_ce_p->bsr_ce_len + mac_ce_p->bsr_header_len; + return (mac_ce_p->bsr_len + mac_ce_p->phr_len); +} + +/* +nr_ue_get_sdu_mac_ce_post recalculates length and prepares the mac_ce field +Need the following from mac_ce_p: + bsr_ce_len + bsr_len + sdu_length_total + total_mac_pdu_header_len +Update the following in mac_ce_p: + bsr_ce_len + bsr_header_len + bsr_len + tot_mac_ce_len + total_mac_pdu_header_len + bsr_s + bsr_l + bsr_t +*/ +void nr_ue_get_sdu_mac_ce_post(module_id_t module_idP, + int CC_id, + frame_t frameP, + sub_frame_t subframe, + uint8_t gNB_index, + uint8_t *ulsch_buffer, + uint16_t buflen, + NR_UE_MAC_CE_INFO *mac_ce_p) { + NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP); + + // Compute BSR Values and update Nb LCGID with data after multiplexing + unsigned short padding_len = 0; + uint8_t lcid = 0; + int lcg_id = 0; + int num_lcg_id_with_data = 0; + int lcg_id_bsr_trunc = 0; + for (lcg_id = 0; lcg_id < NR_MAX_NUM_LCGID; lcg_id++) { + if (mac_ce_p->bsr_ce_len == sizeof(NR_BSR_SHORT)) { + mac->scheduling_info.BSR[lcg_id] = nr_locate_BsrIndexByBufferSize(NR_SHORT_BSR_TABLE, NR_SHORT_BSR_TABLE_SIZE, mac->scheduling_info.BSR_bytes[lcg_id]); + } else { + mac->scheduling_info.BSR[lcg_id] = nr_locate_BsrIndexByBufferSize(NR_LONG_BSR_TABLE, NR_LONG_BSR_TABLE_SIZE, mac->scheduling_info.BSR_bytes[lcg_id]); + } + if (mac->scheduling_info.BSR_bytes[lcg_id]) { + num_lcg_id_with_data++; + lcg_id_bsr_trunc = lcg_id; + } + } + + // TS 38.321 Section 5.4.5 + // Check BSR padding: it is done after PHR according to Logical Channel Prioritization order + // Check for max padding size, ie MAC Hdr for last RLC PDU = 1 + /* For Padding BSR: + - if the number of padding bits is equal to or larger than the size of the Short BSR plus its subheader but smaller than the size of the Long BSR plus its subheader: + - if more than one LCG has data available for transmission in the TTI where the BSR is transmitted: report Truncated BSR of the LCG with the highest priority logical channel with data available for transmission; + - else report Short BSR. + - else if the number of padding bits is equal to or larger than the size of the Long BSR plus its subheader, report Long BSR. + */ + if (mac_ce_p->sdu_length_total) { + padding_len = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total); + } + + if ((padding_len) && (mac_ce_p->bsr_len == 0)) { + /* if the number of padding bits is equal to or larger than the size of the Long BSR plus its subheader, report Long BSR */ + if (padding_len >= (num_lcg_id_with_data+1+sizeof(NR_MAC_SUBHEADER_SHORT))) { + mac_ce_p->bsr_ce_len = num_lcg_id_with_data + 1; //variable size + mac_ce_p->bsr_header_len = sizeof(NR_MAC_SUBHEADER_SHORT); //2 bytes + // Trigger BSR Padding + mac->BSR_reporting_active |= NR_BSR_TRIGGER_PADDING; + } else if (padding_len >= (sizeof(NR_BSR_SHORT)+sizeof(NR_MAC_SUBHEADER_FIXED))) { + mac_ce_p->bsr_ce_len = sizeof(NR_BSR_SHORT); //1 byte + mac_ce_p->bsr_header_len = sizeof(NR_MAC_SUBHEADER_FIXED); //1 byte + + if (num_lcg_id_with_data > 1) { + // REPORT SHORT TRUNCATED BSR + //Get LCGID of highest priority LCID with data (todo) + for (lcid = DCCH; lcid < NR_MAX_NUM_LCID; lcid++) { + lcg_id = mac->scheduling_info.LCGID[lcid]; + if ((lcg_id < NR_MAX_NUM_LCGID) && (mac->scheduling_info.BSR_bytes[lcg_id])) { + lcg_id_bsr_trunc = lcg_id; + } + } + } else { + //Report SHORT BSR, clear bsr_t + mac_ce_p->bsr_t = NULL; + } + + // Trigger BSR Padding + mac->BSR_reporting_active |= NR_BSR_TRIGGER_PADDING; + } + + mac_ce_p->bsr_len = mac_ce_p->bsr_header_len + mac_ce_p->bsr_ce_len; + mac_ce_p->tot_mac_ce_len += mac_ce_p->bsr_len; + mac_ce_p->total_mac_pdu_header_len += mac_ce_p->bsr_len; + } + + //Fill BSR Infos + if (mac_ce_p->bsr_ce_len == 0) { + mac_ce_p->bsr_s = NULL; + mac_ce_p->bsr_l = NULL; + mac_ce_p->bsr_t = NULL; + } else if (mac_ce_p->bsr_header_len == sizeof(NR_MAC_SUBHEADER_SHORT)) { + mac_ce_p->bsr_s = NULL; + mac_ce_p->bsr_t = NULL; + mac_ce_p->bsr_l->Buffer_size0 = mac->scheduling_info.BSR[0]; + mac_ce_p->bsr_l->Buffer_size1 = mac->scheduling_info.BSR[1]; + mac_ce_p->bsr_l->Buffer_size2 = mac->scheduling_info.BSR[2]; + mac_ce_p->bsr_l->Buffer_size3 = mac->scheduling_info.BSR[3]; + mac_ce_p->bsr_l->Buffer_size4 = mac->scheduling_info.BSR[4]; + mac_ce_p->bsr_l->Buffer_size5 = mac->scheduling_info.BSR[5]; + mac_ce_p->bsr_l->Buffer_size6 = mac->scheduling_info.BSR[6]; + mac_ce_p->bsr_l->Buffer_size7 = mac->scheduling_info.BSR[7]; + LOG_D(NR_MAC, "[UE %d] Frame %d subframe %d BSR Trig=%d report LONG BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d level LCGID4 %d,level LCGID5 %d,level LCGID6 %d,level LCGID7 %d)\n", + module_idP, frameP, subframe, + mac->BSR_reporting_active, + mac->scheduling_info.BSR[0], + mac->scheduling_info.BSR[1], + mac->scheduling_info.BSR[2], + mac->scheduling_info.BSR[3], + mac->scheduling_info.BSR[4], + mac->scheduling_info.BSR[5], + mac->scheduling_info.BSR[6], + mac->scheduling_info.BSR[7]); + } else if (mac_ce_p->bsr_header_len == sizeof(NR_MAC_SUBHEADER_FIXED)) { + mac_ce_p->bsr_l = NULL; + + if ((mac_ce_p->bsr_t != NULL) && (mac->BSR_reporting_active & NR_BSR_TRIGGER_PADDING)) { + //Truncated BSR + mac_ce_p->bsr_s = NULL; + mac_ce_p->bsr_t->LcgID = lcg_id_bsr_trunc; + mac_ce_p->bsr_t->Buffer_size = mac->scheduling_info.BSR[lcg_id_bsr_trunc]; + LOG_D(NR_MAC, "[UE %d] Frame %d subframe %d BSR Trig=%d report TRUNCATED BSR with level %d for LCGID %d\n", + module_idP, frameP, subframe, + mac->BSR_reporting_active, + mac->scheduling_info.BSR[lcg_id_bsr_trunc], lcg_id_bsr_trunc); + } else { + mac_ce_p->bsr_t = NULL; + mac_ce_p->bsr_s->LcgID = lcg_id_bsr_trunc; + mac_ce_p->bsr_s->Buffer_size = mac->scheduling_info.BSR[lcg_id_bsr_trunc]; + LOG_D(NR_MAC, "[UE %d] Frame %d subframe %d BSR Trig=%d report SHORT BSR with level %d for LCGID %d\n", + module_idP, frameP, subframe, + mac->BSR_reporting_active, + mac->scheduling_info.BSR[lcg_id_bsr_trunc], lcg_id_bsr_trunc); + } + } + + LOG_D(NR_MAC, "[UE %d][SR] Gave SDU to PHY, clearing any scheduling request\n", module_idP); + mac->scheduling_info.SR_pending = 0; + mac->scheduling_info.SR_COUNTER = 0; + + /* Actions when a BSR is sent */ + if (mac_ce_p->bsr_ce_len) { + LOG_D(NR_MAC, "[UE %d] MAC BSR Sent !! bsr (ce%d,hdr%d) buff_len %d\n", + module_idP, mac_ce_p->bsr_ce_len, mac_ce_p->bsr_header_len, buflen); + // Reset ReTx BSR Timer + mac->scheduling_info.retxBSR_SF = nr_get_sf_retxBSRTimer(mac->scheduling_info.retxBSR_Timer); + LOG_D(NR_MAC, "[UE %d] MAC ReTx BSR Timer Reset =%d\n", module_idP, mac->scheduling_info.retxBSR_SF); + + // Reset Periodic Timer except when BSR is truncated + if ((mac_ce_p->bsr_t == NULL) && (mac->scheduling_info.periodicBSR_Timer != NR_BSR_Config__periodicBSR_Timer_infinity)) { + mac->scheduling_info.periodicBSR_SF = nr_get_sf_periodicBSRTimer(mac->scheduling_info.periodicBSR_Timer); + LOG_D(NR_MAC, "[UE %d] MAC Periodic BSR Timer Reset =%d\n", + module_idP, + mac->scheduling_info.periodicBSR_SF); + } + + // Reset BSR Trigger flags + mac->BSR_reporting_active = BSR_TRIGGER_NONE; + } +} /** * Function: to fetch data to be transmitted from RLC, place it in the ULSCH PDU buffer to generate the complete MAC PDU with sub-headers and MAC CEs according to ULSCH MAC PDU generation (6.1.2 TS 38.321) the selected sub-header for the payload sub-PDUs is NR_MAC_SUBHEADER_LONG * @module_idP Module ID + * @CC_id Component Carrier index * @frameP current UL frame * @subframe current UL slot * @gNB_index gNB index @@ -2050,36 +2639,51 @@ void nr_ue_sib1_scheduler(module_id_t module_idP, * @buflen TBS */ uint8_t nr_ue_get_sdu(module_id_t module_idP, + int CC_id, frame_t frameP, sub_frame_t subframe, uint8_t gNB_index, uint8_t *ulsch_buffer, uint16_t buflen) { - + NR_UE_MAC_CE_INFO mac_ce_info; + NR_UE_MAC_CE_INFO *mac_ce_p=&mac_ce_info; int16_t buflen_remain = 0; + mac_ce_p->bsr_len = 0; + mac_ce_p->bsr_ce_len = 0; + mac_ce_p->bsr_header_len = 0; + mac_ce_p->phr_len = 0; + //mac_ce_p->phr_ce_len = 0; + //mac_ce_p->phr_header_len = 0; + uint8_t lcid = 0; uint16_t sdu_length = 0; uint16_t num_sdus = 0; - uint16_t sdu_length_total = 0; + mac_ce_p->sdu_length_total = 0; + NR_BSR_SHORT bsr_short, bsr_truncated; + NR_BSR_LONG bsr_long; + mac_ce_p->bsr_s = &bsr_short; + mac_ce_p->bsr_l = &bsr_long; + mac_ce_p->bsr_t = &bsr_truncated; + //NR_POWER_HEADROOM_CMD phr; + //mac_ce_p->phr_p = &phr; NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP); + //int highest_priority = 16; const uint8_t sh_size = sizeof(NR_MAC_SUBHEADER_LONG); // Pointer used to build the MAC PDU by placing the RLC SDUs in the ULSCH buffer uint8_t *pdu = ulsch_buffer; - // Preparing the MAC CEs sub-PDUs and get the total size - unsigned char mac_header_control_elements[16] = {0}; - int tot_mac_ce_len = nr_write_ce_ulsch_pdu(&mac_header_control_elements[0], mac); - uint8_t total_mac_pdu_header_len = tot_mac_ce_len; + //nr_ue_get_sdu_mac_ce_pre updates all mac_ce related header field related to length + mac_ce_p->tot_mac_ce_len = nr_ue_get_sdu_mac_ce_pre(module_idP, CC_id, frameP, subframe, gNB_index, ulsch_buffer, buflen, mac_ce_p); + mac_ce_p->total_mac_pdu_header_len = mac_ce_p->tot_mac_ce_len; LOG_D(NR_MAC, "In %s: [UE %d] [%d.%d] process UL transport block at with size TBS = %d bytes \n", __FUNCTION__, module_idP, frameP, subframe, buflen); // Check for DCCH first // TO DO: Multiplex in the order defined by the logical channel prioritization - for (lcid = UL_SCH_LCID_SRB1; - lcid < MAX_LCID; lcid++) { + for (lcid = UL_SCH_LCID_SRB1; lcid < MAX_LCID; lcid++) { - buflen_remain = buflen - (total_mac_pdu_header_len + sdu_length_total + sh_size); + buflen_remain = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total + sh_size); LOG_D(NR_MAC, "In %s: [UE %d] [%d.%d] UL-DXCH -> ULSCH, RLC with LCID 0x%02x (TBS %d bytes, sdu_length_total %d bytes, MAC header len %d bytes, buflen_remain %d bytes)\n", __FUNCTION__, @@ -2088,8 +2692,8 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP, subframe, lcid, buflen, - sdu_length_total, - tot_mac_ce_len, + mac_ce_p->sdu_length_total, + mac_ce_p->tot_mac_ce_len, buflen_remain); while (buflen_remain > 0){ @@ -2119,7 +2723,7 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP, if (sdu_length > 0) { - LOG_D(MAC, "In %s: Generating UL MAC sub-PDU for SDU %d, length %d bytes, RB with LCID 0x%02x (buflen (TBS) %d bytes)\n", __FUNCTION__, + LOG_D(NR_MAC, "In %s: Generating UL MAC sub-PDU for SDU %d, length %d bytes, RB with LCID 0x%02x (buflen (TBS) %d bytes)\n", __FUNCTION__, num_sdus + 1, sdu_length, lcid, @@ -2139,40 +2743,53 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP, #endif pdu += sdu_length; - sdu_length_total += sdu_length; - total_mac_pdu_header_len += sh_size; + mac_ce_p->sdu_length_total += sdu_length; + mac_ce_p->total_mac_pdu_header_len += sh_size; num_sdus++; } else { pdu -= sh_size; - LOG_D(MAC, "In %s: no data to transmit for RB with LCID 0x%02x\n", __FUNCTION__, lcid); + LOG_D(NR_MAC, "In %s: no data to transmit for RB with LCID 0x%02x\n", __FUNCTION__, lcid); break; } - buflen_remain = buflen - (total_mac_pdu_header_len + sdu_length_total + sh_size); + buflen_remain = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total + sh_size); + //Update Buffer remain and BSR bytes after transmission + mac->scheduling_info.LCID_buffer_remain[lcid] -= sdu_length; + mac->scheduling_info.BSR_bytes[mac->scheduling_info.LCGID[lcid]] -= sdu_length; + LOG_D(NR_MAC, "[UE %d] Update BSR [%d.%d] BSR_bytes for LCG%d=%d\n", + module_idP, frameP, subframe, mac->scheduling_info.LCGID[lcid], + mac->scheduling_info.BSR_bytes[mac->scheduling_info.LCGID[lcid]]); + if (mac->scheduling_info.BSR_bytes[mac->scheduling_info.LCGID[lcid]] < 0) + mac->scheduling_info.BSR_bytes[mac->scheduling_info.LCGID[lcid]] = 0; } } - if (tot_mac_ce_len > 0) { + //nr_ue_get_sdu_mac_ce_post recalculates all mac_ce related header fields since buffer has been changed after mac_rlc_data_req. + //Also, BSR padding is handled here after knowing mac_ce_p->sdu_length_total. + nr_ue_get_sdu_mac_ce_post(module_idP, CC_id, frameP, subframe, gNB_index, ulsch_buffer, buflen, mac_ce_p); - LOG_D(NR_MAC, "In %s copying %d bytes of MAC CEs to the UL PDU \n", __FUNCTION__, tot_mac_ce_len); - memcpy((void *) pdu, (void *) mac_header_control_elements, tot_mac_ce_len); - pdu += (unsigned char) tot_mac_ce_len; + if (mac_ce_p->tot_mac_ce_len > 0) { + + LOG_D(NR_MAC, "In %s copying %d bytes of MAC CEs to the UL PDU \n", __FUNCTION__, mac_ce_p->tot_mac_ce_len); + nr_write_ce_ulsch_pdu(pdu, mac, 0, NULL, mac_ce_p->bsr_t, mac_ce_p->bsr_s, mac_ce_p->bsr_l); + pdu += (unsigned char) mac_ce_p->tot_mac_ce_len; #ifdef ENABLE_MAC_PAYLOAD_DEBUG - LOG_I(NR_MAC, "In %s: dumping MAC CE with length tot_mac_ce_len %d: \n", __FUNCTION__, tot_mac_ce_len); - log_dump(NR_MAC, mac_header_control_elements, tot_mac_ce_len, LOG_DUMP_CHAR, "\n"); + LOG_I(NR_MAC, "In %s: dumping MAC CE with length tot_mac_ce_len %d: \n", __FUNCTION__, mac_ce_p->tot_mac_ce_len); + log_dump(NR_MAC, mac_header_control_elements, mac_ce_p->tot_mac_ce_len, LOG_DUMP_CHAR, "\n"); #endif } - buflen_remain = buflen - (total_mac_pdu_header_len + sdu_length_total); + buflen_remain = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total); // Compute final offset for padding and fill remainder of ULSCH with 0 if (buflen_remain > 0) { + LOG_D(NR_MAC, "In %s filling remainder %d bytes to the UL PDU \n", __FUNCTION__, buflen_remain); ((NR_MAC_SUBHEADER_FIXED *) pdu)->R = 0; ((NR_MAC_SUBHEADER_FIXED *) pdu)->LCID = UL_SCH_LCID_PADDING; diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 13a2cb48dd..cedd095794 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -33,7 +33,7 @@ #include "COMMON/platform_types.h" #include "COMMON/platform_constants.h" #include "common/ran_context.h" - +#include "common/utils/nr/nr_common.h" #include "common/utils/LOG/log.h" #include "common/utils/LOG/vcd_signal_dumper.h" @@ -318,7 +318,16 @@ void config_common(int Mod_idP, int ssb_SubcarrierOffset, int pdsch_AntennaPorts scs_scaling = scs_scaling>>2; uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); uint16_t sco = absolute_diff%(12*scs_scaling); - AssertFatal(sco==0,"absoluteFrequencySSB has a subcarrier offset of %d while it should be alligned with CRBs\n",sco); + // values of subcarrier offset larger than the limit only indicates CORESET for Type0-PDCCH CSS set is not present + uint8_t ssb_SubcarrierOffset_limit = 0; + if(frequency_range == FR1) { + ssb_SubcarrierOffset_limit = 24; + } else { + ssb_SubcarrierOffset_limit = 12; + } + if (ssb_SubcarrierOffsetssb_table.ssb_offset_point_a.value = absolute_diff/(12*scs_scaling) - 10; //absoluteFrequencySSB is the central frequency of SSB which is made by 20RBs in total cfg->ssb_table.ssb_offset_point_a.tl.tag = NFAPI_NR_CONFIG_SSB_OFFSET_POINT_A_TAG; cfg->num_tlv++; @@ -421,9 +430,10 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, int pusch_AntennaPorts, int sib1_tda, NR_ServingCellConfigCommon_t *scc, - int add_ue, + NR_BCCH_BCH_Message_t *mib, + int add_ue, uint32_t rnti, - NR_CellGroupConfig_t *CellGroup) { + NR_CellGroupConfig_t *CellGroup) { if (scc != NULL ) { AssertFatal((scc->ssb_PositionsInBurst->present > 0) && (scc->ssb_PositionsInBurst->present < 4), "SSB Bitmap type %d is not valid\n",scc->ssb_PositionsInBurst->present); @@ -458,7 +468,7 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, ssb_SubcarrierOffset, pdsch_AntennaPorts, pusch_AntennaPorts, - scc); + scc); LOG_D(NR_MAC, "%s() %s:%d RC.nrmac[Mod_idP]->if_inst->NR_PHY_config_req:%p\n", __FUNCTION__, __FILE__, __LINE__, RC.nrmac[Mod_idP]->if_inst->NR_PHY_config_req); // if in nFAPI mode @@ -519,7 +529,9 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, } } } - + + if (mib) RC.nrmac[Mod_idP]->common_channels[0].mib = mib; + if (CellGroup) { const NR_ServingCellConfig_t *servingCellConfig = CellGroup->spCellConfig->spCellConfigDedicated; @@ -531,11 +543,13 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, const NR_BWP_Downlink_t *bwp = bwpList->list.array[i]; calculate_preferred_dl_tda(Mod_idP, bwp); } + } else { + calculate_preferred_dl_tda(Mod_idP, NULL); } const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList; if(ubwpList) { - AssertFatal(ubwpList->list.count > 0, "downlinkBWP_ToAddModList no BWPs!\n"); + AssertFatal(ubwpList->list.count > 0, "uplinkBWP_ToAddModList no BWPs!\n"); for (int i = 0; i < ubwpList->list.count; ++i) { const NR_BWP_Uplink_t *ubwp = ubwpList->list.array[i]; calculate_preferred_ul_tda(Mod_idP, ubwp); @@ -592,9 +606,26 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, LOG_I(NR_MAC,"Added new RA process for UE RNTI %04x with initial CellGroup\n", rnti); } else { // CellGroup has been updated const int UE_id = find_nr_UE_id(Mod_idP,rnti); + int target_ss; UE_info->CellGroup[UE_id] = CellGroup; LOG_I(NR_MAC,"Modified UE_id %d/%x with CellGroup\n",UE_id,rnti); process_CellGroup(CellGroup,&UE_info->UE_sched_ctrl[UE_id]); + // update coreset/searchspace + void *bwpd = NULL; + target_ss = NR_SearchSpace__searchSpaceType_PR_common; + if ((UE_info->UE_sched_ctrl[UE_id].active_bwp)) { + target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; + bwpd = (void*)UE_info->UE_sched_ctrl[UE_id].active_bwp->bwp_Dedicated; + } + else if (CellGroup->spCellConfig && + CellGroup->spCellConfig->spCellConfigDedicated && + (CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP)) { + target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; + bwpd = (void*)CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP; + } + UE_info->UE_sched_ctrl[UE_id].search_space = get_searchspace(scc, bwpd, target_ss); + UE_info->UE_sched_ctrl[UE_id].coreset = get_coreset(Mod_idP, scc, bwpd, UE_info->UE_sched_ctrl[UE_id].search_space, target_ss); + UE_info->UE_sched_ctrl[UE_id].maxL = 2; } } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_MAC_CONFIG, VCD_FUNCTION_OUT); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index 252144be3b..b62f8e0282 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -46,9 +46,6 @@ //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" -#include "openair1/PHY/defs_gNB.h" -#include "openair1/PHY/NR_TRANSPORT/nr_dlsch.h" - #include "intertask_interface.h" #include "executables/softmodem-common.h" @@ -62,80 +59,6 @@ uint16_t nr_pdcch_order_table[6] = { 31, 31, 511, 2047, 2047, 8191 }; uint8_t vnf_first_sched_entry = 1; -void clear_mac_stats(gNB_MAC_INST *gNB) { - memset((void*)gNB->UE_info.mac_stats,0,MAX_MOBILES_PER_GNB*sizeof(NR_mac_stats_t)); -} -#define MACSTATSSTRLEN 16384 -void dump_mac_stats(gNB_MAC_INST *gNB) -{ - NR_UE_info_t *UE_info = &gNB->UE_info; - int num = 1; - FILE *fd=fopen("nrMAC_stats.log","w"); - AssertFatal(fd!=NULL,"Cannot open nrMAC_stats.log, error %s\n",strerror(errno)); - char output[MACSTATSSTRLEN]; - memset(output,0,MACSTATSSTRLEN); - int stroff=0; - for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) { - stroff = sprintf(output,"UE ID %d RNTI %04x (%d/%d)\n", UE_id, UE_info->rnti[UE_id], num++, UE_info->num_UEs); - LOG_I(NR_MAC, "UE ID %d RNTI %04x (%d/%d) PH %d dB PCMAX %d dBm\n", - UE_id, - UE_info->rnti[UE_id], - num++, - UE_info->num_UEs, - UE_info->UE_sched_ctrl[UE_id].ph, - UE_info->UE_sched_ctrl[UE_id].pcmax); - NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id]; - const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0; - stroff+=sprintf(output+stroff,"UE %d: dlsch_rounds %d/%d/%d/%d, dlsch_errors %d, average RSRP %d (%d meas)\n", - UE_id, - stats->dlsch_rounds[0], stats->dlsch_rounds[1], - stats->dlsch_rounds[2], stats->dlsch_rounds[3], stats->dlsch_errors, - avg_rsrp, stats->num_rsrp_meas); - LOG_I(NR_MAC, "UE %d: dlsch_rounds %d/%d/%d/%d, dlsch_errors %d, average RSRP %d (%d meas)\n", - UE_id, - stats->dlsch_rounds[0], stats->dlsch_rounds[1], - stats->dlsch_rounds[2], stats->dlsch_rounds[3], stats->dlsch_errors, - avg_rsrp, stats->num_rsrp_meas); - stats->num_rsrp_meas = 0; - stats->cumul_rsrp = 0 ; - stroff+=sprintf(output+stroff,"UE %d: dlsch_total_bytes %d\n", UE_id, stats->dlsch_total_bytes); - stroff+=sprintf(output+stroff,"UE %d: ulsch_rounds %d/%d/%d/%d, ulsch_DTX %d, ulsch_errors %d\n", - UE_id, - stats->ulsch_rounds[0], stats->ulsch_rounds[1], - stats->ulsch_rounds[2], stats->ulsch_rounds[3], - stats->ulsch_DTX, - stats->ulsch_errors); - stroff+=sprintf(output+stroff, - "UE %d: ulsch_total_bytes_scheduled %d, ulsch_total_bytes_received %d\n", - UE_id, - stats->ulsch_total_bytes_scheduled, stats->ulsch_total_bytes_rx); - LOG_I(NR_MAC, "UE %d: dlsch_total_bytes %d\n", UE_id, stats->dlsch_total_bytes); - LOG_I(NR_MAC, "UE %d: ulsch_rounds %d/%d/%d/%d, ulsch_DTX %d, ulsch_errors %d\n", - UE_id, - stats->ulsch_rounds[0], stats->ulsch_rounds[1], - stats->ulsch_rounds[2], stats->ulsch_rounds[3], - stats->ulsch_DTX, - stats->ulsch_errors); - LOG_I(NR_MAC, - "UE %d: ulsch_total_bytes_scheduled %d, ulsch_total_bytes_received %d\n", - UE_id, - stats->ulsch_total_bytes_scheduled, stats->ulsch_total_bytes_rx); - for (int lc_id = 0; lc_id < 63; lc_id++) { - if (stats->lc_bytes_tx[lc_id] > 0) { - stroff+=sprintf(output+stroff, "UE %d: LCID %d: %d bytes TX\n", UE_id, lc_id, stats->lc_bytes_tx[lc_id]); - LOG_D(NR_MAC, "UE %d: LCID %d: %d bytes TX\n", UE_id, lc_id, stats->lc_bytes_tx[lc_id]); - } - if (stats->lc_bytes_rx[lc_id] > 0) { - stroff+=sprintf(output+stroff, "UE %d: LCID %d: %d bytes RX\n", UE_id, lc_id, stats->lc_bytes_rx[lc_id]); - LOG_D(NR_MAC, "UE %d: LCID %d: %d bytes RX\n", UE_id, lc_id, stats->lc_bytes_rx[lc_id]); - } - } - } - print_meas(&gNB->eNB_scheduler, "DL & UL scheduling timing stats", NULL, NULL); - if (stroff>0) fprintf(fd,"%s",output); - fclose(fd); -} - void clear_nr_nfapi_information(gNB_MAC_INST * gNB, int CC_idP, frame_t frameP, @@ -354,6 +277,7 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frame, slot,module_idP); const int bwp_id = 1; + char stats_output[16384]; gNB_MAC_INST *gNB = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = gNB->common_channels; @@ -384,6 +308,7 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, } memset(RC.nrmac[module_idP]->cce_list[0][0],0,MAX_NUM_CCE*sizeof(int)); // coreset0 + memset(RC.nrmac[module_idP]->cce_list[0][1],0,MAX_NUM_CCE*sizeof(int)); // coreset1 on initialBWP memset(RC.nrmac[module_idP]->cce_list[bwp_id][1],0,MAX_NUM_CCE*sizeof(int)); // coresetid 1 NR_UE_info_t *UE_info = &RC.nrmac[module_idP]->UE_info; for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) @@ -420,8 +345,11 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, } - if ((slot == 0) && (frame & 127) == 0) dump_mac_stats(RC.nrmac[module_idP]); - + if ((slot == 0) && (frame & 127) == 0) { + stats_output[0]='\0'; + dump_mac_stats(RC.nrmac[module_idP],stats_output,16384); + LOG_I(NR_MAC,"Frame.Slot %d.%d\n%s\n",frame,slot,stats_output); + } // This schedules MIB schedule_nr_mib(module_idP, frame, slot); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 26ef47f152..af3fff6d79 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -261,6 +261,8 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP else mu = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; + int bwp_start = NRRIV2PRBOFFSET(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value; // prach is scheduled according to configuration index and tables 6.3.3.2.2 to 6.3.3.2.4 if ( get_nr_prach_info_from_index(config_index, @@ -387,7 +389,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP const int16_t N_RA_RB = get_N_RA_RB(cfg->prach_config.prach_sub_c_spacing.value, mu_pusch); uint16_t *vrb_map_UL = &cc->vrb_map_UL[slotP * MAX_BWP_SIZE]; for (int i = 0; i < N_RA_RB * fdm; ++i) - vrb_map_UL[rach_ConfigGeneric->msg1_FrequencyStart + i] = 0xff; // all symbols + vrb_map_UL[bwp_start + rach_ConfigGeneric->msg1_FrequencyStart + i] = 0xff; // all symbols } } } @@ -691,20 +693,22 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - NR_BWP_Uplink_t *ubwp = ra->CellGroup ? - ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra->bwp_id-1] : - NULL; - - NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList= ubwp ? - ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList: - scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; - - int mu = ubwp ? - ubwp->bwp_Common->genericParameters.subcarrierSpacing : - scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing; + NR_BWP_Uplink_t *ubwp = NULL; + NR_BWP_UplinkDedicated_t *ubwpd = NULL; + NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = NULL; + NR_BWP_t *genericParameters = NULL; + if(ra->CellGroup) { + ubwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra->bwp_id-1]; + ubwpd = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; + genericParameters = &ubwp->bwp_Common->genericParameters; + pusch_TimeDomainAllocationList = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; + } else { + genericParameters = &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; + pusch_TimeDomainAllocationList = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; + } + int mu = genericParameters->subcarrierSpacing; uint8_t K2 = *pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->k2; - const int sched_frame = frame + (slot + K2 >= nr_slots_per_frame[mu]); const int sched_slot = (slot + K2) % nr_slots_per_frame[mu]; @@ -722,36 +726,23 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t tdd_beam_association[num_tdd_period] = ra->beam_id; } - int bwpSize = NRRIV2BW(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - int bwpStart = NRRIV2PRBOFFSET(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); int scs = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing; int fh = 0; int startSymbolAndLength = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; int mappingtype = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->mappingType; - if (ra->CellGroup) { - AssertFatal(ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count == 1, - "downlinkBWP_ToAddModList has %d BWP!\n", ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count); - int act_bwp_start = NRRIV2PRBOFFSET(ubwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - int act_bwp_size = NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - startSymbolAndLength = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; - mappingtype = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->mappingType; - scs = ubwp->bwp_Common->genericParameters.subcarrierSpacing; - fh = ubwp->bwp_Dedicated->pusch_Config->choice.setup->frequencyHopping ? 1 : 0; - if ((bwpStart < act_bwp_start) || (bwpSize > act_bwp_size)) - bwpStart = act_bwp_start; - } - uint16_t *vrb_map_UL = - &RC.nrmac[module_idP]->common_channels[CC_id].vrb_map_UL[sched_slot * MAX_BWP_SIZE]; + uint16_t *vrb_map_UL = &RC.nrmac[module_idP]->common_channels[CC_id].vrb_map_UL[sched_slot * MAX_BWP_SIZE]; + int BWPStart = nr_mac->type0_PDCCH_CSS_config[ra->beam_id].cset_start_rb; + int BWPSize = nr_mac->type0_PDCCH_CSS_config[ra->beam_id].num_rbs; int rbStart = 0; - for (int i = 0; (i < ra->msg3_nb_rb) && (rbStart <= (bwpSize - ra->msg3_nb_rb)); i++) { - if (vrb_map_UL[rbStart + bwpStart + i]) { + for (int i = 0; (i < ra->msg3_nb_rb) && (rbStart <= (BWPSize - ra->msg3_nb_rb)); i++) { + if (vrb_map_UL[rbStart + BWPStart + i]) { rbStart += i; i = 0; } } - if (rbStart > (bwpSize - ra->msg3_nb_rb)) { + if (rbStart > (BWPSize - ra->msg3_nb_rb)) { // cannot find free vrb_map for msg3 retransmission in this slot return; } @@ -776,33 +767,14 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t ra->msg3_round, startSymbolAndLength, ra->rnti, scs, - bwpSize, bwpStart, + BWPSize, BWPStart, mappingtype, fh, rbStart, ra->msg3_nb_rb); future_ul_tti_req->n_pdus += 1; // generation of DCI 0_0 to schedule msg3 retransmission NR_SearchSpace_t *ss = ra->ra_ss; - NR_BWP_Downlink_t *bwp = NULL; - NR_ControlResourceSet_t *coreset = NULL; - - NR_BWP_t *genericParameters = NULL; - if (ra->CellGroup && - ra->CellGroup->spCellConfig && - ra->CellGroup->spCellConfig->spCellConfigDedicated && - ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList && - ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->bwp_id-1]) { - bwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->bwp_id-1]; - genericParameters = &bwp->bwp_Common->genericParameters; - } - else { - genericParameters= &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; - } - - if (*ss->controlResourceSetId == 0) - coreset = nr_mac->sched_ctrlCommon->coreset; // this is coreset 0 - else - coreset = get_coreset(scc, bwp, ss, NR_SearchSpace__searchSpaceType_PR_common); + NR_ControlResourceSet_t *coreset = get_coreset(module_idP, scc, NULL, ss, NR_SearchSpace__searchSpaceType_PR_common); AssertFatal(coreset!=NULL,"Coreset cannot be null for RA-Msg3 retransmission\n"); nfapi_nr_ul_dci_request_t *ul_dci_req = &nr_mac->UL_dci_req[CC_id]; @@ -816,14 +788,19 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t ul_dci_request_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); pdcch_pdu_rel15 = &ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15; ul_dci_req->numPdus += 1; - nr_configure_pdcch(pdcch_pdu_rel15, ss, coreset, scc, genericParameters, NULL); + nr_configure_pdcch(nr_mac, pdcch_pdu_rel15, ss, coreset, scc, genericParameters, NULL); nr_mac->pdcch_pdu_idx[CC_id][ra->bwp_id][coresetid] = pdcch_pdu_rel15; } uint8_t aggregation_level; uint8_t nr_of_candidates; - find_aggregation_candidates(&aggregation_level, &nr_of_candidates, ss); - int CCEIndex = allocate_nr_CCEs(nr_mac, bwp, coreset, aggregation_level, 0, 0, nr_of_candidates); + for (int i=0; i<5; i++) { + // for now taking the lowest value among the available aggregation levels + find_aggregation_candidates(&aggregation_level, &nr_of_candidates, ss, 1<0) break; + } + AssertFatal(nr_of_candidates>0,"nr_of_candidates is 0\n"); + int CCEIndex = allocate_nr_CCEs(nr_mac, NULL, coreset, aggregation_level, 0, 0, nr_of_candidates); if (CCEIndex < 0) { LOG_E(NR_MAC, "%s(): cannot find free CCE for RA RNTI %04x!\n", __func__, ra->rnti); return; @@ -844,6 +821,7 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t memset(&uldci_payload, 0, sizeof(uldci_payload)); config_uldci(ubwp, + ubwpd, scc, pusch_pdu, &uldci_payload, @@ -864,7 +842,7 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t // Mark the corresponding RBs as used for (int rb = 0; rb < ra->msg3_nb_rb; rb++) { - vrb_map_UL[rbStart + bwpStart + rb] = 1; + vrb_map_UL[rbStart + BWPStart + rb] = 1; } // reset state to wait msg3 @@ -887,7 +865,7 @@ void nr_get_Msg3alloc(module_id_t module_id, // msg3 is scheduled in mixed slot in the following TDD period - uint16_t msg3_nb_rb = 8 + sizeof(NR_MAC_SUBHEADER_SHORT) + sizeof(NR_MAC_SUBHEADER_SHORT); // sdu has 6 or 8 bytes + uint16_t msg3_nb_rb = 8; // sdu has 6 or 8 bytes int mu = ubwp ? ubwp->bwp_Common->genericParameters.subcarrierSpacing : @@ -940,10 +918,19 @@ void nr_get_Msg3alloc(module_id_t module_id, LOG_D(NR_MAC, "[RAPROC] Msg3 slot %d: current slot %u Msg3 frame %u k2 %u Msg3_tda_id %u start symbol index %u\n", ra->Msg3_slot, current_slot, ra->Msg3_frame, k2,ra->Msg3_tda_id, StartSymbolIndex); uint16_t *vrb_map_UL = &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[ra->Msg3_slot * MAX_BWP_SIZE]; - const uint16_t bwpSize = NRRIV2BW(ubwp ? - ubwp->bwp_Common->genericParameters.locationAndBandwidth : - scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, - MAX_BWP_SIZE); + + int bwpSize = NRRIV2BW(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + int bwpStart = NRRIV2PRBOFFSET(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + + if (ra->CellGroup) { + AssertFatal(ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count == 1, + "downlinkBWP_ToAddModList has %d BWP!\n", ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count); + NR_BWP_Uplink_t *ubwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra->bwp_id - 1]; + int act_bwp_start = NRRIV2PRBOFFSET(ubwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + int act_bwp_size = NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + if (!((bwpStart >= act_bwp_start) && ((bwpStart+bwpSize) <= (act_bwp_start+act_bwp_size)))) + bwpStart = act_bwp_start; + } /* search msg3_nb_rb free RBs */ int rbSize = 0; @@ -951,16 +938,17 @@ void nr_get_Msg3alloc(module_id_t module_id, while (rbSize < msg3_nb_rb) { rbStart += rbSize; /* last iteration rbSize was not enough, skip it */ rbSize = 0; - while (rbStart < bwpSize && vrb_map_UL[rbStart]) + while (rbStart < bwpSize && vrb_map_UL[rbStart + bwpStart]) rbStart++; AssertFatal(rbStart < bwpSize - msg3_nb_rb, "no space to allocate Msg 3 for RA!\n"); while (rbStart + rbSize < bwpSize - && !vrb_map_UL[rbStart + rbSize] + && !vrb_map_UL[rbStart + bwpStart + rbSize] && rbSize < msg3_nb_rb) rbSize++; } ra->msg3_nb_rb = msg3_nb_rb; ra->msg3_first_rb = rbStart; + ra->msg3_bwp_start = bwpStart; } @@ -1046,12 +1034,12 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t uint16_t *vrb_map_UL = &RC.nrmac[module_idP]->common_channels[CC_id].vrb_map_UL[ra->Msg3_slot * MAX_BWP_SIZE]; for (int i = 0; i < ra->msg3_nb_rb; ++i) { - AssertFatal(!vrb_map_UL[i + ra->msg3_first_rb], + AssertFatal(!vrb_map_UL[i + ra->msg3_first_rb + ra->msg3_bwp_start], "RB %d in %4d.%2d is already taken, cannot allocate Msg3!\n", i + ra->msg3_first_rb, ra->Msg3_frame, ra->Msg3_slot); - vrb_map_UL[i + ra->msg3_first_rb] = 1; + vrb_map_UL[i + ra->msg3_first_rb + ra->msg3_bwp_start] = 1; } LOG_D(NR_MAC, "[gNB %d][RAPROC] Frame %d, Slot %d : CC_id %d RA is active, Msg3 in (%d,%d)\n", module_idP, frameP, slotP, CC_id, ra->Msg3_frame, ra->Msg3_slot); @@ -1070,9 +1058,6 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t memset(pusch_pdu, 0, sizeof(nfapi_nr_pusch_pdu_t)); int ibwp_size = NRRIV2BW(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - int ibwp_start = NRRIV2PRBOFFSET(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - int abwp_size = ibwp_size; - int abwp_start = ibwp_start; int scs = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing; int fh = 0; int startSymbolAndLength = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; @@ -1085,8 +1070,6 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t startSymbolAndLength = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; mappingtype = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->mappingType; - abwp_size = NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - abwp_start = NRRIV2PRBOFFSET(ubwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); scs = ubwp->bwp_Common->genericParameters.subcarrierSpacing; fh = ubwp->bwp_Dedicated->pusch_Config->choice.setup->frequencyHopping ? 1 : 0; } @@ -1101,17 +1084,11 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t ra->msg3_round, ra->rnti); - int bwp_start; - if ((ibwp_start < abwp_start) || (ibwp_size > abwp_size)) - bwp_start = abwp_start; - else - bwp_start = ibwp_start; - fill_msg3_pusch_pdu(pusch_pdu,scc, ra->msg3_round, startSymbolAndLength, ra->rnti, scs, - ibwp_size, bwp_start, + ibwp_size, ra->msg3_bwp_start, mappingtype, fh, ra->msg3_first_rb, ra->msg3_nb_rb); future_ul_tti_req->n_pdus += 1; @@ -1136,13 +1113,10 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; NR_SearchSpace_t *ss = ra->ra_ss; - long BWPSize = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - NR_BWP_Downlink_t *bwp = NULL; NR_ControlResourceSet_t *coreset = NULL; NR_BWP_t *genericParameters = NULL; NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList=NULL; - long BWPStart = 0; if (ra->CellGroup && ra->CellGroup->spCellConfig && @@ -1157,18 +1131,26 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra genericParameters= &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; pdsch_TimeDomainAllocationList = scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; } - BWPStart = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - if (*ss->controlResourceSetId == 0) - coreset = nr_mac->sched_ctrlCommon->coreset; // this is coreset 0 - else - coreset = get_coreset(scc, bwp, ss, NR_SearchSpace__searchSpaceType_PR_common); + long BWPStart = 0; + long BWPSize = 0; + NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config = NULL; + if(*ss->controlResourceSetId!=0) { + BWPStart = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + BWPSize = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + } else { + type0_PDCCH_CSS_config = &nr_mac->type0_PDCCH_CSS_config[ra->beam_id]; + BWPStart = type0_PDCCH_CSS_config->cset_start_rb; + BWPSize = type0_PDCCH_CSS_config->num_rbs; + } + + coreset = get_coreset(module_idP, scc, bwp, ss, NR_SearchSpace__searchSpaceType_PR_common); AssertFatal(coreset!=NULL,"Coreset cannot be null for RA-Msg2\n"); uint16_t *vrb_map = cc[CC_id].vrb_map; for (int i = 0; (i < rbSize) && (rbStart <= (BWPSize - rbSize)); i++) { - if (vrb_map[rbStart + i]) { + if (vrb_map[BWPStart + rbStart + i]) { rbStart += i; i = 0; } @@ -1188,7 +1170,12 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra uint8_t aggregation_level; uint8_t nr_of_candidates; - find_aggregation_candidates(&aggregation_level, &nr_of_candidates, ss); + for (int i=0; i<5; i++) { + // for now taking the lowest value among the available aggregation levels + find_aggregation_candidates(&aggregation_level, &nr_of_candidates, ss, 1<0) break; + } + AssertFatal(nr_of_candidates>0,"nr_of_candidates is 0\n"); int CCEIndex = allocate_nr_CCEs(nr_mac, bwp, coreset, aggregation_level,0,0,nr_of_candidates); if (CCEIndex < 0) { LOG_E(NR_MAC, "%s(): cannot find free CCE for RA RNTI %04x!\n", __func__, ra->rnti); @@ -1201,7 +1188,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra SLIV2SL(startSymbolAndLength, &startSymbolIndex, &nrOfSymbols); AssertFatal(startSymbolIndex >= 0, "StartSymbolIndex is negative\n"); - LOG_D(MAC,"Msg2 startSymbolIndex.nrOfSymbols %d.%d\n",startSymbolIndex,nrOfSymbols); + LOG_D(NR_MAC,"Msg2 startSymbolIndex.nrOfSymbols %d.%d\n",startSymbolIndex,nrOfSymbols); int mappingtype = pdsch_TimeDomainAllocationList->list.array[time_domain_assignment]->mappingType; @@ -1217,7 +1204,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2 + sizeof(nfapi_nr_dl_tti_pdcch_pdu)); dl_req->nPDUs += 1; pdcch_pdu_rel15 = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; - nr_configure_pdcch(pdcch_pdu_rel15, ss, coreset, scc, genericParameters, NULL); + nr_configure_pdcch(nr_mac, pdcch_pdu_rel15, ss, coreset, scc, genericParameters, NULL); nr_mac->pdcch_pdu_idx[CC_id][bwpid][coresetid] = pdcch_pdu_rel15; } @@ -1228,8 +1215,8 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra dl_req->nPDUs+=1; nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15; - LOG_I(NR_MAC,"[gNB %d][RAPROC] CC_id %d Frame %d, slotP %d: Generating RA-Msg2 DCI, rnti 0x%x, state %d\n", - module_idP, CC_id, frameP, slotP, ra->RA_rnti, ra->state); + LOG_I(NR_MAC,"[gNB %d][RAPROC] CC_id %d Frame %d, slotP %d: Generating RA-Msg2 DCI, rnti 0x%x, state %d, CoreSetType %d\n", + module_idP, CC_id, frameP, slotP, ra->RA_rnti, ra->state,pdcch_pdu_rel15->CoreSetType); // SCF222: PDU index incremented for each PDSCH PDU sent in TX control message. This is used to associate control // information to data and is reset every slot. @@ -1310,7 +1297,11 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra dci_pdu_rel15_t dci_payload; dci_payload.frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pdsch_pdu_rel15->rbSize, pdsch_pdu_rel15->rbStart, - pdsch_pdu_rel15->BWPSize); + BWPSize); + + LOG_D(NR_MAC,"Msg2 rbSize.rbStart.BWPsize %d.%d.%ld\n",pdsch_pdu_rel15->rbSize, + pdsch_pdu_rel15->rbStart, + BWPSize); dci_payload.time_domain_assignment.val = time_domain_assignment; dci_payload.vrb_to_prb_mapping.val = 0; @@ -1318,11 +1309,11 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra dci_payload.tb_scaling = tb_scaling; LOG_D(NR_MAC, - "[RAPROC] DCI type 1 payload: freq_alloc %d (%d,%d,%d), time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d \n", + "[RAPROC] DCI type 1 payload: freq_alloc %d (%d,%d,%ld), time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d \n", dci_payload.frequency_domain_assignment.val, pdsch_pdu_rel15->rbStart, pdsch_pdu_rel15->rbSize, - pdsch_pdu_rel15->BWPSize, + BWPSize, dci_payload.time_domain_assignment.val, dci_payload.vrb_to_prb_mapping.val, dci_payload.mcs, @@ -1333,7 +1324,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra pdcch_pdu_rel15->dci_pdu[0].RNTI, NR_RNTI_RA, NR_DL_DCI_FORMAT_1_0, - (unsigned long long)pdcch_pdu_rel15->FreqDomainResource, + *(unsigned long long *)pdcch_pdu_rel15->FreqDomainResource, pdcch_pdu_rel15->StartSymbolIndex, pdcch_pdu_rel15->DurationSymbols); @@ -1343,7 +1334,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra &dci_payload, NR_DL_DCI_FORMAT_1_0, NR_RNTI_RA, - pdsch_pdu_rel15->BWPSize, + BWPSize, bwpid); // DL TX request @@ -1373,11 +1364,11 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra // Mark the corresponding RBs as used for (int rb = 0; rb < rbSize; rb++) { - vrb_map[rb + rbStart] = 1; + vrb_map[BWPStart + rb + rbStart] = 1; } ra->state = WAIT_Msg3; - LOG_I(NR_MAC,"[gNB %d][RAPROC] Frame %d, Subframe %d: RA state %d\n", module_idP, frameP, slotP, ra->state); + LOG_D(NR_MAC,"[gNB %d][RAPROC] Frame %d, Subframe %d: RA state %d\n", module_idP, frameP, slotP, ra->state); } } @@ -1401,7 +1392,6 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra NR_BWP_Downlink_t *bwp = NULL; NR_ControlResourceSet_t *coreset = NULL; - NR_BWP_t *genericParameters = NULL; NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList=NULL; if (ra->CellGroup && @@ -1410,18 +1400,13 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList && ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->bwp_id-1]) { bwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->bwp_id-1]; - genericParameters = &bwp->bwp_Common->genericParameters; pdsch_TimeDomainAllocationList = bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; } else { - genericParameters= &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; pdsch_TimeDomainAllocationList = scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; } - if (*ss->controlResourceSetId == 0) - coreset = nr_mac->sched_ctrlCommon->coreset; // this is coreset 0 - else - coreset = get_coreset(scc, bwp, ss, NR_SearchSpace__searchSpaceType_PR_common); + coreset = get_coreset(module_idP, scc, bwp, ss, NR_SearchSpace__searchSpaceType_PR_common); AssertFatal(coreset!=NULL,"Coreset cannot be null for RA-Msg4\n"); @@ -1429,8 +1414,19 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra NR_UE_info_t *UE_info = &nr_mac->UE_info; NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; - long BWPSize = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - long BWPStart = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + NR_BWP_t *genericParameters = bwp ? & bwp->bwp_Common->genericParameters : &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; + + long BWPStart = 0; + long BWPSize = 0; + NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config = NULL; + if(*ss->controlResourceSetId!=0) { + BWPStart = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + BWPSize = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + } else { + type0_PDCCH_CSS_config = &nr_mac->type0_PDCCH_CSS_config[ra->beam_id]; + BWPStart = type0_PDCCH_CSS_config->cset_start_rb; + BWPSize = type0_PDCCH_CSS_config->num_rbs; + } /* get the PID of a HARQ process awaiting retrnasmission, or -1 otherwise */ int current_harq_pid = sched_ctrl->retrans_dl_harq.head; @@ -1450,7 +1446,12 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra // get CCEindex, needed also for PUCCH and then later for PDCCH uint8_t aggregation_level; uint8_t nr_of_candidates; - find_aggregation_candidates(&aggregation_level, &nr_of_candidates, ss); + for (int i=0; i<5; i++) { + // for now taking the lowest value among the available aggregation levels + find_aggregation_candidates(&aggregation_level, &nr_of_candidates, ss, 1<0) break; + } + AssertFatal(nr_of_candidates>0,"nr_of_candidates is 0\n"); int CCEIndex = allocate_nr_CCEs(nr_mac, bwp, coreset, aggregation_level,0,0,nr_of_candidates); if (CCEIndex < 0) { LOG_E(NR_MAC, "%s(): cannot find free CCE for RA RNTI %04x!\n", __func__, ra->rnti); @@ -1467,8 +1468,9 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra const int delta_PRI=0; int r_pucch = ((CCEIndex<<1)/N_cce)+(delta_PRI<<1); - int alloc = nr_acknack_scheduling(module_idP, UE_id, frameP, slotP, r_pucch); - AssertFatal(alloc>=0,"%d.%d Couldn't find a pucch allocation for ack nack (msg4), r_pucch %d (CCEindex%d,N_cce%d\n",frameP,slotP,r_pucch,CCEIndex,N_cce); + LOG_D(NR_MAC,"[RAPROC] Msg4 r_pucch %d (CCEIndex %d, N_cce %d, nb_of_candidates %d,delta_PRI %d)\n",r_pucch,CCEIndex,N_cce,nr_of_candidates,delta_PRI); + int alloc = nr_acknack_scheduling(module_idP, UE_id, frameP, slotP, r_pucch, 1); + AssertFatal(alloc>=0,"Couldn't find a pucch allocation for ack nack (msg4)\n"); NR_sched_pucch_t *pucch = &sched_ctrl->sched_pucch[alloc]; harq->feedback_slot = pucch->ul_slot; harq->feedback_frame = pucch->frame; @@ -1550,7 +1552,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra int i = 0; while ((i < rbSize) && (rbStart + rbSize <= BWPSize)) { - if (vrb_map[rbStart + i]) { + if (vrb_map[BWPStart + rbStart + i]) { rbStart += i+1; i = 0; } else { @@ -1583,7 +1585,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2 + sizeof(nfapi_nr_dl_tti_pdcch_pdu)); dl_req->nPDUs += 1; pdcch_pdu_rel15 = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; - nr_configure_pdcch(pdcch_pdu_rel15, ss, coreset, scc, genericParameters, NULL); + nr_configure_pdcch(nr_mac, pdcch_pdu_rel15, ss, coreset, scc, genericParameters, NULL); nr_mac->pdcch_pdu_idx[CC_id][bwpid][coresetid] = pdcch_pdu_rel15; } @@ -1653,7 +1655,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra dci_pdu_rel15_t dci_payload; dci_payload.frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pdsch_pdu_rel15->rbSize, pdsch_pdu_rel15->rbStart, - pdsch_pdu_rel15->BWPSize); + BWPSize); dci_payload.format_indicator = 1; dci_payload.time_domain_assignment.val = time_domain_assignment; @@ -1669,7 +1671,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra dci_payload.pdsch_to_harq_feedback_timing_indicator.val = pucch->timing_indicator; LOG_D(NR_MAC, - "[RAPROC] DCI type 1 payload: freq_alloc %d (%d,%d,%d), time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d pucchres %d harqtiming %d\n", + "[RAPROC] DCI 1_0 payload: freq_alloc %d (%d,%d,%d), time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d pucchres %d harqtiming %d\n", dci_payload.frequency_domain_assignment.val, pdsch_pdu_rel15->rbStart, pdsch_pdu_rel15->rbSize, @@ -1682,13 +1684,14 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra dci_payload.pdsch_to_harq_feedback_timing_indicator.val); LOG_D(NR_MAC, - "[RAPROC] DCI params: rnti 0x%x, rnti_type %d, dci_format %d coreset params: FreqDomainResource %llx, start_symbol %d n_symb %d\n", + "[RAPROC] DCI params: rnti 0x%x, rnti_type %d, dci_format %d coreset params: FreqDomainResource %llx, start_symbol %d n_symb %d, BWPsize %d\n", pdcch_pdu_rel15->dci_pdu[0].RNTI, NR_RNTI_TC, NR_DL_DCI_FORMAT_1_0, (unsigned long long)pdcch_pdu_rel15->FreqDomainResource, pdcch_pdu_rel15->StartSymbolIndex, - pdcch_pdu_rel15->DurationSymbols); + pdcch_pdu_rel15->DurationSymbols, + pdsch_pdu_rel15->BWPSize); fill_dci_pdu_rel15(scc, ra->CellGroup, @@ -1725,7 +1728,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra // Mark the corresponding RBs as used for (int rb = 0; rb < pdsch_pdu_rel15->rbSize; rb++) { - vrb_map[rb + pdsch_pdu_rel15->rbStart] = 1; + vrb_map[BWPStart + rb + pdsch_pdu_rel15->rbStart] = 1; } LOG_D(NR_MAC,"BWPSize: %i\n", pdcch_pdu_rel15->BWPSize); @@ -1744,7 +1747,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra LOG_D(NR_MAC,"numDlDci: %i\n", pdcch_pdu_rel15->numDlDci); ra->state = WAIT_Msg4_ACK; - LOG_I(NR_MAC,"[gNB %d][RAPROC] Frame %d, Subframe %d: RA state %d\n", module_idP, frameP, slotP, ra->state); + LOG_D(NR_MAC,"[gNB %d][RAPROC] Frame %d, Subframe %d: RA state %d\n", module_idP, frameP, slotP, ra->state); } } @@ -1934,7 +1937,7 @@ void nr_fill_rar(uint8_t Mod_idP, // TC-RNTI int t_crnti = rar->TCRNTI_2 + (rar->TCRNTI_1 << 8); - LOG_I(NR_MAC, "In %s: Transmitted RAR with t_alloc %d f_alloc %d ta_command %d mcs %d freq_hopping %d tpc_command %d csi_req %d t_crnti %x \n", + LOG_D(NR_MAC, "In %s: Transmitted RAR with t_alloc %d f_alloc %d ta_command %d mcs %d freq_hopping %d tpc_command %d csi_req %d t_crnti %x \n", __FUNCTION__, Msg3_t_alloc, Msg3_f_alloc, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index b74432b2ae..f35de9e28b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -219,6 +219,7 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) ssb_start_symbol, scs, FR1, + band, i_ssb, ssb_frame_periodicity, offset_pointa); @@ -246,6 +247,7 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) ssb_start_symbol, scs, FR1, + band, i_ssb, ssb_frame_periodicity, offset_pointa); @@ -281,6 +283,7 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) ssb_start_symbol, scs, FR2, + band, i_ssb, ssb_frame_periodicity, offset_pointa); @@ -328,19 +331,16 @@ uint32_t schedule_control_sib1(module_id_t module_id, gNB_MAC_INST *gNB_mac = RC.nrmac[module_id]; uint16_t *vrb_map = RC.nrmac[module_id]->common_channels[CC_id].vrb_map; - int ret; if (gNB_mac->sched_ctrlCommon == NULL){ LOG_D(NR_MAC,"schedule_control_common: Filling nr_mac->sched_ctrlCommon\n"); gNB_mac->sched_ctrlCommon = calloc(1,sizeof(*gNB_mac->sched_ctrlCommon)); gNB_mac->sched_ctrlCommon->search_space = calloc(1,sizeof(*gNB_mac->sched_ctrlCommon->search_space)); gNB_mac->sched_ctrlCommon->coreset = calloc(1,sizeof(*gNB_mac->sched_ctrlCommon->coreset)); - for (int i=0; i<3; i++){ // loop over possible aggregation levels - ret = fill_searchSpaceZero(gNB_mac->sched_ctrlCommon->search_space,type0_PDCCH_CSS_config,4<sched_ctrlCommon->search_space,type0_PDCCH_CSS_config); fill_coresetZero(gNB_mac->sched_ctrlCommon->coreset,type0_PDCCH_CSS_config); + gNB_mac->cset0_bwp_start = type0_PDCCH_CSS_config->cset_start_rb; + gNB_mac->cset0_bwp_size = type0_PDCCH_CSS_config->num_rbs; } gNB_mac->sched_ctrlCommon->pdsch_semi_static.time_domain_allocation = time_domain_allocation; @@ -349,8 +349,12 @@ uint32_t schedule_control_sib1(module_id_t module_id, gNB_mac->sched_ctrlCommon->num_total_bytes = num_total_bytes; uint8_t nr_of_candidates; - find_aggregation_candidates(&gNB_mac->sched_ctrlCommon->aggregation_level, &nr_of_candidates, gNB_mac->sched_ctrlCommon->search_space); + for (int i=0; i<3; i++) { + find_aggregation_candidates(&gNB_mac->sched_ctrlCommon->aggregation_level, &nr_of_candidates, gNB_mac->sched_ctrlCommon->search_space,4<0) break; // choosing the lower value of aggregation level available + } + AssertFatal(nr_of_candidates>0,"nr_of_candidates is 0\n"); gNB_mac->sched_ctrlCommon->cce_index = allocate_nr_CCEs(RC.nrmac[module_id], NULL, gNB_mac->sched_ctrlCommon->coreset, @@ -434,7 +438,8 @@ void nr_fill_nfapi_dl_sib1_pdu(int Mod_idP, dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); dl_req->nPDUs += 1; nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; - nr_configure_pdcch(pdcch_pdu_rel15, + nr_configure_pdcch(NULL, + pdcch_pdu_rel15, gNB_mac->sched_ctrlCommon->search_space, gNB_mac->sched_ctrlCommon->coreset, scc, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 9e9e105ba0..c40a665d4a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -29,11 +29,7 @@ */ -/*PHY*/ -#include "PHY/CODING/coding_defs.h" -#include "PHY/defs_nr_common.h" #include "common/utils/nr/nr_common.h" -#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" /*MAC*/ #include "NR_MAC_COMMON/nr_mac.h" #include "NR_MAC_gNB/nr_mac_gNB.h" @@ -56,7 +52,6 @@ #define HALFWORD 16 #define WORD 32 //#define SIZE_OF_POINTER sizeof (void *) -static int loop_dcch_dtch = DL_SCH_LCID_DTCH; void calculate_preferred_dl_tda(module_id_t module_id, const NR_BWP_Downlink_t *bwp) { @@ -71,16 +66,22 @@ void calculate_preferred_dl_tda(module_id_t module_id, const NR_BWP_Downlink_t * scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; const int symb_dlMixed = tdd ? (1 << tdd->nrofDownlinkSymbols) - 1 : 0; - const int target_ss = bwp ? NR_SearchSpace__searchSpaceType_PR_ue_Specific : NR_SearchSpace__searchSpaceType_PR_common; + int target_ss; + if (bwp) { + target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; + } + else { + target_ss = NR_SearchSpace__searchSpaceType_PR_common; + } NR_SearchSpace_t *search_space = get_searchspace(scc, bwp ? bwp->bwp_Dedicated : NULL, target_ss); - const NR_ControlResourceSet_t *coreset = get_coreset(scc, (NR_BWP_Downlink_t*)bwp, search_space, target_ss); - + NR_ControlResourceSet_t *coreset = get_coreset(module_id, scc, bwp ? bwp->bwp_Dedicated : NULL, search_space, target_ss); // get coreset symbol "map" const uint16_t symb_coreset = (1 << coreset->duration) - 1; /* check that TDA index 0 fits into DL and does not overlap CORESET */ - const struct NR_PDSCH_TimeDomainResourceAllocationList *tdaList = - bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; + const struct NR_PDSCH_TimeDomainResourceAllocationList *tdaList = bwp ? + bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList : + scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; AssertFatal(tdaList->list.count >= 1, "need to have at least one TDA for DL slots\n"); const NR_PDSCH_TimeDomainResourceAllocation_t *tdaP_DL = tdaList->list.array[0]; AssertFatal(!tdaP_DL->k0 || *tdaP_DL->k0 == 0, @@ -131,7 +132,7 @@ void calculate_preferred_dl_tda(module_id_t module_id, const NR_BWP_Downlink_t * nrmac->preferred_dl_tda[bwp_id][i] = 0; else if (tdd && nr_mix_slots && i % nr_slots_period == tdd->nrofDownlinkSlots) nrmac->preferred_dl_tda[bwp_id][i] = tdaMi; - LOG_I(MAC, "slot %d preferred_dl_tda %d\n", i, nrmac->preferred_dl_tda[bwp_id][i]); + LOG_D(MAC, "slot %d preferred_dl_tda %d\n", i, nrmac->preferred_dl_tda[bwp_id][i]); } } @@ -391,39 +392,57 @@ void nr_store_dlsch_buffer(module_id_t module_id, NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; sched_ctrl->num_total_bytes = 0; - if ((sched_ctrl->lcid_mask&(1<<4)) > 0 && loop_dcch_dtch == DL_SCH_LCID_DCCH1) - loop_dcch_dtch = DL_SCH_LCID_DTCH; - else if ((sched_ctrl->lcid_mask&(1<<1)) > 0 && loop_dcch_dtch == DL_SCH_LCID_DTCH) - loop_dcch_dtch = DL_SCH_LCID_DCCH; - /*else if ((sched_ctrl->lcid_mask&(1<<2)) > 0 && loop_dcch_dtch == DL_SCH_LCID_DCCH) - loop_dcch_dtch = DL_SCH_LCID_DCCH1;*/ - else if ((sched_ctrl->lcid_mask&(1<<2)) > 0){ //&& loop_dcch_dtch == DL_SCH_LCID_DCCH - if (loop_dcch_dtch == DL_SCH_LCID_DCCH) - loop_dcch_dtch = DL_SCH_LCID_DCCH1; - else if(loop_dcch_dtch == DL_SCH_LCID_DCCH1) - loop_dcch_dtch = DL_SCH_LCID_DCCH; - } - const int lcid = loop_dcch_dtch; - // const int lcid = DL_SCH_LCID_DTCH; + int lcid; const uint16_t rnti = UE_info->rnti[UE_id]; - sched_ctrl->rlc_status[lcid] = mac_rlc_status_ind(module_id, - rnti, - module_id, - frame, - slot, - ENB_FLAG_YES, - MBMS_FLAG_NO, - lcid, - 0, - 0); + LOG_D(NR_MAC,"UE %d/%x : lcid_mask %x\n",UE_id,rnti,sched_ctrl->lcid_mask); + if ((sched_ctrl->lcid_mask&(1<<2)) > 0) + sched_ctrl->rlc_status[DL_SCH_LCID_DCCH1] = mac_rlc_status_ind(module_id, + rnti, + module_id, + frame, + slot, + ENB_FLAG_YES, + MBMS_FLAG_NO, + DL_SCH_LCID_DCCH1, + 0, + 0); + if ((sched_ctrl->lcid_mask&(1<<1)) > 0) + sched_ctrl->rlc_status[DL_SCH_LCID_DCCH] = mac_rlc_status_ind(module_id, + rnti, + module_id, + frame, + slot, + ENB_FLAG_YES, + MBMS_FLAG_NO, + DL_SCH_LCID_DCCH, + 0, + 0); + if ((sched_ctrl->lcid_mask&(1<<4)) > 0) + sched_ctrl->rlc_status[DL_SCH_LCID_DTCH] = mac_rlc_status_ind(module_id, + rnti, + module_id, + frame, + slot, + ENB_FLAG_YES, + MBMS_FLAG_NO, + DL_SCH_LCID_DTCH, + 0, + 0); + + if(sched_ctrl->rlc_status[DL_SCH_LCID_DCCH].bytes_in_buffer > 0){ + lcid = DL_SCH_LCID_DCCH; + } + else if (sched_ctrl->rlc_status[DL_SCH_LCID_DCCH1].bytes_in_buffer > 0) + { + lcid = DL_SCH_LCID_DCCH1; + }else{ + lcid = DL_SCH_LCID_DTCH; + } + sched_ctrl->num_total_bytes += sched_ctrl->rlc_status[lcid].bytes_in_buffer; - LOG_D(NR_MAC, - "%d.%d, LCID%d:->DLSCH, RLC status %d bytes. \n", - frame, - slot, - lcid, - sched_ctrl->num_total_bytes); + //later multiplex here. Just select DCCH/SRB before DTCH/DRB + sched_ctrl->lcid_to_schedule = lcid; if (sched_ctrl->num_total_bytes == 0 && !sched_ctrl->ta_apply) /* If TA should be applied, give at least one RB */ @@ -453,17 +472,22 @@ bool allocate_dl_retransmission(module_id_t module_id, NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; NR_sched_pdsch_t *retInfo = &sched_ctrl->harq_processes[current_harq_pid].sched_pdsch; + NR_CellGroupConfig_t *cg = UE_info->CellGroup[UE_id]; + NR_BWP_DownlinkDedicated_t *bwpd= cg ? cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP:NULL; + + NR_BWP_t *genericParameters = sched_ctrl->active_bwp ? &sched_ctrl->active_bwp->bwp_Common->genericParameters : &RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon->downlinkConfigCommon->initialDownlinkBWP->genericParameters; const uint16_t bwpSize = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - int rbStart = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + int rbStart = 0; // start wrt BWPstart NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; - const long f = sched_ctrl->active_bwp ? sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats : 0; + const long f = (sched_ctrl->active_bwp ||bwpd) ? sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats : 0; int rbSize = 0; - const int tda = sched_ctrl->active_bwp ? RC.nrmac[module_id]->preferred_dl_tda[sched_ctrl->active_bwp->bwp_Id][slot] : 1; + const int tda = RC.nrmac[module_id]->preferred_dl_tda[sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0][slot]; + AssertFatal(tda>=0,"Unable to find PDSCH time domain allocation in list\n"); if (tda == retInfo->time_domain_allocation) { /* Check that there are enough resources for retransmission */ while (rbSize < retInfo->rbSize) { @@ -481,7 +505,7 @@ bool allocate_dl_retransmission(module_id_t module_id, /* check whether we need to switch the TDA allocation since the last * (re-)transmission */ if (ps->time_domain_allocation != tda) - nr_set_pdsch_semi_static(scc, UE_info->CellGroup[UE_id], sched_ctrl->active_bwp, tda, f, ps); + nr_set_pdsch_semi_static(scc, cg, sched_ctrl->active_bwp, bwpd, tda, f, ps); } else { /* the retransmission will use a different time domain allocation, check * that we have enough resources */ @@ -491,7 +515,7 @@ bool allocate_dl_retransmission(module_id_t module_id, rbSize++; NR_pdsch_semi_static_t temp_ps; temp_ps.nrOfLayers = 1; - nr_set_pdsch_semi_static(scc, UE_info->CellGroup[UE_id], sched_ctrl->active_bwp, tda, f, &temp_ps); + nr_set_pdsch_semi_static(scc, cg, sched_ctrl->active_bwp, bwpd, tda, f, &temp_ps); uint32_t new_tbs; uint16_t new_rbSize; bool success = nr_find_nb_rb(retInfo->Qm, @@ -524,7 +548,7 @@ bool allocate_dl_retransmission(module_id_t module_id, /* Find PUCCH occasion: if it fails, undo CCE allocation (undoing PUCCH * allocation after CCE alloc fail would be more complex) */ - const int alloc = nr_acknack_scheduling(module_id, UE_id, frame, slot, -1); + const int alloc = nr_acknack_scheduling(module_id, UE_id, frame, slot, -1, 0); if (alloc<0) { LOG_D(MAC, "%s(): could not find PUCCH for UE %d/%04x@%d.%d\n", @@ -535,18 +559,18 @@ bool allocate_dl_retransmission(module_id_t module_id, slot); int cid = sched_ctrl->coreset->controlResourceSetId; UE_info->num_pdcch_cand[UE_id][cid]--; - int *cce_list = RC.nrmac[module_id]->cce_list[sched_ctrl->active_bwp->bwp_Id][cid]; + int *cce_list = RC.nrmac[module_id]->cce_list[sched_ctrl->active_bwp?sched_ctrl->active_bwp->bwp_Id:0][cid]; for (int i = 0; i < sched_ctrl->aggregation_level; i++) cce_list[sched_ctrl->cce_index + i] = 0; return false; } - sched_ctrl->sched_pdsch.pucch_allocation = alloc; - /* just reuse from previous scheduling opportunity, set new start RB */ sched_ctrl->sched_pdsch = *retInfo; sched_ctrl->sched_pdsch.rbStart = rbStart; + sched_ctrl->sched_pdsch.pucch_allocation = alloc; + /* retransmissions: directly allocate */ *n_rb_sched -= sched_ctrl->sched_pdsch.rbSize; for (int rb = 0; rb < sched_ctrl->sched_pdsch.rbSize; rb++) @@ -636,6 +660,8 @@ void pf_dl(module_id_t module_id, p = &UE_sched.next[*max]; *max = UE_sched.next[*max]; *p = -1; + NR_CellGroupConfig_t *cg = UE_info->CellGroup[UE_id]; + NR_BWP_DownlinkDedicated_t *bwpd= cg ? cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP:NULL; NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; int bwp_Id = sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0; @@ -645,7 +671,7 @@ void pf_dl(module_id_t module_id, &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; const uint16_t bwpSize = NRRIV2BW(genericParameters->locationAndBandwidth,MAX_BWP_SIZE); - int rbStart = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + int rbStart = 0; // start wrt BWPstart /* Find a free CCE */ bool freeCCE = find_free_CCE(module_id, slot, UE_id); @@ -659,7 +685,7 @@ void pf_dl(module_id_t module_id, /* Find PUCCH occasion: if it fails, undo CCE allocation (undoing PUCCH * allocation after CCE alloc fail would be more complex) */ - const int alloc = nr_acknack_scheduling(module_id, UE_id, frame, slot, -1); + const int alloc = nr_acknack_scheduling(module_id, UE_id, frame, slot, -1,0); if (alloc<0) { LOG_D(NR_MAC, "%s(): could not find PUCCH for UE %d/%04x@%d.%d\n", @@ -684,12 +710,14 @@ void pf_dl(module_id_t module_id, max_rbSize++; /* MCS has been set above */ - const int tda = sched_ctrl->active_bwp ? RC.nrmac[module_id]->preferred_dl_tda[sched_ctrl->active_bwp->bwp_Id][slot] : 1; + + const int tda = RC.nrmac[module_id]->preferred_dl_tda[sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0][slot]; + AssertFatal(tda>=0,"Unable to find PDSCH time domain allocation in list\n"); NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; - const long f = sched_ctrl->active_bwp ? sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats : 0; + const long f = (sched_ctrl->active_bwp || bwpd) ? sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats : 0; if (ps->time_domain_allocation != tda) - nr_set_pdsch_semi_static(scc, UE_info->CellGroup[UE_id], sched_ctrl->active_bwp, tda, f, ps); + nr_set_pdsch_semi_static(scc, UE_info->CellGroup[UE_id], sched_ctrl->active_bwp, bwpd, tda, f, ps); sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, ps->mcsTableIdx); sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, ps->mcsTableIdx); sched_pdsch->pucch_allocation = alloc; @@ -718,14 +746,12 @@ void pf_dl(module_id_t module_id, void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t slot) { NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; - NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon; - if (UE_info->num_UEs == 0) return; + NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon; const int CC_id = 0; - /* Get bwpSize from the first UE */ int UE_id = UE_info->list.head; NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; @@ -734,6 +760,10 @@ void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth: scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + const uint16_t BWPStart = NRRIV2PRBOFFSET(sched_ctrl->active_bwp ? + sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth: + scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, + MAX_BWP_SIZE); uint16_t *vrb_map = RC.nrmac[module_id]->common_channels[CC_id].vrb_map; uint8_t rballoc_mask[bwpSize]; @@ -741,7 +771,7 @@ void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t for (int i = 0; i < bwpSize; i++) { // calculate mask: init with "NOT" vrb_map: // if any RB in vrb_map is blocked (1), the current RBG will be 0 - rballoc_mask[i] = !vrb_map[i]; + rballoc_mask[i] = !vrb_map[i+BWPStart]; n_rb_sched += rballoc_mask[i]; } @@ -812,6 +842,8 @@ void nr_schedule_ue_spec(module_id_t module_id, if (sched_ctrl->ul_failure==1 && get_softmodem_params()->phy_test==0) continue; NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; UE_info->mac_stats[UE_id].dlsch_current_bytes = 0; + NR_CellGroupConfig_t *cg = UE_info->CellGroup[UE_id]; + NR_BWP_DownlinkDedicated_t *bwpd= cg ? cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP:NULL; /* update TA and set ta_apply every 10 frames. * Possible improvement: take the periodicity from input file. @@ -866,19 +898,28 @@ void nr_schedule_ue_spec(module_id_t module_id, UE_info->mac_stats[UE_id].dlsch_rounds[harq->round]++; LOG_D(NR_MAC, - "%4d.%2d RNTI %04x start %3d RBs %3d startSymbol %2d nb_symbol %2d MCS %2d TBS %4d HARQ PID %2d round %d NDI %d\n", + "%4d.%2d [DLSCH/PDSCH/PUCCH] UE %d RNTI %04x DCI L %d start %3d RBs %3d startSymbol %2d nb_symbol %2d dmrspos %x MCS %2d TBS %4d HARQ PID %2d round %d RV %d NDI %d dl_data_to_ULACK %d (%d.%d) PUCCH allocation %d TPC %d\n", frame, slot, + UE_id, rnti, + sched_ctrl->aggregation_level, sched_pdsch->rbStart, sched_pdsch->rbSize, ps->startSymbolIndex, ps->nrOfSymbols, + ps->dl_dmrs_symb_pos, sched_pdsch->mcs, TBS, current_harq_pid, harq->round, - harq->ndi); + nr_rv_round_map[harq->round], + harq->ndi, + pucch->timing_indicator, + pucch->frame, + pucch->ul_slot, + sched_pdsch->pucch_allocation, + sched_ctrl->tpc1); NR_BWP_Downlink_t *bwp = sched_ctrl->active_bwp; @@ -889,7 +930,7 @@ void nr_schedule_ue_spec(module_id_t module_id, NR_BWP_t *genericParameters = bwp ? &bwp->bwp_Common->genericParameters : &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; const int bwpid = bwp ? bwp->bwp_Id : 0; - const int coresetid = bwp ? sched_ctrl->coreset->controlResourceSetId : gNB_mac->sched_ctrlCommon->coreset->controlResourceSetId; + const int coresetid = (bwp||bwpd) ? sched_ctrl->coreset->controlResourceSetId : gNB_mac->sched_ctrlCommon->coreset->controlResourceSetId; nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu = gNB_mac->pdcch_pdu_idx[CC_id][bwpid][coresetid]; if (!pdcch_pdu) { nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdcch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs]; @@ -898,10 +939,10 @@ void nr_schedule_ue_spec(module_id_t module_id, dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); dl_req->nPDUs += 1; pdcch_pdu = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; - LOG_D(NR_MAC,"Trying to configure DL pdcch for bwp %d, cs %d\n",bwpid,coresetid); - NR_SearchSpace_t *ss = bwp ? sched_ctrl->search_space:gNB_mac->sched_ctrlCommon->search_space; - NR_ControlResourceSet_t *coreset = bwp? sched_ctrl->coreset:gNB_mac->sched_ctrlCommon->coreset; - nr_configure_pdcch(pdcch_pdu, ss, coreset, scc, genericParameters, NULL); + LOG_D(NR_MAC,"Trying to configure DL pdcch for UE %d, bwp %d, cs %d\n",UE_id,bwpid,coresetid); + NR_SearchSpace_t *ss = (bwp||bwpd) ? sched_ctrl->search_space:gNB_mac->sched_ctrlCommon->search_space; + NR_ControlResourceSet_t *coreset = (bwp||bwpd)? sched_ctrl->coreset:gNB_mac->sched_ctrlCommon->coreset; + nr_configure_pdcch(gNB_mac, pdcch_pdu, ss, coreset, scc, genericParameters, NULL); gNB_mac->pdcch_pdu_idx[CC_id][bwpid][coresetid] = pdcch_pdu; } @@ -1034,7 +1075,7 @@ void nr_schedule_ue_spec(module_id_t module_id, dci_payload.dmrs_sequence_initialization.val = pdsch_pdu->SCID; LOG_D(NR_MAC, "%4d.%2d DCI type 1 payload: freq_alloc %d (%d,%d,%d), " - "time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d tpc %d\n", + "time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d tpc %d ti %d\n", frame, slot, dci_payload.frequency_domain_assignment.val, @@ -1047,10 +1088,17 @@ void nr_schedule_ue_spec(module_id_t module_id, dci_payload.tb_scaling, dci_payload.ndi, dci_payload.rv, - dci_payload.tpc); + dci_payload.tpc, + pucch->timing_indicator); const long f = sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats; - const int dci_format = bwp ? (f ? NR_DL_DCI_FORMAT_1_1 : NR_DL_DCI_FORMAT_1_0) : NR_DL_DCI_FORMAT_1_0; + int dci_format; + if (sched_ctrl->search_space) { + dci_format = f ? NR_DL_DCI_FORMAT_1_1 : NR_DL_DCI_FORMAT_1_0; + } + else { + dci_format = NR_DL_DCI_FORMAT_1_0; + } const int rnti_type = NR_RNTI_C; fill_dci_pdu_rel15(scc, @@ -1105,7 +1153,7 @@ void nr_schedule_ue_spec(module_id_t module_id, /* next, get RLC data */ // const int lcid = DL_SCH_LCID_DTCH; - const int lcid = loop_dcch_dtch; + const int lcid = sched_ctrl->lcid_to_schedule; int dlsch_total_bytes = 0; if (sched_ctrl->num_total_bytes > 0) { tbs_size_t len = 0; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index f707e6efeb..f1005cea70 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -29,11 +29,8 @@ */ #include "nr_mac_gNB.h" -#include "SCHED_NR/sched_nr.h" #include "NR_MAC_gNB/mac_proto.h" #include "LAYER2/NR_MAC_COMMON/nr_mac_common.h" -#include "PHY/NR_TRANSPORT/nr_dlsch.h" -#include "PHY/NR_TRANSPORT/nr_dci.h" #include "executables/nr-softmodem.h" #include "LAYER2/NR_MAC_COMMON/nr_mac.h" #include "executables/softmodem-common.h" @@ -56,7 +53,7 @@ //#define UL_HARQ_PRINT extern RAN_CONTEXT_t RC; -const uint8_t nr_rv_round_map[4] = {0, 2, 1, 3}; +const uint8_t nr_rv_round_map[4] = {0, 2, 3, 1}; //#define ENABLE_MAC_PAYLOAD_DEBUG 1 //uint8_t mac_pdu[MAX_NR_DLSCH_PAYLOAD_BYTES]; @@ -283,6 +280,7 @@ void nr_preprocessor_phytest(module_id_t module_id, NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; /* find largest unallocated chunk */ const int bwpSize = NRRIV2BW(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + const int BWPStart = NRRIV2PRBOFFSET(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); int rbStart = 0; int rbSize = 0; if (target_dl_bw>bwpSize) @@ -291,11 +289,11 @@ void nr_preprocessor_phytest(module_id_t module_id, /* loop ensures that we allocate exactly target_dl_bw, or return */ while (true) { /* advance to first free RB */ - while (rbStart < bwpSize && vrb_map[rbStart]) + while (rbStart < bwpSize && vrb_map[rbStart + BWPStart]) rbStart++; rbSize = 1; /* iterate until we are at target_dl_bw or no available RBs */ - while (rbStart + rbSize < bwpSize && !vrb_map[rbStart + rbSize] && rbSize < target_dl_bw) + while (rbStart + rbSize < bwpSize && !vrb_map[rbStart + rbSize + BWPStart] && rbSize < target_dl_bw) rbSize++; /* found target_dl_bw? */ if (rbSize == target_dl_bw) @@ -322,11 +320,19 @@ void nr_preprocessor_phytest(module_id_t module_id, 0, 0); sched_ctrl->num_total_bytes += sched_ctrl->rlc_status[lcid].bytes_in_buffer; + sched_ctrl->lcid_to_schedule = lcid; uint8_t nr_of_candidates; - find_aggregation_candidates(&sched_ctrl->aggregation_level, - &nr_of_candidates, - sched_ctrl->search_space); + for (int i=0; i<5; i++) { + // for now taking the lowest value among the available aggregation levels + find_aggregation_candidates(&sched_ctrl->aggregation_level, + &nr_of_candidates, + sched_ctrl->search_space, + 1<0) break; + } + AssertFatal(nr_of_candidates>0,"nr_of_candidates is 0\n"); + const int cid = sched_ctrl->coreset->controlResourceSetId; const uint16_t Y = UE_info->Y[UE_id][cid][slot]; const int m = UE_info->num_pdcch_cand[UE_id][cid]; @@ -342,7 +348,7 @@ void nr_preprocessor_phytest(module_id_t module_id, __func__, UE_id); - const int alloc = nr_acknack_scheduling(module_id, UE_id, frame, slot, -1); + const int alloc = nr_acknack_scheduling(module_id, UE_id, frame, slot, -1,0); if (alloc < 0) { LOG_D(MAC, "%s(): could not find PUCCH for UE %d/%04x@%d.%d\n", @@ -368,12 +374,11 @@ void nr_preprocessor_phytest(module_id_t module_id, sched_pdsch->rbStart = rbStart; sched_pdsch->rbSize = rbSize; const int tda = sched_ctrl->active_bwp ? RC.nrmac[module_id]->preferred_dl_tda[sched_ctrl->active_bwp->bwp_Id][slot] : 1; - const uint8_t num_dmrs_cdm_grps_no_data = 1; + const long f = sched_ctrl->active_bwp ? sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats : 0; ps->nrOfLayers = target_dl_Nl; - if (ps->time_domain_allocation != tda || ps->numDmrsCdmGrpsNoData != num_dmrs_cdm_grps_no_data) + if (ps->time_domain_allocation != tda) nr_set_pdsch_semi_static( - scc, UE_info->CellGroup[UE_id], sched_ctrl->active_bwp, tda, num_dmrs_cdm_grps_no_data, ps); - + scc, UE_info->CellGroup[UE_id], sched_ctrl->active_bwp, NULL, tda, f, ps); sched_pdsch->mcs = target_dl_mcs; sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, ps->mcsTableIdx); @@ -393,7 +398,7 @@ void nr_preprocessor_phytest(module_id_t module_id, /* mark the corresponding RBs as used */ for (int rb = 0; rb < sched_pdsch->rbSize; rb++) - vrb_map[rb + sched_pdsch->rbStart] = 1; + vrb_map[rb + sched_pdsch->rbStart + BWPStart] = 1; if ((frame&127) == 0) LOG_D(MAC,"phytest: %d.%d DL mcs %d, DL rbStart %d, DL rbSize %d\n", frame, slot, sched_pdsch->mcs, rbStart,rbSize); } @@ -449,14 +454,17 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ if (ps->time_domain_allocation != tda || ps->dci_format != dci_format || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) - nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); + nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, NULL,dci_format, tda, num_dmrs_cdm_grps_no_data, ps); uint16_t rbStart = 0; uint16_t rbSize; const int bw = NRRIV2BW(sched_ctrl->active_ubwp ? - sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth : - scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth : + scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + const int BWPStart = NRRIV2PRBOFFSET(sched_ctrl->active_ubwp ? + sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth : + scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); if (target_ul_bw>bw) rbSize = bw; @@ -467,7 +475,7 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[sched_slot * MAX_BWP_SIZE]; const uint16_t symb = ((1 << ps->nrOfSymbols) - 1) << ps->startSymbolIndex; for (int i = rbStart; i < rbStart + rbSize; ++i) { - if ((vrb_map_UL[i] & symb) != 0) { + if ((vrb_map_UL[i+BWPStart] & symb) != 0) { LOG_E(MAC, "%s(): %4d.%2d RB %d is already reserved, cannot schedule UE\n", __func__, @@ -482,9 +490,16 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ sched_ctrl->sched_pusch.frame = sched_frame; uint8_t nr_of_candidates; - find_aggregation_candidates(&sched_ctrl->aggregation_level, - &nr_of_candidates, - sched_ctrl->search_space); + for (int i=0; i<5; i++) { + // for now taking the lowest value among the available aggregation levels + find_aggregation_candidates(&sched_ctrl->aggregation_level, + &nr_of_candidates, + sched_ctrl->search_space, + 1<0) break; + } + AssertFatal(nr_of_candidates>0,"nr_of_candidates is 0\n"); + const int cid = sched_ctrl->coreset->controlResourceSetId; const uint16_t Y = UE_info->Y[UE_id][cid][slot]; const int m = UE_info->num_pdcch_cand[UE_id][cid]; @@ -529,6 +544,6 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ /* mark the corresponding RBs as used */ for (int rb = rbStart; rb < rbStart + rbSize; rb++) - vrb_map_UL[rb] = 1; + vrb_map_UL[rb+BWPStart] = 1; return true; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 1948959d55..7387bfe698 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -30,6 +30,7 @@ */ +#include #include "assertions.h" #include "NR_MAC_gNB/nr_mac_gNB.h" @@ -152,27 +153,33 @@ void set_dl_dmrs_ports(NR_pdsch_semi_static_t *ps) { } } -NR_ControlResourceSet_t *get_coreset(NR_ServingCellConfigCommon_t *scc, - NR_BWP_Downlink_t *bwp, +NR_ControlResourceSet_t *get_coreset(module_id_t module_idP, + NR_ServingCellConfigCommon_t *scc, + void *bwp, NR_SearchSpace_t *ss, NR_SearchSpace__searchSpaceType_PR ss_type) { NR_ControlResourceSetId_t coreset_id = *ss->controlResourceSetId; if (ss_type == NR_SearchSpace__searchSpaceType_PR_common) { // common search space NR_ControlResourceSet_t *coreset; - if (bwp) coreset = bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonControlResourceSet; - else if (scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonControlResourceSet) + if(coreset_id == 0) { + coreset = RC.nrmac[module_idP]->sched_ctrlCommon->coreset; // this is coreset 0 + } else if (bwp) { + coreset = ((NR_BWP_Downlink_t*)bwp)->bwp_Common->pdcch_ConfigCommon->choice.setup->commonControlResourceSet; + } else if (scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonControlResourceSet) { coreset = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonControlResourceSet; - else coreset = NULL; + } else { + coreset = NULL; + } if (coreset) AssertFatal(coreset_id == coreset->controlResourceSetId, "ID of common ss coreset does not correspond to id set in the " "search space\n"); return coreset; } else { - const int n = bwp->bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.count; + const int n = ((NR_BWP_DownlinkDedicated_t*)bwp)->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.count; for (int i = 0; i < n; i++) { NR_ControlResourceSet_t *coreset = - bwp->bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.array[i]; + ((NR_BWP_DownlinkDedicated_t*)bwp)->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.array[i]; if (coreset_id == coreset->controlResourceSetId) { return coreset; } @@ -212,8 +219,8 @@ int allocate_nr_CCEs(gNB_MAC_INST *nr_mac, int coreset_id = coreset->controlResourceSetId; int *cce_list; - if(bwp == NULL || bwp->bwp_Id == 0) { - cce_list = nr_mac->cce_list[0][0]; + if(bwp == NULL) { + cce_list = nr_mac->cce_list[0][coreset_id]; } else { cce_list = nr_mac->cce_list[bwp->bwp_Id][coreset_id]; } @@ -231,6 +238,8 @@ int allocate_nr_CCEs(gNB_MAC_INST *nr_mac, const uint16_t N_cce = N_reg / NR_NB_REG_PER_CCE; const uint16_t M_s_max = nr_of_candidates; + LOG_D(PHY,"allocate_NR_CCes : bwp_id %d, coreset_id %d : N_cce %d, m %d, nr_of_candidates %d, Y %d\n", + (int)(bwp ? bwp->bwp_Id : 0),coreset_id,N_cce,m,nr_of_candidates, Y); //PDCCH candidate index m in CORESET exceeds the maximum number of PDCCH candidates if(m >= nr_of_candidates) return -1; @@ -266,7 +275,7 @@ bool nr_find_nb_rb(uint16_t Qm, return true; /* is the minimum enough? */ - *nb_rb = 1; + *nb_rb = 5; *tbs = nr_compute_tbs(Qm, R, *nb_rb, nb_symb_sch, nb_dmrs_prb, 0, 0, 1) >> 3; if (bytes <= *tbs) return true; @@ -295,6 +304,7 @@ bool nr_find_nb_rb(uint16_t Qm, void nr_set_pdsch_semi_static(const NR_ServingCellConfigCommon_t *scc, const NR_CellGroupConfig_t *secondaryCellGroup, const NR_BWP_Downlink_t *bwp, + const NR_BWP_DownlinkDedicated_t *bwpd0, int tda, const long dci_format, NR_pdsch_semi_static_t *ps) @@ -308,14 +318,19 @@ void nr_set_pdsch_semi_static(const NR_ServingCellConfigCommon_t *scc, const int mapping_type = tdaList->list.array[tda]->mappingType; const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength; SLIV2SL(startSymbolAndLength, &ps->startSymbolIndex, &ps->nrOfSymbols); + NR_BWP_DownlinkDedicated_t *bwpd; + + if (bwp && bwp->bwp_Dedicated) { + bwpd = bwp->bwp_Dedicated; + } else { + bwpd = (NR_BWP_DownlinkDedicated_t*)bwpd0; + } ps->mcsTableIdx = 0; - if (bwp && - bwp->bwp_Dedicated && - bwp->bwp_Dedicated->pdsch_Config && - bwp->bwp_Dedicated->pdsch_Config->choice.setup && - bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table) { - if (*bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table == 0) + if (bwpd->pdsch_Config && + bwpd->pdsch_Config->choice.setup && + bwpd->pdsch_Config->choice.setup->mcs_Table) { + if (*bwpd->pdsch_Config->choice.setup->mcs_Table == 0) ps->mcsTableIdx = 1; else ps->mcsTableIdx = 2; @@ -329,12 +344,14 @@ void nr_set_pdsch_semi_static(const NR_ServingCellConfigCommon_t *scc, ps->dmrsConfigType = bwp!=NULL ? (bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type == NULL ? 0 : 1) : 0; ps->N_PRB_DMRS = ps->numDmrsCdmGrpsNoData * (ps->dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6 : 4); - ps->dl_dmrs_symb_pos = fill_dmrs_mask(bwp ? bwp->bwp_Dedicated->pdsch_Config->choice.setup : NULL, scc->dmrs_TypeA_Position, ps->nrOfSymbols, ps->startSymbolIndex, mapping_type); + ps->dl_dmrs_symb_pos = fill_dmrs_mask(bwpd ? bwpd->pdsch_Config->choice.setup : NULL, scc->dmrs_TypeA_Position, ps->nrOfSymbols, ps->startSymbolIndex, mapping_type); ps->N_DMRS_SLOT = get_num_dmrs(ps->dl_dmrs_symb_pos); + LOG_D(NR_MAC,"bwpd0 %p, bwpd %p : Filling dmrs info, ps->N_PRB_DMRS %d, ps->dl_dmrs_symb_pos %x, ps->N_DMRS_SLOT %d\n",bwpd0,bwpd,ps->N_PRB_DMRS,ps->dl_dmrs_symb_pos,ps->N_DMRS_SLOT); } void nr_set_pusch_semi_static(const NR_ServingCellConfigCommon_t *scc, const NR_BWP_Uplink_t *ubwp, + const NR_BWP_UplinkDedicated_t *ubwpd, long dci_format, int tda, uint8_t num_dmrs_cdm_grps_no_data, @@ -352,7 +369,7 @@ void nr_set_pusch_semi_static(const NR_ServingCellConfigCommon_t *scc, &ps->startSymbolIndex, &ps->nrOfSymbols); - ps->pusch_Config = ubwp?ubwp->bwp_Dedicated->pusch_Config->choice.setup:NULL; + ps->pusch_Config = ubwp?ubwp->bwp_Dedicated->pusch_Config->choice.setup:(ubwpd ? ubwpd->pusch_Config->choice.setup : NULL); if (ps->pusch_Config == NULL || !ps->pusch_Config->transformPrecoder) ps->transform_precoding = !scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder; else @@ -627,6 +644,7 @@ void nr_configure_css_dci_initial(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu, } void config_uldci(const NR_BWP_Uplink_t *ubwp, + const NR_BWP_UplinkDedicated_t *ubwpd, const NR_ServingCellConfigCommon_t *scc, const nfapi_nr_pusch_pdu_t *pusch_pdu, dci_pdu_rel15_t *dci_pdu_rel15, @@ -649,23 +667,25 @@ void config_uldci(const NR_BWP_Uplink_t *ubwp, dci_pdu_rel15->rv = pusch_pdu->pusch_data.rv_index; dci_pdu_rel15->harq_pid = pusch_pdu->pusch_data.harq_process_id; dci_pdu_rel15->tpc = tpc; - if (ubwp) AssertFatal(ubwp->bwp_Dedicated->pusch_Config->choice.setup->resourceAllocation == NR_PUSCH_Config__resourceAllocation_resourceAllocationType1, + const NR_BWP_UplinkDedicated_t *ubwpd2 = (ubwp) ? ubwp->bwp_Dedicated : ubwpd; + + if (ubwpd2) AssertFatal(ubwpd2->pusch_Config->choice.setup->resourceAllocation == NR_PUSCH_Config__resourceAllocation_resourceAllocationType1, "Only frequency resource allocation type 1 is currently supported\n"); switch (dci_format) { case NR_UL_DCI_FORMAT_0_0: dci_pdu_rel15->format_indicator = 0; break; case NR_UL_DCI_FORMAT_0_1: + LOG_D(NR_MAC,"Configuring DCI Format 0_1\n"); dci_pdu_rel15->dai[0].val = 0; //TODO // bwp indicator as per table 7.3.1.1.2-1 in 38.212 dci_pdu_rel15->bwp_indicator.val = n_ubwp < 4 ? bwp_id : bwp_id - 1; // SRS resource indicator - if (ubwp && - ubwp->bwp_Dedicated && - ubwp->bwp_Dedicated->pusch_Config && - ubwp->bwp_Dedicated->pusch_Config->choice.setup && - ubwp->bwp_Dedicated->pusch_Config->choice.setup->txConfig != NULL) { - AssertFatal(*ubwp->bwp_Dedicated->pusch_Config->choice.setup->txConfig == NR_PUSCH_Config__txConfig_codebook, + if (ubwpd2 && + ubwpd2->pusch_Config && + ubwpd2->pusch_Config->choice.setup && + ubwpd2->pusch_Config->choice.setup->txConfig != NULL) { + AssertFatal(*ubwpd2->pusch_Config->choice.setup->txConfig == NR_PUSCH_Config__txConfig_codebook, "Non Codebook configuration non supported\n"); dci_pdu_rel15->srs_resource_indicator.val = 0; // taking resource 0 for SRS } @@ -703,7 +723,8 @@ int nr_get_default_pucch_res(int pucch_ResourceCommon) { return(default_pucch_csset[pucch_ResourceCommon]); } -void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, +void nr_configure_pdcch(gNB_MAC_INST *gNB_mac, + nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, NR_SearchSpace_t *ss, NR_ControlResourceSet_t *coreset, NR_ServingCellConfigCommon_t *scc, @@ -711,9 +732,19 @@ void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config) { int sps; + AssertFatal(*ss->controlResourceSetId == coreset->controlResourceSetId, + "coreset id in SS %ld does not correspond to the one in coreset %ld", + *ss->controlResourceSetId, coreset->controlResourceSetId); + if (bwp) { // This is not for SIB1 - pdcch_pdu->BWPSize = NRRIV2BW(bwp->locationAndBandwidth, MAX_BWP_SIZE); - pdcch_pdu->BWPStart = NRRIV2PRBOFFSET(bwp->locationAndBandwidth, MAX_BWP_SIZE); + if(coreset->controlResourceSetId == 0){ + pdcch_pdu->BWPSize = gNB_mac->cset0_bwp_size; + pdcch_pdu->BWPStart = gNB_mac->cset0_bwp_start; + } + else { + pdcch_pdu->BWPSize = NRRIV2BW(bwp->locationAndBandwidth, MAX_BWP_SIZE); + pdcch_pdu->BWPStart = NRRIV2PRBOFFSET(bwp->locationAndBandwidth, MAX_BWP_SIZE); + } pdcch_pdu->SubcarrierSpacing = bwp->subcarrierSpacing; pdcch_pdu->CyclicPrefix = (bwp->cyclicPrefix==NULL) ? 0 : *bwp->cyclicPrefix; @@ -721,6 +752,7 @@ void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, sps = bwp->cyclicPrefix == NULL ? 14 : 12; } else { + AssertFatal(type0_PDCCH_CSS_config!=NULL,"type0_PDCCH_CSS_config is null,bwp %p\n",bwp); pdcch_pdu->BWPSize = type0_PDCCH_CSS_config->num_rbs; pdcch_pdu->BWPStart = type0_PDCCH_CSS_config->cset_start_rb; pdcch_pdu->SubcarrierSpacing = type0_PDCCH_CSS_config->scs_pdcch; @@ -747,6 +779,7 @@ void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, for (int i=0;i<6;i++) pdcch_pdu->FreqDomainResource[i] = coreset->frequencyDomainResources.buf[i]; + LOG_D(MAC,"Coreset : BWPstart %d, BWPsize %d, SCS %d, freq %x, , duration %d, \n",pdcch_pdu->BWPStart,pdcch_pdu->BWPSize,(int)pdcch_pdu->SubcarrierSpacing,(int)coreset->frequencyDomainResources.buf[0],(int)coreset->duration); //cce-REG-MappingType pdcch_pdu->CceRegMappingType = coreset->cce_REG_MappingType.present == NR_ControlResourceSet__cce_REG_MappingType_PR_interleaved? @@ -785,6 +818,7 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, NR_ServingCellConfigCommon_t *scc, NR_CellGroupConfig_t *CellGroup, NR_BWP_Uplink_t *bwp, + NR_BWP_UplinkDedicated_t *bwpd, uint16_t rnti, uint8_t pucch_resource, uint16_t O_csi, @@ -808,12 +842,12 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, uint16_t O_uci = O_csi + O_ack; - NR_PUSCH_Config_t *pusch_Config = bwp ? bwp->bwp_Dedicated->pusch_Config->choice.setup : NULL; - long *pusch_id = bwp ? pusch_Config->dataScramblingIdentityPUSCH : NULL; + NR_PUSCH_Config_t *pusch_Config = bwp ? bwp->bwp_Dedicated->pusch_Config->choice.setup : bwpd->pusch_Config->choice.setup; + long *pusch_id = pusch_Config ? pusch_Config->dataScramblingIdentityPUSCH : NULL; - if (bwp && pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA != NULL) + if (pusch_Config && pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA != NULL) id0 = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->transformPrecodingDisabled->scramblingID0; - else if (bwp && pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB != NULL) + else if (pusch_Config && pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB != NULL) id0 = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->transformPrecodingDisabled->scramblingID0; else id0 = scc->physCellId; @@ -838,7 +872,7 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, pucch_pdu->sequence_hop_flag = 1; break; default: - AssertFatal(1==0,"Group hopping flag %ld undefined (0,1,2) \n", bwp->bwp_Common->pucch_ConfigCommon->choice.setup->pucch_GroupHopping); + AssertFatal(1==0,"Group hopping flag %ld undefined (0,1,2) \n", pucch_ConfigCommon->pucch_GroupHopping); } if (pucch_ConfigCommon->hoppingId != NULL) @@ -852,34 +886,36 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, pucch_pdu->bwp_start = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth,MAX_BWP_SIZE); pucch_pdu->subcarrier_spacing = genericParameters->subcarrierSpacing; pucch_pdu->cyclic_prefix = (genericParameters->cyclicPrefix==NULL) ? 0 : *genericParameters->cyclicPrefix; - if (r_pucch<0 || bwp){ - // we have either a dedicated BWP or Dedicated PUCCH configuration on InitialBWP - pucch_Config = bwp ? - bwp->bwp_Dedicated->pucch_Config->choice.setup: - CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pucch_Config->choice.setup; + if (r_pucch<0 || bwp ){ + LOG_D(NR_MAC,"pucch_acknak: Filling dedicated configuration for PUCCH\n"); + // we have either a dedicated BWP or Dedicated PUCCH configuration on InitialBWP + AssertFatal(bwp!=NULL || bwpd!=NULL,"We need one dedicated configuration for a BWP (neither additional or initial BWP has a dedicated configuration)\n"); + pucch_Config = bwp ? + bwp->bwp_Dedicated->pucch_Config->choice.setup: + bwpd->pucch_Config->choice.setup; - AssertFatal(pucch_Config->resourceSetToAddModList!=NULL, - "PUCCH resourceSetToAddModList is null\n"); + AssertFatal(pucch_Config->resourceSetToAddModList!=NULL, + "PUCCH resourceSetToAddModList is null\n"); - n_set = pucch_Config->resourceSetToAddModList->list.count; - AssertFatal(n_set>0,"PUCCH resourceSetToAddModList is empty\n"); + n_set = pucch_Config->resourceSetToAddModList->list.count; + AssertFatal(n_set>0,"PUCCH resourceSetToAddModList is empty\n"); - LOG_D(NR_MAC, "UCI n_set= %d\n", n_set); + LOG_D(NR_MAC, "UCI n_set= %d\n", n_set); - N2 = 2; - // procedure to select pucch resource id from resource sets according to - // number of uci bits and pucch resource indicator pucch_resource - // ( see table 9.2.3.2 in 38.213) - for (int i=0; iresourceSetToAddModList->list.array[i]; - n_list = pucchresset->resourceList.list.count; - if (pucchresset->pucch_ResourceSetId == 0 && O_uci<3) { - if (pucch_resource < n_list) - resource_id = pucchresset->resourceList.list.array[pucch_resource]; - else - AssertFatal(1==0,"Couldn't fine pucch resource indicator %d in PUCCH resource set %d for %d UCI bits",pucch_resource,i,O_uci); - } - if (pucchresset->pucch_ResourceSetId == 1 && O_uci>2) { + N2 = 2; + // procedure to select pucch resource id from resource sets according to + // number of uci bits and pucch resource indicator pucch_resource + // ( see table 9.2.3.2 in 38.213) + for (int i=0; iresourceSetToAddModList->list.array[i]; + n_list = pucchresset->resourceList.list.count; + if (pucchresset->pucch_ResourceSetId == 0 && O_uci<3) { + if (pucch_resource < n_list) + resource_id = pucchresset->resourceList.list.array[pucch_resource]; + else + AssertFatal(1==0,"Couldn't fine pucch resource indicator %d in PUCCH resource set %d for %d UCI bits",pucch_resource,i,O_uci); + } + if (pucchresset->pucch_ResourceSetId == 1 && O_uci>2) { #if (NR_RRC_VERSION >= MAKE_VERSION(16, 0, 0)) N3 = pucchresset->maxPayloadSize!= NULL ? *pucchresset->maxPayloadSize : 1706; #else @@ -921,6 +957,7 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, pucch_pdu->nr_of_symbols = pucchres->format.choice.format0->nrofSymbols; pucch_pdu->start_symbol_index = pucchres->format.choice.format0->startingSymbolIndex; pucch_pdu->sr_flag = O_sr; + pucch_pdu->prb_size = 1; break; case NR_PUCCH_Resource__format_PR_format1 : pucch_pdu->format_type = 1; @@ -929,6 +966,7 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, pucch_pdu->start_symbol_index = pucchres->format.choice.format1->startingSymbolIndex; pucch_pdu->time_domain_occ_idx = pucchres->format.choice.format1->timeDomainOCC; pucch_pdu->sr_flag = O_sr; + pucch_pdu->prb_size = 1; break; case NR_PUCCH_Resource__format_PR_format2 : pucch_pdu->format_type = 2; @@ -995,6 +1033,7 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, AssertFatal(res_found==1,"No PUCCH resource found corresponding to id %ld\n",*resource_id); } else { // this is the default PUCCH configuration, PUCCH format 0 or 1 + LOG_D(NR_MAC,"pucch_acknak: Filling default PUCCH configuration from Tables (r_pucch %d, bwp %p)\n",r_pucch,bwp); int rsetindex = *scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->pucch_ResourceCommon; int prboffset = r_pucch/default_pucch_csset[rsetindex]; int prboffsetm8 = (r_pucch-8)/default_pucch_csset[rsetindex]; @@ -1015,6 +1054,7 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, pucch_pdu->start_symbol_index = default_pucch_firstsymb[rsetindex]; if (pucch_pdu->format_type == 1) pucch_pdu->time_domain_occ_idx = 0; // check this!! pucch_pdu->sr_flag = O_sr; + pucch_pdu->prb_size=1; } } @@ -1024,7 +1064,21 @@ void prepare_dci(const NR_CellGroupConfig_t *CellGroup, nr_dci_format_t format, int bwp_id) { - NR_BWP_Downlink_t *bwp=CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]; + AssertFatal(CellGroup!=NULL,"CellGroup shouldn't be null here\n"); + + const NR_BWP_DownlinkDedicated_t *bwpd = NULL; + const NR_PDSCH_Config_t *pdsch_Config = NULL; + const NR_PDCCH_Config_t *pdcch_Config = NULL; + + if (bwp_id>0) { + bwpd=CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Dedicated; + } + else { + bwpd=CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP; + } + pdsch_Config = (bwpd->pdsch_Config) ? bwpd->pdsch_Config->choice.setup : NULL; + pdcch_Config = (bwpd->pdcch_Config) ? bwpd->pdcch_Config->choice.setup : NULL; + switch(format) { case NR_UL_DCI_FORMAT_0_1: @@ -1047,22 +1101,22 @@ void prepare_dci(const NR_CellGroupConfig_t *CellGroup, if (CellGroup->spCellConfig->spCellConfigDedicated->crossCarrierSchedulingConfig != NULL) AssertFatal(1==0,"Cross Carrier Scheduling Config currently not supported\n"); //vrb to prb mapping - if (bwp->bwp_Dedicated->pdsch_Config->choice.setup->vrb_ToPRB_Interleaver==NULL) + if (pdsch_Config->vrb_ToPRB_Interleaver==NULL) dci_pdu_rel15->vrb_to_prb_mapping.val = 0; else dci_pdu_rel15->vrb_to_prb_mapping.val = 1; //bundling size indicator - if (bwp->bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.present == NR_PDSCH_Config__prb_BundlingType_PR_dynamicBundling) + if (pdsch_Config->prb_BundlingType.present == NR_PDSCH_Config__prb_BundlingType_PR_dynamicBundling) AssertFatal(1==0,"Dynamic PRB bundling type currently not supported\n"); //rate matching indicator - uint16_t msb = (bwp->bwp_Dedicated->pdsch_Config->choice.setup->rateMatchPatternGroup1==NULL)?0:1; - uint16_t lsb = (bwp->bwp_Dedicated->pdsch_Config->choice.setup->rateMatchPatternGroup2==NULL)?0:1; + uint16_t msb = (pdsch_Config->rateMatchPatternGroup1==NULL)?0:1; + uint16_t lsb = (pdsch_Config->rateMatchPatternGroup2==NULL)?0:1; dci_pdu_rel15->rate_matching_indicator.val = lsb | (msb<<1); // aperiodic ZP CSI-RS trigger - if (bwp->bwp_Dedicated->pdsch_Config->choice.setup->aperiodic_ZP_CSI_RS_ResourceSetsToAddModList != NULL) + if (pdsch_Config->aperiodic_ZP_CSI_RS_ResourceSetsToAddModList != NULL) AssertFatal(1==0,"Aperiodic ZP CSI-RS currently not supported\n"); // transmission configuration indication - if (bwp->bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.array[bwp_id-1]->tci_PresentInDCI != NULL) + if (pdcch_Config->controlResourceSetToAddModList->list.array[0]->tci_PresentInDCI != NULL) AssertFatal(1==0,"TCI in DCI currently not supported\n"); //srs resource set if (CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->carrierSwitching!=NULL) { @@ -1086,7 +1140,9 @@ void prepare_dci(const NR_CellGroupConfig_t *CellGroup, else dci_pdu_rel15->srs_request.val = 0; // CBGTI and CBGFI - if (CellGroup->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup->codeBlockGroupTransmission != NULL) + if (CellGroup->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig && + CellGroup->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup && + CellGroup->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup->codeBlockGroupTransmission != NULL) AssertFatal(1==0,"CBG transmission currently not supported\n"); break; default : @@ -1106,10 +1162,10 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, uint8_t fsize = 0, pos = 0; uint64_t *dci_pdu = (uint64_t *)pdcch_dci_pdu->Payload; - int dci_size = nr_dci_size(scc->uplinkConfigCommon->initialUplinkBWP, CellGroup, dci_pdu_rel15, dci_format, rnti_type, N_RB, bwp_id); + *dci_pdu=0; + int dci_size = nr_dci_size(scc->downlinkConfigCommon->initialDownlinkBWP,scc->uplinkConfigCommon->initialUplinkBWP, CellGroup, dci_pdu_rel15, dci_format, rnti_type, N_RB, bwp_id); pdcch_dci_pdu->PayloadSizeBits = dci_size; AssertFatal(dci_size <= 64, "DCI sizes above 64 bits not yet supported"); - if (dci_format == NR_DL_DCI_FORMAT_1_1 || dci_format == NR_UL_DCI_FORMAT_0_1) prepare_dci(CellGroup, dci_pdu_rel15, dci_format, bwp_id); @@ -1123,8 +1179,8 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, pos = fsize; *dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val & ((1 << fsize) - 1)) << (dci_size - pos)); LOG_D(NR_MAC, - "frequency-domain assignment %d (%d bits) N_RB_BWP %d=> %d (0x%lx)\n", - dci_pdu_rel15->frequency_domain_assignment.val, + "RA_RNTI, size %d frequency-domain assignment %d (%d bits) N_RB_BWP %d=> %d (0x%lx)\n", + dci_size,dci_pdu_rel15->frequency_domain_assignment.val, fsize, N_RB, dci_size - pos, @@ -1133,7 +1189,7 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, pos += 4; *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment.val & 0xf) << (dci_size - pos)); LOG_D(NR_MAC, - "time-domain assignment %d (3 bits)=> %d (0x%lx)\n", + "time-domain assignment %d (4 bits)=> %d (0x%lx)\n", dci_pdu_rel15->time_domain_assignment.val, dci_size - pos, *dci_pdu); @@ -1148,15 +1204,11 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, // MCS pos += 5; *dci_pdu |= ((uint64_t)dci_pdu_rel15->mcs & 0x1f) << (dci_size - pos); -#ifdef DEBUG_FILL_DCI - LOG_I(NR_MAC, "mcs %d (5 bits)=> %d (0x%lx)\n", dci_pdu_rel15->mcs, dci_size - pos, *dci_pdu); -#endif + LOG_D(NR_MAC, "mcs %d (5 bits)=> %d (0x%lx)\n", dci_pdu_rel15->mcs, dci_size - pos, *dci_pdu); // TB scaling pos += 2; *dci_pdu |= ((uint64_t)dci_pdu_rel15->tb_scaling & 0x3) << (dci_size - pos); -#ifdef DEBUG_FILL_DCI - LOG_I(NR_MAC, "tb_scaling %d (2 bits)=> %d (0x%lx)\n", dci_pdu_rel15->tb_scaling, dci_size - pos, *dci_pdu); -#endif + LOG_D(NR_MAC, "tb_scaling %d (2 bits)=> %d (0x%lx)\n", dci_pdu_rel15->tb_scaling, dci_size - pos, *dci_pdu); break; case NR_RNTI_C: @@ -1164,7 +1216,8 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, pos++; *dci_pdu |= ((uint64_t)1) << (dci_size - pos); LOG_D(NR_MAC, - "Format indicator %d (%d bits) N_RB_BWP %d => %d (0x%lx)\n", + "DCI1_0 (size %d): Format indicator %d (%d bits) N_RB_BWP %d => %d (0x%lx)\n", + dci_size, dci_pdu_rel15->format_indicator, 1, N_RB, @@ -1292,28 +1345,28 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, pos = 1; // Freq domain assignment 0-16 bit fsize = (int)ceil(log2((N_RB * (N_RB + 1)) >> 1)); - LOG_D(PHY, "fsize = %i\n", fsize); + LOG_D(NR_MAC, "fsize = %i\n", fsize); for (int i = 0; i < fsize; i++) *dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val >> (fsize - i - 1)) & 1) << (dci_size - pos++); - LOG_D(PHY, "dci_pdu_rel15->frequency_domain_assignment.val = %i\n", dci_pdu_rel15->frequency_domain_assignment.val); + LOG_D(NR_MAC, "dci_pdu_rel15->frequency_domain_assignment.val = %i\n", dci_pdu_rel15->frequency_domain_assignment.val); // Time domain assignment 4 bit for (int i = 0; i < 4; i++) *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment.val >> (3 - i)) & 1) << (dci_size - pos++); - LOG_D(PHY, "dci_pdu_rel15->time_domain_assignment.val = %i\n", dci_pdu_rel15->time_domain_assignment.val); + LOG_D(NR_MAC, "dci_pdu_rel15->time_domain_assignment.val = %i\n", dci_pdu_rel15->time_domain_assignment.val); // VRB to PRB mapping 1 bit *dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping.val & 1) << (dci_size - pos++); - LOG_D(PHY, "dci_pdu_rel15->vrb_to_prb_mapping.val = %i\n", dci_pdu_rel15->vrb_to_prb_mapping.val); + LOG_D(NR_MAC, "dci_pdu_rel15->vrb_to_prb_mapping.val = %i\n", dci_pdu_rel15->vrb_to_prb_mapping.val); // MCS 5bit //bit over 32, so dci_pdu ++ for (int i = 0; i < 5; i++) *dci_pdu |= (((uint64_t)dci_pdu_rel15->mcs >> (4 - i)) & 1) << (dci_size - pos++); - LOG_D(PHY, "dci_pdu_rel15->mcs = %i\n", dci_pdu_rel15->mcs); + LOG_D(NR_MAC, "dci_pdu_rel15->mcs = %i\n", dci_pdu_rel15->mcs); // Redundancy version 2bit for (int i = 0; i < 2; i++) *dci_pdu |= (((uint64_t)dci_pdu_rel15->rv >> (1 - i)) & 1) << (dci_size - pos++); - LOG_D(PHY, "dci_pdu_rel15->rv = %i\n", dci_pdu_rel15->rv); + LOG_D(NR_MAC, "dci_pdu_rel15->rv = %i\n", dci_pdu_rel15->rv); // System information indicator 1bit *dci_pdu |= ((uint64_t)dci_pdu_rel15->system_info_indicator&1)<<(dci_size-pos++); - LOG_D(PHY, "dci_pdu_rel15->system_info_indicator = %i\n", dci_pdu_rel15->system_info_indicator); + LOG_D(NR_MAC, "dci_pdu_rel15->system_info_indicator = %i\n", dci_pdu_rel15->system_info_indicator); break; case NR_RNTI_TC: @@ -1374,6 +1427,7 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, case NR_UL_DCI_FORMAT_0_0: switch (rnti_type) { case NR_RNTI_C: + LOG_D(NR_MAC,"Filling format 0_0 DCI for CRNTI (size %d bits, format ind %d)\n",dci_size,dci_pdu_rel15->format_indicator); // indicating a UL DCI format 1bit pos=1; *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator & 1) << (dci_size - pos); @@ -1481,6 +1535,7 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, case NR_UL_DCI_FORMAT_0_1: switch (rnti_type) { case NR_RNTI_C: + LOG_D(NR_MAC,"Filling NR_UL_DCI_FORMAT_0_1 size %d format indicator %d\n",dci_size,dci_pdu_rel15->format_indicator); // Indicating a DL DCI format 1bit pos = 1; *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator & 0x1) << (dci_size - pos); @@ -1559,6 +1614,7 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, case NR_DL_DCI_FORMAT_1_1: // Indicating a DL DCI format 1bit + LOG_D(NR_MAC,"Filling Format 1_1 DCI of size %d\n",dci_size); pos = 1; *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator & 0x1) << (dci_size - pos); // Carrier indicator @@ -1895,6 +1951,9 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP, NR_CellGroupConfig_t *CellG NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; memset(sched_ctrl, 0, sizeof(*sched_ctrl)); sched_ctrl->lcid_mask = 0; + if (!get_softmodem_params()->phy_test && !get_softmodem_params()->do_ra && !get_softmodem_params()->sa) { + sched_ctrl->lcid_mask = 1<ta_frame = 0; sched_ctrl->ta_update = 31; sched_ctrl->ta_apply = false; @@ -1915,11 +1974,12 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP, NR_CellGroupConfig_t *CellG const int bwp_id = 1; sched_ctrl->active_bwp = bwpList ? bwpList->list.array[bwp_id - 1] : NULL; const int target_ss = sched_ctrl->active_bwp ? NR_SearchSpace__searchSpaceType_PR_ue_Specific : NR_SearchSpace__searchSpaceType_PR_common; - sched_ctrl->search_space = get_searchspace(scc, sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Dedicated : NULL, target_ss); - if (*sched_ctrl->search_space->controlResourceSetId == 0) - sched_ctrl->coreset = RC.nrmac[mod_idP]->sched_ctrlCommon->coreset; // this is coreset 0 - else - sched_ctrl->coreset = get_coreset(scc, sched_ctrl->active_bwp, sched_ctrl->search_space, target_ss); + sched_ctrl->search_space = get_searchspace(scc, + sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Dedicated : NULL, + target_ss); + sched_ctrl->coreset = get_coreset(mod_idP, scc, + sched_ctrl->active_bwp ? (void*)sched_ctrl->active_bwp->bwp_Dedicated : NULL, + sched_ctrl->search_space, target_ss); const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig ? servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList : NULL; if (ubwpList) AssertFatal(ubwpList->list.count == 1, "uplinkBWP_ToAddModList has %d BWP!\n", @@ -1946,7 +2006,7 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP, NR_CellGroupConfig_t *CellG add_tail_nr_list(&sched_ctrl->available_ul_harq, harq); create_nr_list(&sched_ctrl->feedback_ul_harq, 16); create_nr_list(&sched_ctrl->retrans_ul_harq, 16); - LOG_I(NR_MAC, "[gNB %d] Add NR UE_id %d : rnti %x\n", + LOG_D(NR_MAC, "[gNB %d] Add NR UE_id %d : rnti %x\n", mod_idP, UE_id, rntiP); @@ -2036,8 +2096,8 @@ uint8_t nr_get_tpc(int target, uint8_t cqi, int incr) { // al values passed to this function are x10 int snrx10 = (cqi*5) - 640; if (snrx10 > target + incr) return 0; // decrease 1dB - if (snrx10 < target - incr) return 2; // increase 1dB if (snrx10 < target - (3*incr)) return 3; // increase 3dB + if (snrx10 < target - incr) return 2; // increase 1dB LOG_D(NR_MAC,"tpc : target %d, snrx10 %d\n",target,snrx10); return 1; // no change } @@ -2045,34 +2105,61 @@ uint8_t nr_get_tpc(int target, uint8_t cqi, int incr) { void get_pdsch_to_harq_feedback(int Mod_idP, int UE_id, + int bwp_id, NR_SearchSpace__searchSpaceType_PR ss_type, + int *max_fb_time, uint8_t *pdsch_to_harq_feedback) { - int bwp_id=1; NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info; NR_CellGroupConfig_t *CellGroup = UE_info->CellGroup[UE_id]; - NR_BWP_Downlink_t *bwp=NULL; - NR_BWP_Uplink_t *ubwp=NULL; + NR_BWP_DownlinkDedicated_t *bwpd=NULL; + NR_BWP_UplinkDedicated_t *ubwpd=NULL; - if (CellGroup && CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList) - bwp = CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]; - if (CellGroup && CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList) - ubwp = CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1]; + if (ss_type == NR_SearchSpace__searchSpaceType_PR_ue_Specific) { + AssertFatal(CellGroup!=NULL,"Cellgroup is not defined for UE_id %d\n",UE_id); + AssertFatal(CellGroup->spCellConfig!=NULL,"Cellgroup->spCellConfig is null\n"); + AssertFatal(CellGroup->spCellConfig->spCellConfigDedicated!=NULL,"CellGroup->spCellConfig->spCellConfigDedicated is null\n"); + } + if (bwp_id>0) { + AssertFatal(CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList!=NULL, + "CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList is null\n"); + AssertFatal(CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList!=NULL, + "CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList is null\n"); + AssertFatal(CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count >= bwp_id, + "CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count %d < bwp_id %d\n", + CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count,bwp_id); + AssertFatal(CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count >= bwp_id, + "CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count %d < bwp_id %d\n", + CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count,bwp_id); + bwpd = CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Dedicated; + ubwpd = CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Dedicated; + } + else if (CellGroup) { // this is an initialBWP + AssertFatal((bwpd=CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP)!=NULL, + "CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP is null\n"); + AssertFatal((ubwpd=CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP)!=NULL, + "CellGroup->spCellConfig->spCellConfigDedicated->uplnikConfig->initialUplinkBWP is null\n"); + } NR_SearchSpace_t *ss=NULL; // common search type uses DCI format 1_0 if (ss_type == NR_SearchSpace__searchSpaceType_PR_common) { - for (int i=0; i<8; i++) + for (int i=0; i<8; i++) { pdsch_to_harq_feedback[i] = i+1; + if(pdsch_to_harq_feedback[i]>*max_fb_time) + *max_fb_time = pdsch_to_harq_feedback[i]; + } } else { // searching for a ue specific search space int found=0; - - for (int i=0;ibwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count;i++) { - ss=bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.array[i]; + AssertFatal(bwpd->pdcch_Config!=NULL,"bwpd->pdcch_Config is null\n"); + AssertFatal(bwpd->pdcch_Config->choice.setup->searchSpacesToAddModList!=NULL, + "bwpd->pdcch_Config->choice.setup->searchSpacesToAddModList is null\n"); + for (int i=0;ipdcch_Config->choice.setup->searchSpacesToAddModList->list.count;i++) { + ss=bwpd->pdcch_Config->choice.setup->searchSpacesToAddModList->list.array[i]; AssertFatal(ss->controlResourceSetId != NULL,"ss->controlResourceSetId is null\n"); AssertFatal(ss->searchSpaceType != NULL,"ss->searchSpaceType is null\n"); if (ss->searchSpaceType->present == ss_type) { @@ -2084,13 +2171,20 @@ void get_pdsch_to_harq_feedback(int Mod_idP, if (ss->searchSpaceType->choice.ue_Specific->dci_Formats == NR_SearchSpace__searchSpaceType__ue_Specific__dci_Formats_formats0_0_And_1_0) { - for (int i=0; i<8; i++) + for (int i=0; i<8; i++) { pdsch_to_harq_feedback[i] = i+1; + if(pdsch_to_harq_feedback[i]>*max_fb_time) + *max_fb_time = pdsch_to_harq_feedback[i]; + } } else { - if(ubwp->bwp_Dedicated->pucch_Config->choice.setup->dl_DataToUL_ACK != NULL) { - for (int i=0; i<8; i++) - pdsch_to_harq_feedback[i] = *ubwp->bwp_Dedicated->pucch_Config->choice.setup->dl_DataToUL_ACK->list.array[i]; + AssertFatal(ubwpd!=NULL,"ubwpd shouldn't be null here\n"); + if(ubwpd->pucch_Config->choice.setup->dl_DataToUL_ACK != NULL) { + for (int i=0; i<8; i++) { + pdsch_to_harq_feedback[i] = *ubwpd->pucch_Config->choice.setup->dl_DataToUL_ACK->list.array[i]; + if(pdsch_to_harq_feedback[i]>*max_fb_time) + *max_fb_time = pdsch_to_harq_feedback[i]; + } } else AssertFatal(0==1,"There is no allocated dl_DataToUL_ACK for pdsch to harq feedback\n"); @@ -2174,20 +2268,20 @@ void nr_csirs_scheduling(int Mod_idP, csirs_pdu_rel15->row = 1; csirs_pdu_rel15->freq_domain = ((resourceMapping.frequencyDomainAllocation.choice.row1.buf[0])>>4)&0x0f; for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++) - vrb_map[rb] |= (1 << csirs_pdu_rel15->symb_l0); + vrb_map[rb+csirs_pdu_rel15->bwp_start] |= (1 << csirs_pdu_rel15->symb_l0); break; case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row2: csirs_pdu_rel15->row = 2; csirs_pdu_rel15->freq_domain = (((resourceMapping.frequencyDomainAllocation.choice.row2.buf[1]>>4)&0x0f) | ((resourceMapping.frequencyDomainAllocation.choice.row2.buf[0]<<8)&0xff0)); for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++) - vrb_map[rb] |= (1 << csirs_pdu_rel15->symb_l0); + vrb_map[rb+csirs_pdu_rel15->bwp_start] |= (1 << csirs_pdu_rel15->symb_l0); break; case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row4: csirs_pdu_rel15->row = 4; csirs_pdu_rel15->freq_domain = ((resourceMapping.frequencyDomainAllocation.choice.row4.buf[0])>>5)&0x07; for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++) - vrb_map[rb] |= (1 << csirs_pdu_rel15->symb_l0); + vrb_map[rb+csirs_pdu_rel15->bwp_start] |= (1 << csirs_pdu_rel15->symb_l0); break; case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_other: csirs_pdu_rel15->freq_domain = ((resourceMapping.frequencyDomainAllocation.choice.other.buf[0])>>2)&0x3f; @@ -2198,18 +2292,18 @@ void nr_csirs_scheduling(int Mod_idP, case NR_CSI_RS_ResourceMapping__nrofPorts_p2: csirs_pdu_rel15->row = 3; for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++) - vrb_map[rb] |= (1 << csirs_pdu_rel15->symb_l0); + vrb_map[rb+csirs_pdu_rel15->bwp_start] |= (1 << csirs_pdu_rel15->symb_l0); break; case NR_CSI_RS_ResourceMapping__nrofPorts_p4: csirs_pdu_rel15->row = 5; for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++) - vrb_map[rb] |= ((1 << csirs_pdu_rel15->symb_l0) | (2 << csirs_pdu_rel15->symb_l0)); + vrb_map[rb+csirs_pdu_rel15->bwp_start] |= ((1 << csirs_pdu_rel15->symb_l0) | (2 << csirs_pdu_rel15->symb_l0)); break; case NR_CSI_RS_ResourceMapping__nrofPorts_p8: if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) { csirs_pdu_rel15->row = 8; for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++) - vrb_map[rb] |= ((1 << csirs_pdu_rel15->symb_l0) | (2 << csirs_pdu_rel15->symb_l0)); + vrb_map[rb+csirs_pdu_rel15->bwp_start] |= ((1 << csirs_pdu_rel15->symb_l0) | (2 << csirs_pdu_rel15->symb_l0)); } else{ int num_k = 0; @@ -2218,12 +2312,12 @@ void nr_csirs_scheduling(int Mod_idP, if(num_k==4) { csirs_pdu_rel15->row = 6; for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++) - vrb_map[rb] |= (1 << csirs_pdu_rel15->symb_l0); + vrb_map[rb+csirs_pdu_rel15->bwp_start] |= (1 << csirs_pdu_rel15->symb_l0); } else { csirs_pdu_rel15->row = 7; for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++) - vrb_map[rb] |= ((1 << csirs_pdu_rel15->symb_l0) | (2 << csirs_pdu_rel15->symb_l0)); + vrb_map[rb+csirs_pdu_rel15->bwp_start] |= ((1 << csirs_pdu_rel15->symb_l0) | (2 << csirs_pdu_rel15->symb_l0)); } } break; @@ -2231,12 +2325,12 @@ void nr_csirs_scheduling(int Mod_idP, if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) { csirs_pdu_rel15->row = 10; for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++) - vrb_map[rb] |= ((1 << csirs_pdu_rel15->symb_l0) | (2 << csirs_pdu_rel15->symb_l0)); + vrb_map[rb+csirs_pdu_rel15->bwp_start] |= ((1 << csirs_pdu_rel15->symb_l0) | (2 << csirs_pdu_rel15->symb_l0)); } else { csirs_pdu_rel15->row = 9; for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++) - vrb_map[rb] |= (1 << csirs_pdu_rel15->symb_l0); + vrb_map[rb+csirs_pdu_rel15->bwp_start] |= (1 << csirs_pdu_rel15->symb_l0); } break; case NR_CSI_RS_ResourceMapping__nrofPorts_p16: @@ -2245,24 +2339,24 @@ void nr_csirs_scheduling(int Mod_idP, else csirs_pdu_rel15->row = 11; for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++) - vrb_map[rb] |= ((1 << csirs_pdu_rel15->symb_l0) | (2 << csirs_pdu_rel15->symb_l0)); + vrb_map[rb+csirs_pdu_rel15->bwp_start] |= ((1 << csirs_pdu_rel15->symb_l0) | (2 << csirs_pdu_rel15->symb_l0)); break; case NR_CSI_RS_ResourceMapping__nrofPorts_p24: if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) { csirs_pdu_rel15->row = 14; for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++) - vrb_map[rb] |= ((3 << csirs_pdu_rel15->symb_l0) | (3 << csirs_pdu_rel15->symb_l1)); + vrb_map[rb+csirs_pdu_rel15->bwp_start] |= ((3 << csirs_pdu_rel15->symb_l0) | (3 << csirs_pdu_rel15->symb_l1)); } else{ if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm8_FD2_TD4) { csirs_pdu_rel15->row = 15; for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++) - vrb_map[rb] |= (7 << csirs_pdu_rel15->symb_l0); + vrb_map[rb+csirs_pdu_rel15->bwp_start] |= (7 << csirs_pdu_rel15->symb_l0); } else { csirs_pdu_rel15->row = 13; for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++) - vrb_map[rb] |= ((3 << csirs_pdu_rel15->symb_l0) | (3 << csirs_pdu_rel15->symb_l1)); + vrb_map[rb+csirs_pdu_rel15->bwp_start] |= ((3 << csirs_pdu_rel15->symb_l0) | (3 << csirs_pdu_rel15->symb_l1)); } } break; @@ -2270,18 +2364,18 @@ void nr_csirs_scheduling(int Mod_idP, if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) { csirs_pdu_rel15->row = 17; for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++) - vrb_map[rb] |= ((3 << csirs_pdu_rel15->symb_l0) | (3 << csirs_pdu_rel15->symb_l1)); + vrb_map[rb+csirs_pdu_rel15->bwp_start] |= ((3 << csirs_pdu_rel15->symb_l0) | (3 << csirs_pdu_rel15->symb_l1)); } else{ if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm8_FD2_TD4) { csirs_pdu_rel15->row = 18; for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++) - vrb_map[rb] |= (7 << csirs_pdu_rel15->symb_l0); + vrb_map[rb+csirs_pdu_rel15->bwp_start] |= (7 << csirs_pdu_rel15->symb_l0); } else { csirs_pdu_rel15->row = 16; for (int rb = csirs_pdu_rel15->start_rb; rb < (csirs_pdu_rel15->start_rb + csirs_pdu_rel15->nr_of_rbs); rb++) - vrb_map[rb] |= ((3 << csirs_pdu_rel15->symb_l0) | (3 << csirs_pdu_rel15->symb_l1)); + vrb_map[rb+csirs_pdu_rel15->bwp_start] |= ((3 << csirs_pdu_rel15->symb_l0) | (3 << csirs_pdu_rel15->symb_l1)); } } break; @@ -2304,12 +2398,19 @@ bool find_free_CCE(module_id_t module_id, int UE_id){ NR_UE_sched_ctrl_t *sched_ctrl = &RC.nrmac[module_id]->UE_info.UE_sched_ctrl[UE_id]; uint8_t nr_of_candidates; - find_aggregation_candidates(&sched_ctrl->aggregation_level, - &nr_of_candidates, - sched_ctrl->search_space); + for (int i=0; i<5; i++) { + // for now taking the lowest value among the available aggregation levels + find_aggregation_candidates(&sched_ctrl->aggregation_level, + &nr_of_candidates, + sched_ctrl->search_space, + 1<0) break; + } + AssertFatal(nr_of_candidates>0,"nr_of_candidates is 0\n"); const int cid = sched_ctrl->coreset->controlResourceSetId; const uint16_t Y = RC.nrmac[module_id]->UE_info.Y[UE_id][cid][slot]; const int m = RC.nrmac[module_id]->UE_info.num_pdcch_cand[UE_id][cid]; + if (UE_id >= 0) LOG_D(NR_MAC,"calling allocate_nr_CCEs with L %d, nr_of_candidates %d, Y %x\n",sched_ctrl->aggregation_level,nr_of_candidates,Y); sched_ctrl->cce_index = allocate_nr_CCEs(RC.nrmac[module_id], sched_ctrl->active_bwp, sched_ctrl->coreset, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 6fcc3fe5c1..6a4ccc0d65 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -60,8 +60,9 @@ void nr_fill_nfapi_pucch(module_id_t mod_id, memset(pucch_pdu, 0, sizeof(nfapi_nr_pucch_pdu_t)); future_ul_tti_req->n_pdus += 1; - LOG_D(MAC, - "%4d.%2d Scheduling pucch reception in %4d.%2d: bits SR %d, ACK %d, CSI %d on res %d\n", + LOG_D(NR_MAC, + "%s %4d.%2d Scheduling pucch reception in %4d.%2d: bits SR %d, DAI %d, CSI %d on res %d\n", + pucch->dai_c>0 ? "pucch_acknak" : "", frame, slot, pucch->frame, @@ -72,10 +73,17 @@ void nr_fill_nfapi_pucch(module_id_t mod_id, pucch->resource_indicator); NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels->ServingCellConfigCommon; + NR_CellGroupConfig_t *cg=UE_info->CellGroup[UE_id]; + + NR_BWP_UplinkDedicated_t *ubwpd; + ubwpd = cg ? cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP:NULL; + + LOG_D(NR_MAC,"pucch_acknak: %d.%d Calling nr_configure_pucch (ubwpd %p,r_pucch %d) pucch in %d.%d\n",frame,slot,ubwpd,pucch->r_pucch,pucch->frame,pucch->ul_slot); nr_configure_pucch(pucch_pdu, scc, UE_info->CellGroup[UE_id], UE_info->UE_sched_ctrl[UE_id].active_ubwp, + ubwpd, UE_info->rnti[UE_id], pucch->resource_indicator, pucch->csi_bits, @@ -284,10 +292,9 @@ uint8_t compute_ri_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, } return max_ri; } - else { + else AssertFatal(1==0,"Other configurations not yet implemented\n"); - return 0; - } + return -1; } void compute_li_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, @@ -382,13 +389,11 @@ void compute_csi_bitlen(NR_CSI_MeasConfig_t *csi_MeasConfig, NR_UE_info_t *UE_in // setting the CSI or SSB index list if (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP == csi_report->reportQuantity_type) { - AssertFatal(csi_MeasConfig->csi_SSB_ResourceSetToAddModList != NULL, - "Wrong settings! Report quantity is SSB-RSRP but csi_MeasConfig->csi_SSB_ResourceSetToAddModList is NULL\n"); for (int csi_idx = 0; csi_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_idx++) { if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_idx]->csi_SSB_ResourceSetId == *(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])){ //We can configure only one SSB resource set from spec 38.331 IE CSI-ResourceConfig - nb_resources = csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_idx]->csi_SSB_ResourceList.list.count; + nb_resources= csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_idx]->csi_SSB_ResourceList.list.count; csi_report->SSB_Index_list = csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_idx]->csi_SSB_ResourceList.list.array; csi_report->CSI_Index_list = NULL; break; @@ -489,7 +494,7 @@ void nr_csi_meas_reporting(int Mod_idP, // preparation is done in first slot of tdd period if (frame % (period / n_slots_frame) != offset / n_slots_frame) continue; - LOG_D(MAC, "CSI reporting in frame %d slot %d\n", frame, sched_slot); + LOG_D(NR_MAC, "CSI reporting in frame %d slot %d\n", frame, sched_slot); const NR_PUCCH_CSI_Resource_t *pucchcsires = csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.array[0]; const NR_PUCCH_ResourceSet_t *pucchresset = pucch_Config->resourceSetToAddModList->list.array[1]; // set with formats >1 @@ -516,6 +521,11 @@ void nr_csi_meas_reporting(int Mod_idP, curr_pucch->csi_bits += nr_get_csi_bitlen(Mod_idP,UE_id,csi_report_id); + NR_BWP_t *genericParameters = sched_ctrl->active_ubwp ? + &sched_ctrl->active_ubwp->bwp_Common->genericParameters: + &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; + int bwp_start = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth,MAX_BWP_SIZE); + // going through the list of PUCCH resources to find the one indexed by resource_id uint16_t *vrb_map_UL = &RC.nrmac[Mod_idP]->common_channels[0].vrb_map_UL[sched_slot * MAX_BWP_SIZE]; const int m = pucch_Config->resourceToAddModList->list.count; @@ -546,7 +556,7 @@ void nr_csi_meas_reporting(int Mod_idP, } // verify resources are free for (int i = start; i < start + len; ++i) { - vrb_map_UL[i] |= mask; + vrb_map_UL[i+bwp_start] |= mask; } } } @@ -572,7 +582,7 @@ static void handle_dl_harq(module_id_t mod_id, harq->ndi ^= 1; NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id]; stats->dlsch_errors++; - LOG_D(MAC, "retransmission error for UE %d (total %d)\n", UE_id, stats->dlsch_errors); + LOG_D(NR_MAC, "retransmission error for UE %d (total %d)\n", UE_id, stats->dlsch_errors); } else { add_tail_nr_list(&UE_info->UE_sched_ctrl[UE_id].retrans_dl_harq, harq_pid); harq->round++; @@ -598,7 +608,7 @@ int checkTargetSSBInFirst64TCIStates_pdschConfig(int ssb_index_t, int Mod_idP, i else if(tci->qcl_Type2 != NULL && tci->qcl_Type2->referenceSignal.present == NR_QCL_Info__referenceSignal_PR_ssb) { if(tci->qcl_Type2->referenceSignal.choice.ssb == ssb_index_t) return tci->tci_StateId; // returned TCI state ID - } else LOG_I(MAC,"SSB index is not found in first 64 TCI states of TCI_statestoAddModList[%d]", i); + } else LOG_I(NR_MAC,"SSB index is not found in first 64 TCI states of TCI_statestoAddModList[%d]", i); } } @@ -722,7 +732,7 @@ void tci_handling(module_id_t Mod_idP, int UE_id, frame_t frame, slot_t slot) { stats->cumul_rsrp += strongest_ssb_rsrp; stats->num_rsrp_meas++; ssb_rsrp[idx * nb_of_csi_ssb_report] = strongest_ssb_rsrp; - LOG_D(MAC,"ssb_rsrp = %d\n",strongest_ssb_rsrp); + LOG_D(NR_MAC,"ssb_rsrp = %d\n",strongest_ssb_rsrp); //if current ssb rsrp is greater than better rsrp if(ssb_rsrp[idx * nb_of_csi_ssb_report] > better_rsrp_reported) { @@ -745,7 +755,7 @@ void tci_handling(module_id_t Mod_idP, int UE_id, frame_t frame, slot_t slot) { if(ssb_index[target_ssb_beam_index] != ssb_index[curr_ssb_beam_index] && ssb_rsrp[target_ssb_beam_index] > ssb_rsrp[curr_ssb_beam_index]) { if( ssb_rsrp[target_ssb_beam_index] - ssb_rsrp[curr_ssb_beam_index] > L1_RSRP_HYSTERIS) { is_triggering_ssb_beam_switch = 1; - LOG_D(MAC, "Triggering ssb beam switching using tci\n"); + LOG_D(NR_MAC, "Triggering ssb beam switching using tci\n"); } } @@ -1033,7 +1043,7 @@ static NR_UE_harq_t *find_harq(module_id_t mod_id, frame_t frame, sub_frame_t sl /* old feedbacks we missed: mark for retransmission */ while (harq->feedback_frame != frame || (harq->feedback_frame == frame && harq->feedback_slot < slot)) { - LOG_W(MAC, + LOG_W(NR_MAC, "expected HARQ pid %d feedback at %d.%d, but is at %d.%d instead (HARQ feedback is in the past)\n", pid, harq->feedback_frame, @@ -1049,7 +1059,7 @@ static NR_UE_harq_t *find_harq(module_id_t mod_id, frame_t frame, sub_frame_t sl } /* feedbacks that we wait for in the future: don't do anything */ if (harq->feedback_slot > slot) { - LOG_W(MAC, + LOG_W(NR_MAC, "expected HARQ pid %d feedback at %d.%d, but is at %d.%d instead (HARQ feedback is in the future)\n", pid, harq->feedback_frame, @@ -1068,7 +1078,7 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, { int UE_id = find_nr_UE_id(mod_id, uci_01->rnti); if (UE_id < 0) { - LOG_E(MAC, "%s(): unknown RNTI %04x in PUCCH UCI\n", __func__, uci_01->rnti); + LOG_E(NR_MAC, "%s(): unknown RNTI %04x in PUCCH UCI\n", __func__, uci_01->rnti); return; } NR_UE_info_t *UE_info = &RC.nrmac[mod_id]->UE_info; @@ -1086,6 +1096,7 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, const int8_t pid = sched_ctrl->feedback_dl_harq.head; remove_front_nr_list(&sched_ctrl->feedback_dl_harq); handle_dl_harq(mod_id, UE_id, pid, harq_value == 1 && harq_confidence == 0); + if (harq_confidence == 1) UE_info->mac_stats[UE_id].pucch0_DTX++; } } @@ -1093,13 +1104,14 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, if (uci_01->pduBitmap & 0x1 && uci_01->sr->sr_indication && uci_01->sr->sr_confidence_level == 0 && uci_01->ul_cqi >= 148) { // SR detected with SNR >= 10dB sched_ctrl->SR |= true; - LOG_D(MAC, "SR UE %04x ul_cqi %d\n", uci_01->rnti, uci_01->ul_cqi); + LOG_D(NR_MAC, "SR UE %04x ul_cqi %d\n", uci_01->rnti, uci_01->ul_cqi); } // tpc (power control) only if we received AckNack or positive SR. For a // negative SR, the UE won't have sent anything, and the SNR is not valid if (((uci_01->pduBitmap >> 1) & 0x1) || sched_ctrl->SR) { - sched_ctrl->tpc1 = nr_get_tpc(RC.nrmac[mod_id]->pucch_target_snrx10, uci_01->ul_cqi, 30); + if ((uci_01->harq) && (uci_01->harq->harq_confidence_level==0)) sched_ctrl->tpc1 = nr_get_tpc(RC.nrmac[mod_id]->pucch_target_snrx10, uci_01->ul_cqi, 30); + else sched_ctrl->tpc1 = 3; sched_ctrl->pucch_snrx10 = uci_01->ul_cqi * 5 - 640; } } @@ -1111,7 +1123,7 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, { int UE_id = find_nr_UE_id(mod_id, uci_234->rnti); if (UE_id < 0) { - LOG_E(MAC, "%s(): unknown RNTI %04x in PUCCH UCI\n", __func__, uci_234->rnti); + LOG_E(NR_MAC, "%s(): unknown RNTI %04x in PUCCH UCI\n", __func__, uci_234->rnti); return; } AssertFatal(RC.nrmac[mod_id]->UE_info.CellGroup[UE_id],"Cellgroup is null for UE %d/%x\n",UE_id,uci_234->rnti); @@ -1162,15 +1174,16 @@ int nr_acknack_scheduling(int mod_id, int UE_id, frame_t frame, sub_frame_t slot, - int r_pucch) -{ + int r_pucch, + int is_common) { + const NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels->ServingCellConfigCommon; const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; const NR_TDD_UL_DL_Pattern_t *tdd = &scc->tdd_UL_DL_ConfigurationCommon->pattern1; - const int nr_ulmix_slots = tdd->nrofUplinkSlots + (tdd->nrofUplinkSymbols != 0); const int nr_mix_slots = tdd->nrofDownlinkSymbols != 0 || tdd->nrofUplinkSymbols != 0; const int nr_slots_period = tdd->nrofDownlinkSlots + tdd->nrofUplinkSlots + nr_mix_slots; const int first_ul_slot_tdd = tdd->nrofDownlinkSlots + nr_slots_period * (slot / nr_slots_period); + const int first_ul_slot_period = first_ul_slot_tdd%nr_slots_period; const int CC_id = 0; NR_sched_pucch_t *csi_pucch; @@ -1188,6 +1201,7 @@ int nr_acknack_scheduling(int mod_id, * * each UE has dedicated PUCCH Format 0 resources, and we use index 0! */ NR_UE_sched_ctrl_t *sched_ctrl = &RC.nrmac[mod_id]->UE_info.UE_sched_ctrl[UE_id]; NR_sched_pucch_t *pucch = &sched_ctrl->sched_pucch[0]; + LOG_D(NR_MAC,"pucch_acknak %d.%d Trying to allocate pucch, current DAI %d\n",frame,slot,pucch->dai_c); pucch->r_pucch=r_pucch; AssertFatal(pucch->csi_bits == 0, "%s(): csi_bits %d in sched_pucch[0]\n", @@ -1199,10 +1213,14 @@ int nr_acknack_scheduling(int mod_id, * the same slot again */ const int f = pucch->frame; const int s = pucch->ul_slot; + LOG_D(NR_MAC,"pucch_acknak : %d.%d DAI = 2 pucch currently in %d.%d, advancing by 1 slot\n",frame,slot,f,s); nr_fill_nfapi_pucch(mod_id, frame, slot, pucch, UE_id); memset(pucch, 0, sizeof(*pucch)); pucch->frame = s == n_slots_frame - 1 ? (f + 1) % 1024 : f; - pucch->ul_slot = (s + 1) % n_slots_frame; + if(((s + 1)%nr_slots_period) == 0) + pucch->ul_slot = (s + 1 + first_ul_slot_period) % n_slots_frame; + else + pucch->ul_slot = (s + 1) % n_slots_frame; // we assume that only two indices over the array sched_pucch exist csi_pucch = &sched_ctrl->sched_pucch[1]; // skip the CSI PUCCH if it is present and if in the next frame/slot @@ -1214,30 +1232,40 @@ int nr_acknack_scheduling(int mod_id, && !csi_pucch->simultaneous_harqcsi) { nr_fill_nfapi_pucch(mod_id, frame, slot, csi_pucch, UE_id); memset(csi_pucch, 0, sizeof(*csi_pucch)); - pucch->frame = s >= n_slots_frame - 2 ? (f + 1) % 1024 : f; - pucch->ul_slot = (s + 2) % n_slots_frame; + pucch->frame = s == n_slots_frame - 1 ? (f + 1) % 1024 : f; + if(((s + 1)%nr_slots_period) == 0) + pucch->ul_slot = (s + 1 + first_ul_slot_period) % n_slots_frame; + else + pucch->ul_slot = (s + 1) % n_slots_frame; } } - LOG_D(MAC,"1. DL slot %d, UL_ACK %d\n",slot,pucch->ul_slot); - /* if the UE's next PUCCH occasion is after the possible UL slots (within the - * same frame) or wrapped around to the next frame, then we assume there is - * no possible PUCCH allocation anymore */ - if ((pucch->frame == frame - && (pucch->ul_slot >= first_ul_slot_tdd + nr_ulmix_slots)) - || (pucch->frame == frame + 1)) - return -1; + LOG_D(NR_MAC,"pucch_acknak 1. DL %d.%d, UL_ACK %d.%d, DAI_C %d\n",frame,slot,pucch->frame,pucch->ul_slot,pucch->dai_c); // this is hardcoded for now as ue specific only if we are not on the initialBWP (to be fixed to allow ue_Specific also on initialBWP - NR_SearchSpace__searchSpaceType_PR ss_type = sched_ctrl->active_bwp ? NR_SearchSpace__searchSpaceType_PR_ue_Specific: NR_SearchSpace__searchSpaceType_PR_common; - uint8_t pdsch_to_harq_feedback[8]; - get_pdsch_to_harq_feedback(mod_id, UE_id, ss_type, pdsch_to_harq_feedback); + NR_CellGroupConfig_t *cg = RC.nrmac[mod_id]->UE_info.CellGroup[UE_id]; + NR_BWP_UplinkDedicated_t *ubwpd=NULL; + if (cg && + cg->spCellConfig && + cg->spCellConfig->spCellConfigDedicated && + cg->spCellConfig->spCellConfigDedicated->uplinkConfig && + cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) + ubwpd = cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; + + NR_SearchSpace__searchSpaceType_PR ss_type = (is_common==0 && (sched_ctrl->active_bwp || ubwpd)) ? NR_SearchSpace__searchSpaceType_PR_ue_Specific: NR_SearchSpace__searchSpaceType_PR_common; + uint8_t pdsch_to_harq_feedback[8]; + int bwp_Id = 0; + if (sched_ctrl->active_ubwp) bwp_Id = sched_ctrl->active_ubwp->bwp_Id; + + int max_fb_time = 0; + get_pdsch_to_harq_feedback(mod_id, UE_id, bwp_Id, ss_type, &max_fb_time, pdsch_to_harq_feedback); + int max_absslot = frame*n_slots_frame + slot + max_fb_time; + + LOG_D(NR_MAC,"pucch_acknak 1b. DL %d.%d, UL_ACK %d.%d, DAI_C %d\n",frame,slot,pucch->frame,pucch->ul_slot,pucch->dai_c); /* there is a HARQ. Check whether we can use it for this ACKNACK */ if (pucch->dai_c > 0) { /* this UE already has a PUCCH occasion */ - DevAssert(pucch->frame == frame); - // Find the right timing_indicator value. int i = 0; while (i < 8) { @@ -1250,50 +1278,63 @@ int nr_acknack_scheduling(int mod_id, const int f = pucch->frame; const int s = pucch->ul_slot; const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; + LOG_D(NR_MAC,"pucch_acknak : %d.%d DAI > 0, cannot reach timing for pucch in %d.%d, advancing slot by 1 and trying again\n",frame,slot,f,s); nr_fill_nfapi_pucch(mod_id, frame, slot, pucch, UE_id); memset(pucch, 0, sizeof(*pucch)); pucch->frame = s == n_slots_frame - 1 ? (f + 1) % 1024 : f; - pucch->ul_slot = (s + 1) % n_slots_frame; - return nr_acknack_scheduling(mod_id, UE_id, frame, slot, pucch->r_pucch); + if(((s + 1)%nr_slots_period) == 0) + pucch->ul_slot = (s + 1 + first_ul_slot_period) % n_slots_frame; + else + pucch->ul_slot = (s + 1) % n_slots_frame; + return nr_acknack_scheduling(mod_id, UE_id, frame, slot, r_pucch,is_common); } pucch->timing_indicator = i; pucch->dai_c++; // retain old resource indicator, and we are good + LOG_D(NR_MAC,"pucch_acknak : %d.%d. DAI > 0, pucch allocated for %d.%d (index %d)\n",frame,slot,pucch->frame,pucch->ul_slot,pucch->timing_indicator); return 0; } + LOG_D(NR_MAC,"pucch_acknak : %d.%d DAI = 0, looking for new pucch occasion\n",frame,slot); /* we need to find a new PUCCH occasion */ - /* if time information is outdated (e.g., last PUCCH occasion in last frame), - * set to first possible UL occasion in this frame. Note that if such UE is - * scheduled a lot and used all AckNacks, pucch->frame might have been - * wrapped around to next frame */ - if (frame != pucch->frame || pucch->ul_slot < first_ul_slot_tdd) { + /*Inizialization of timing information*/ + if (pucch->frame == 0 && pucch->ul_slot == 0) { AssertFatal(pucch->sr_flag + pucch->dai_c == 0, "expected no SR/AckNack for UE %d in %4d.%2d, but has %d/%d for %4d.%2d\n", UE_id, frame, slot, pucch->sr_flag, pucch->dai_c, pucch->frame, pucch->ul_slot); - AssertFatal(frame + 1 != pucch->frame, - "frame wrap around not handled in %s() yet\n", - __func__); pucch->frame = frame; pucch->ul_slot = first_ul_slot_tdd; } - // advance ul_slot if it is not reachable by UE - pucch->ul_slot = max(pucch->ul_slot, slot + pdsch_to_harq_feedback[0]); - // Find the right timing_indicator value. - int i = 0; - while (i < 8) { - LOG_D(MAC,"pdsch_to_harq_feedback[%d] = %d (pucch->ul_slot %d - slot %d)\n", - i,pdsch_to_harq_feedback[i],pucch->ul_slot,slot); - if (pdsch_to_harq_feedback[i] == pucch->ul_slot - slot) + int ind_found = -1; + // while we are within the feedback limits and it has not been + while ((pucch->frame*n_slots_frame + pucch->ul_slot) <= max_absslot) { + int i = 0; + while (i < 8) { + LOG_D(NR_MAC,"pdsch_to_harq_feedback[%d] = %d (pucch->ul_slot %d - slot %d)\n", + i,pdsch_to_harq_feedback[i],pucch->ul_slot,slot); + if (pdsch_to_harq_feedback[i] == pucch->ul_slot - slot) { + ind_found = i; + break; + } + ++i; + } + if (ind_found!=-1) break; - ++i; + // advance to the next ul slot + const int f = pucch->frame; + const int s = pucch->ul_slot; + pucch->frame = s == n_slots_frame - 1 ? (f + 1) % 1024 : f; + if(((s + 1)%nr_slots_period) == 0) + pucch->ul_slot = (s + 1 + first_ul_slot_period) % n_slots_frame; + else + pucch->ul_slot = (s + 1) % n_slots_frame; } - if (i >= 8) { - LOG_W(MAC, + if (ind_found==-1) { + LOG_W(NR_MAC, "%4d.%2d could not find pdsch_to_harq_feedback for UE %d: earliest " "ack slot %d\n", frame, @@ -1305,9 +1346,10 @@ int nr_acknack_scheduling(int mod_id, // is there already CSI in this slot? csi_pucch = &sched_ctrl->sched_pucch[1]; - if (csi_pucch->csi_bits > 0 - && csi_pucch->frame == pucch->frame - && csi_pucch->ul_slot == pucch->ul_slot) { + if (csi_pucch && + csi_pucch->csi_bits > 0 && + csi_pucch->frame == pucch->frame && + csi_pucch->ul_slot == pucch->ul_slot) { // skip the CSI PUCCH if it is present and if in the next frame/slot // and if we don't multiplex // FIXME currently we support at most 11 bits in pucch2 so skip also in that case @@ -1321,24 +1363,27 @@ int nr_acknack_scheduling(int mod_id, const int s = pucch->ul_slot; memset(pucch, 0, sizeof(*pucch)); pucch->frame = s == n_slots_frame - 1 ? (f + 1) % 1024 : f; - pucch->ul_slot = (s + 1) % n_slots_frame; - return nr_acknack_scheduling(mod_id, UE_id, frame, slot, -1); + if(((s + 1)%nr_slots_period) == 0) + pucch->ul_slot = (s + 1 + first_ul_slot_period) % n_slots_frame; + else + pucch->ul_slot = (s + 1) % n_slots_frame; + return nr_acknack_scheduling(mod_id, UE_id, frame, slot, r_pucch,is_common); } // multiplexing harq and csi in a pucch else { - csi_pucch->timing_indicator = i; + csi_pucch->timing_indicator = ind_found; csi_pucch->dai_c++; return 1; } } - pucch->timing_indicator = i; // index in the list of timing indicators + pucch->timing_indicator = ind_found; // index in the list of timing indicators - LOG_D(MAC,"2. DL slot %d, UL_ACK %d (index %d)\n",slot,pucch->ul_slot,i); + LOG_D(NR_MAC,"pucch_acknak 2. DAI 0 DL %d.%d, UL_ACK %d.%d (index %d)\n",frame,slot,pucch->frame,pucch->ul_slot,pucch->timing_indicator); pucch->dai_c++; pucch->resource_indicator = 0; // each UE has dedicated PUCCH resources - + pucch->r_pucch=r_pucch; NR_PUCCH_Config_t *pucch_Config = NULL; if (sched_ctrl->active_ubwp) { pucch_Config = sched_ctrl->active_ubwp->bwp_Dedicated->pucch_Config->choice.setup; @@ -1351,19 +1396,34 @@ int nr_acknack_scheduling(int mod_id, pucch_Config = RC.nrmac[mod_id]->UE_info.CellGroup[UE_id]->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pucch_Config->choice.setup; } + NR_BWP_t *genericParameters = sched_ctrl->active_ubwp ? + &sched_ctrl->active_ubwp->bwp_Common->genericParameters: + &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; + int bwp_start = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth,MAX_BWP_SIZE); + /* verify that at that slot and symbol, resources are free. We only do this * for initialCyclicShift 0 (we assume it always has that one), so other * initialCyclicShifts can overlap with ICS 0!*/ - if (pucch_Config==NULL) - return 0; - const NR_PUCCH_Resource_t *resource = pucch_Config->resourceToAddModList->list.array[pucch->resource_indicator]; - DevAssert(resource->format.present == NR_PUCCH_Resource__format_PR_format0); - if (resource->format.choice.format0->initialCyclicShift == 0) { - uint16_t *vrb_map_UL = &RC.nrmac[mod_id]->common_channels[CC_id].vrb_map_UL[pucch->ul_slot * MAX_BWP_SIZE]; - const uint16_t symb = 1 << resource->format.choice.format0->startingSymbolIndex; - if ((vrb_map_UL[resource->startingPRB] & symb) != 0) - LOG_W(MAC, "symbol 0x%x is not free for PUCCH alloc in vrb_map_UL at RB %ld and slot %d.%d\n", symb, resource->startingPRB, pucch->frame, pucch->ul_slot); - vrb_map_UL[resource->startingPRB] |= symb; + + if (pucch_Config) { + const NR_PUCCH_Resource_t *resource = pucch_Config->resourceToAddModList->list.array[pucch->resource_indicator]; + DevAssert(resource->format.present == NR_PUCCH_Resource__format_PR_format0); + int second_hop_prb = resource->secondHopPRB!= NULL ? *resource->secondHopPRB : 0; + int nr_of_symbols = resource->format.choice.format0->nrofSymbols; + if (resource->format.choice.format0->initialCyclicShift == 0) { + uint16_t *vrb_map_UL = &RC.nrmac[mod_id]->common_channels[CC_id].vrb_map_UL[pucch->ul_slot * MAX_BWP_SIZE]; + for (int l=0; lformat.choice.format0->startingSymbolIndex + l); + int prb; + if (l==1 && second_hop_prb != 0) + prb = second_hop_prb; + else + prb = resource->startingPRB; + if ((vrb_map_UL[bwp_start+prb] & symb) != 0) + LOG_W(MAC, "symbol 0x%x is not free for PUCCH alloc in vrb_map_UL at RB %ld and slot %d.%d\n", symb, resource->startingPRB, pucch->frame, pucch->ul_slot); + vrb_map_UL[bwp_start+prb] |= symb; + } + } } return 0; } @@ -1381,6 +1441,7 @@ void nr_sr_reporting(int Mod_idP, frame_t SFN, sub_frame_t slot) for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + if (sched_ctrl->ul_failure==1) continue; NR_PUCCH_Config_t *pucch_Config = NULL; if (sched_ctrl->active_ubwp) { pucch_Config = sched_ctrl->active_ubwp->bwp_Dedicated->pucch_Config->choice.setup; @@ -1392,7 +1453,11 @@ void nr_sr_reporting(int Mod_idP, frame_t SFN, sub_frame_t slot) RC.nrmac[Mod_idP]->UE_info.CellGroup[UE_id]->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pucch_Config->choice.setup) { pucch_Config = RC.nrmac[Mod_idP]->UE_info.CellGroup[UE_id]->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pucch_Config->choice.setup; } - if (pucch_Config == NULL ) continue; + + else continue; + if (!pucch_Config->schedulingRequestResourceToAddModList) + continue; + AssertFatal(pucch_Config->schedulingRequestResourceToAddModList->list.count>0,"NO SR configuration available"); for (int SR_resource_id =0; SR_resource_id < pucch_Config->schedulingRequestResourceToAddModList->list.count;SR_resource_id++) { @@ -1403,9 +1468,10 @@ void nr_sr_reporting(int Mod_idP, frame_t SFN, sub_frame_t slot) find_period_offest_SR(SchedulingRequestResourceConfig,&SR_period,&SR_offset); // convert to int to avoid underflow of uint int sfn_sf = SFN * n_slots_frame + slot; + LOG_D(NR_MAC,"SR_resource_id %d: SR_period %d, SR_offset %d\n",SR_resource_id,SR_period,SR_offset); if ((sfn_sf - SR_offset) % SR_period != 0) continue; - LOG_D(MAC, "%4d.%2d Scheduling Request identified\n", SFN, slot); + LOG_D(NR_MAC, "%4d.%2d Scheduling Request identified\n", SFN, slot); NR_PUCCH_ResourceId_t *PucchResourceId = SchedulingRequestResourceConfig->resource; int found = -1; @@ -1437,7 +1503,7 @@ void nr_sr_reporting(int Mod_idP, frame_t SFN, sub_frame_t slot) && pdu->initial_cyclic_shift == pucch_res->format.choice.format0->initialCyclicShift && pdu->nr_of_symbols == pucch_res->format.choice.format0->nrofSymbols && pdu->start_symbol_index == pucch_res->format.choice.format0->startingSymbolIndex) { - LOG_D(MAC,"%4d.%2d adding SR_flag 1 to PUCCH nFAPI SR for RNTI %04x\n", SFN, slot, pdu->rnti); + LOG_D(NR_MAC,"%4d.%2d adding SR_flag 1 to PUCCH nFAPI SR for RNTI %04x\n", SFN, slot, pdu->rnti); pdu->sr_flag = 1; nfapi_allocated = true; break; @@ -1452,7 +1518,7 @@ void nr_sr_reporting(int Mod_idP, frame_t SFN, sub_frame_t slot) NR_sched_pucch_t *curr_pucch = &sched_ctrl->sched_pucch[0]; if (curr_pucch->frame == SFN && curr_pucch->ul_slot == slot) { if (curr_pucch->resource_indicator != found) { - LOG_W(MAC, "%4d.%2d expected PUCCH in this slot to have resource indicator of SR (%d), skipping SR\n", SFN, slot, found); + LOG_W(NR_MAC, "%4d.%2d expected PUCCH in this slot to have resource indicator of SR (%d), skipping SR\n", SFN, slot, found); continue; } curr_pucch->sr_flag = true; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 18ba5f612d..9a6fa32b5f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -34,34 +34,21 @@ #include "common/utils/nr/nr_common.h" #include +#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" -//38.321 Table 6.1.3.1-1 -const uint32_t NR_SHORT_BSR_TABLE[32] = { - 0, 10, 14, 20, 28, 38, 53, 74, - 102, 142, 198, 276, 384, 535, 745, 1038, - 1446, 2014, 2806, 3909, 5446, 7587, 10570, 14726, -20516, 28581, 39818, 55474, 77284, 107669, 150000, 300000 -}; +int get_dci_format(NR_UE_sched_ctrl_t *sched_ctrl) { -//38.321 Table 6.1.3.1-2 -const uint32_t NR_LONG_BSR_TABLE[256] ={ - 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 25, 26, - 28, 30, 32, 34, 36, 38, 40, 43, 46, 49, 52, 55, 59, 62, 66, 71, - 75, 80, 85, 91, 97, 103, 110, 117, 124, 132, 141, 150, 160, 170, 181, 193, - 205, 218, 233, 248, 264, 281, 299, 318, 339, 361, 384, 409, 436, 464, 494, 526, - 560, 597, 635, 677, 720, 767, 817, 870, 926, 987, 1051, 1119, 1191, 1269, 1351, 1439, - 1532, 1631, 1737, 1850, 1970, 2098, 2234, 2379, 2533, 2698, 2873, 3059, 3258, 3469, 3694, 3934, - 4189, 4461, 4751, 5059, 5387, 5737, 6109, 6506, 6928, 7378, 7857, 8367, 8910, 9488, 10104, 10760, - 11458, 12202, 12994, 13838, 14736, 15692, 16711, 17795, 18951, 20181, 21491, 22885, 24371, 25953, 27638, 29431, - 31342, 33376, 35543, 37850, 40307, 42923, 45709, 48676, 51836, 55200, 58784, 62599, 66663, 70990, 75598, 80505, - 85730, 91295, 97221, 103532, 110252, 117409, 125030, 133146, 141789, 150992, 160793, 171231, 182345, 194182, 206786, 220209, - 234503, 249725, 265935, 283197, 301579, 321155, 342002, 364202, 387842, 413018, 439827, 468377, 498780, 531156, 565634, 602350, - 641449, 683087, 727427, 774645, 824928, 878475, 935498, 996222, 1060888, 1129752, 1203085, 1281179, 1364342, 1452903, 1547213, 1647644, - 1754595, 1868488, 1989774, 2118933, 2256475, 2402946, 2558924, 2725027, 2901912, 3090279, 3290873, 3504487, 3731968, 3974215, 4232186, 4506902, - 4799451, 5110989, 5442750, 5796046, 6172275, 6572925, 6999582, 7453933, 7937777, 8453028, 9001725, 9586039, 10208280, 10870913, 11576557, 12328006, -13128233, 13980403, 14887889, 15854280, 16883401, 17979324, 19146385, 20389201, 21712690, 23122088, 24622972, 26221280, 27923336, 29735875, 31666069, 33721553, -35910462, 38241455, 40723756, 43367187, 46182206, 49179951, 52372284, 55771835, 59392055, 63247269, 67352729, 71724679, 76380419, 81338368, 162676736, 4294967295 -}; + const long f = sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats; + int dci_format; + if (sched_ctrl->search_space) { + dci_format = f ? NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0; + } + else { + dci_format = NR_UL_DCI_FORMAT_0_0; + } + + return(dci_format); +} void calculate_preferred_ul_tda(module_id_t module_id, const NR_BWP_Uplink_t *ubwp) { @@ -164,7 +151,7 @@ void calculate_preferred_ul_tda(module_id_t module_id, const NR_BWP_Uplink_t *ub nrmac->preferred_ul_tda[bwp_id][slot] = 0; else if (tdd && nr_mix_slots && sched_slot % nr_slots_period == tdd->nrofDownlinkSlots) nrmac->preferred_ul_tda[bwp_id][slot] = tdaMi; - LOG_I(MAC, "DL slot %d UL slot %d preferred_ul_tda %d\n", slot, sched_slot, nrmac->preferred_ul_tda[bwp_id][slot]); + LOG_D(MAC, "DL slot %d UL slot %d preferred_ul_tda %d\n", slot, sched_slot, nrmac->preferred_ul_tda[bwp_id][slot]); } if (k2 < tdd->nrofUplinkSlots) @@ -198,7 +185,7 @@ void calculate_preferred_ul_tda(module_id_t module_id, const NR_BWP_Uplink_t *ub // F: length of L is 0:8 or 1:16 bits wide // R: Reserved bit, set to zero. -void nr_process_mac_pdu(module_id_t module_idP, +int nr_process_mac_pdu(module_id_t module_idP, int UE_id, uint8_t CC_id, frame_t frameP, @@ -378,18 +365,22 @@ void nr_process_mac_pdu(module_id_t module_idP, mac_sdu_len = (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L; mac_subheader_len = 2; } - LOG_D(NR_MAC, "[UE %d] Frame %d : ULSCH -> UL-DCCH %d (gNB %d, %d bytes), rnti: %d \n", module_idP, frameP, rx_lcid, module_idP, mac_sdu_len, UE_info->rnti[UE_id]); - mac_rlc_data_ind(module_idP, - UE_info->rnti[UE_id], - module_idP, - frameP, - ENB_FLAG_YES, - MBMS_FLAG_NO, - rx_lcid, - (char *) (pduP + mac_subheader_len), - mac_sdu_len, - 1, - NULL); + if (UE_info->CellGroup[UE_id]) { + LOG_D(NR_MAC, "[UE %d] Frame %d : ULSCH -> UL-DCCH %d (gNB %d, %d bytes), rnti: %d \n", module_idP, frameP, rx_lcid, module_idP, mac_sdu_len, UE_info->rnti[UE_id]); + mac_rlc_data_ind(module_idP, + UE_info->rnti[UE_id], + module_idP, + frameP, + ENB_FLAG_YES, + MBMS_FLAG_NO, + rx_lcid, + (char *) (pduP + mac_subheader_len), + mac_sdu_len, + 1, + NULL); + } else { + AssertFatal(1==0,"[UE %d] Frame/Slot %d.%d : Received LCID %d which is not configured, dropping packet\n",UE_id,frameP,slot,rx_lcid); + } break; case UL_SCH_LCID_SRB3: // todo @@ -478,7 +469,7 @@ void nr_process_mac_pdu(module_id_t module_idP, default: LOG_E(NR_MAC, "Received unknown MAC header (LCID = 0x%02x)\n", rx_lcid); - return; + return -1; break; } @@ -503,9 +494,10 @@ void nr_process_mac_pdu(module_id_t module_idP, for (int i = 0; i < 20; i++) // Only printf 1st - 20nd bytes printf("%02x ", pduP[i]); printf("\n"); - return; + return 0; } } + return 0; } void abort_nr_ul_harq(module_id_t mod_id, int UE_id, int8_t harq_pid) @@ -627,7 +619,7 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, T_BUFFER(sduP, sdu_lenP)); UE_info->mac_stats[UE_id].ulsch_total_bytes_rx += sdu_lenP; - LOG_D(NR_MAC, "[gNB %d][PUSCH %d] CC_id %d %d.%d Received ULSCH sdu from PHY (rnti %x, UE_id %d) ul_cqi %d TA %d sduP %p\n", + LOG_D(NR_MAC, "[gNB %d][PUSCH %d] CC_id %d %d.%d Received ULSCH sdu from PHY (rnti %x, UE_id %d) ul_cqi %d TA %d sduP %p, rssi %d\n", gnb_mod_idP, harq_pid, CC_idP, @@ -637,10 +629,11 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, UE_id, ul_cqi, timing_advance, - sduP); + sduP, + rssi); // if not missed detection (10dB threshold for now) - if (UE_scheduling_control->raw_rssi < 100 + rssi) { + if (rssi>0) { UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10,ul_cqi,30); if (timing_advance != 0xffff) UE_scheduling_control->ta_update = timing_advance; @@ -649,7 +642,8 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, LOG_D(NR_MAC, "[UE %d] PUSCH TPC %d and TA %d\n",UE_id,UE_scheduling_control->tpc0,UE_scheduling_control->ta_update); } else{ - UE_scheduling_control->tpc0 = 1; + LOG_D(NR_MAC,"[UE %d] Detected DTX : increasing UE TX power\n",UE_id); + UE_scheduling_control->tpc0 = 3; } #if defined(ENABLE_MAC_PAYLOAD_DEBUG) @@ -757,7 +751,7 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, // re-initialize ta update variables after RA procedure completion UE_info->UE_sched_ctrl[UE_id].ta_frame = frameP; - LOG_I(NR_MAC, + LOG_D(NR_MAC, "reset RA state information for RA-RNTI %04x/index %d\n", ra->rnti, i); @@ -770,6 +764,14 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, UE_id, ra->rnti); + NR_UE_sched_ctrl_t *UE_scheduling_control = &UE_info->UE_sched_ctrl[UE_id]; + + UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10,ul_cqi,30); + if (timing_advance != 0xffff) + UE_scheduling_control->ta_update = timing_advance; + UE_scheduling_control->raw_rssi = rssi; + UE_scheduling_control->pusch_snrx10 = ul_cqi * 5 - 640; + LOG_D(NR_MAC, "[UE %d] PUSCH TPC %d and TA %d\n",UE_id,UE_scheduling_control->tpc0,UE_scheduling_control->ta_update); if(ra->cfra) { LOG_I(NR_MAC, "(ue %i, rnti 0x%04x) CFRA procedure succeeded!\n", UE_id, ra->rnti); @@ -790,13 +792,16 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, // First byte corresponds to R/LCID MAC sub-header memcpy(ra->cont_res_id, &sduP[1], sizeof(uint8_t) * 6); - nr_process_mac_pdu(gnb_mod_idP, UE_id, CC_idP, frameP, slotP, sduP, sdu_lenP); - - ra->state = Msg4; - ra->Msg4_frame = (frameP + 2) % 1024; - ra->Msg4_slot = 1; - LOG_I(NR_MAC, "Scheduling RA-Msg4 for TC_RNTI %04x (state %d, frame %d, slot %d)\n", ra->rnti, ra->state, ra->Msg4_frame, ra->Msg4_slot); - + if (nr_process_mac_pdu(gnb_mod_idP, UE_id, CC_idP, frameP, slotP, sduP, sdu_lenP) == 0) { + ra->state = Msg4; + ra->Msg4_frame = (frameP + 2) % 1024; + ra->Msg4_slot = 1; + LOG_I(NR_MAC, "Scheduling RA-Msg4 for TC_RNTI %04x (state %d, frame %d, slot %d)\n", ra->rnti, ra->state, ra->Msg4_frame, ra->Msg4_slot); + } + else { + nr_mac_remove_ra_rnti(gnb_mod_idP, ra->rnti); + nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra); + } } return; } @@ -864,7 +869,7 @@ bool nr_UE_is_to_be_scheduled(module_id_t mod_id, int CC_id, int UE_id, frame_t * (2) there is a scheduling request * (3) or we did not schedule it in more than 10 frames */ const bool has_data = sched_ctrl->estimated_ul_buffer > sched_ctrl->sched_ul_bytes; - const bool high_inactivity = diff >= nrmac->ulsch_max_slots_inactivity; + const bool high_inactivity = diff >= nrmac->ulsch_max_frame_inactivity * n; LOG_D(NR_MAC, "%4d.%2d UL inactivity %d slots has_data %d SR %d\n", frame, @@ -895,14 +900,16 @@ bool allocate_ul_retransmission(module_id_t module_id, NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; NR_sched_pusch_t *retInfo = &sched_ctrl->ul_harq_processes[harq_pid].sched_pusch; - + NR_CellGroupConfig_t *cg = UE_info->CellGroup[UE_id]; + NR_BWP_UplinkDedicated_t *ubwpd= cg ? cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP:NULL; NR_BWP_t *genericParameters = sched_ctrl->active_ubwp ? &sched_ctrl->active_ubwp->bwp_Common->genericParameters : &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; - int rbStart = sched_ctrl->active_ubwp ? NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE) : 0; + int rbStart = 0; // wrt BWP start const uint16_t bwpSize = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - const uint8_t num_dmrs_cdm_grps_no_data = sched_ctrl->active_bwp ? 1 : 2; + const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_bwp || ubwpd) ? 1 : 2; const int tda = sched_ctrl->active_ubwp ? RC.nrmac[module_id]->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; LOG_D(NR_MAC,"retInfo->time_domain_allocation = %d, tda = %d\n", retInfo->time_domain_allocation, tda); + LOG_D(NR_MAC,"num_dmrs_cdm_grps_no_data %d, tbs %d\n",num_dmrs_cdm_grps_no_data, retInfo->tb_size); if (tda == retInfo->time_domain_allocation) { /* Check the resource is enough for retransmission */ while (rbStart < bwpSize && !rballoc_mask[rbStart]) @@ -914,12 +921,13 @@ bool allocate_ul_retransmission(module_id_t module_id, /* check whether we need to switch the TDA allocation since tha last * (re-)transmission */ NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; - const long f = sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats; - const int dci_format = sched_ctrl->active_ubwp ? (f ? NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0) : NR_UL_DCI_FORMAT_0_0; + + int dci_format = get_dci_format(sched_ctrl); + if (ps->time_domain_allocation != tda || ps->dci_format != dci_format || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) - nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); + nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); LOG_D(NR_MAC, "%s(): retransmission keeping TDA %d and TBS %d\n", __func__, tda, retInfo->tb_size); } else { /* the retransmission will use a different time domain allocation, check @@ -930,9 +938,8 @@ bool allocate_ul_retransmission(module_id_t module_id, while (rbStart + rbSize < bwpSize && rballoc_mask[rbStart + rbSize]) rbSize++; NR_pusch_semi_static_t temp_ps; - const long f = sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats; - const int dci_format = sched_ctrl->active_ubwp ? (f ? NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0) : NR_UL_DCI_FORMAT_0_0; - nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, dci_format, tda, num_dmrs_cdm_grps_no_data, &temp_ps); + int dci_format = get_dci_format(sched_ctrl); + nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp,ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, &temp_ps); uint32_t new_tbs; uint16_t new_rbSize; bool success = nr_find_nb_rb(retInfo->Qm, @@ -1029,9 +1036,13 @@ void pf_ul(module_id_t module_id, if (UE_info->Msg4_ACKed[UE_id] != true) continue; + LOG_D(NR_MAC,"pf_ul: preparing UL scheduling for UE %d\n",UE_id); NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; NR_BWP_t *genericParameters = sched_ctrl->active_ubwp ? &sched_ctrl->active_ubwp->bwp_Common->genericParameters : &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; - int rbStart = sched_ctrl->active_ubwp ? NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE) : 0; + int rbStart = 0; // wrt BWP start + NR_CellGroupConfig_t *cg = UE_info->CellGroup[UE_id]; + NR_BWP_UplinkDedicated_t *ubwpd= cg ? cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; + const uint16_t bwpSize = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; @@ -1043,6 +1054,7 @@ void pf_ul(module_id_t module_id, /* Check if retransmission is necessary */ sched_pusch->ul_harq_pid = sched_ctrl->retrans_ul_harq.head; + LOG_D(NR_MAC,"pf_ul: UE %d harq_pid %d\n",UE_id,sched_pusch->ul_harq_pid); if (sched_pusch->ul_harq_pid >= 0) { /* Allocate retransmission*/ bool r = allocate_ul_retransmission( @@ -1051,6 +1063,8 @@ void pf_ul(module_id_t module_id, LOG_D(NR_MAC, "%4d.%2d UL retransmission UE RNTI %04x can NOT be allocated\n", frame, slot, UE_info->rnti[UE_id]); continue; } + else LOG_D(NR_MAC,"%4d.%2d UL Retransmission UE RNTI %04x to be allocated, max_num_ue %d\n",frame,slot,UE_info->rnti[UE_id],max_num_ue); + /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */ max_num_ue--; if (max_num_ue < 0) @@ -1062,6 +1076,7 @@ void pf_ul(module_id_t module_id, /* preprocessor computed sched_frame/sched_slot */ const bool do_sched = nr_UE_is_to_be_scheduled(module_id, 0, UE_id, sched_pusch->frame, sched_pusch->slot); + LOG_D(NR_MAC,"pf_ul: do_sched UE %d => %s\n",UE_id,do_sched ? "yes" : "no"); if (B == 0 && !do_sched) continue; @@ -1091,14 +1106,13 @@ void pf_ul(module_id_t module_id, /* we want to avoid a lengthy deduction of DMRS and other parameters in * every TTI if we can save it, so check whether dci_format, TDA, or * num_dmrs_cdm_grps_no_data has changed and only then recompute */ - const uint8_t num_dmrs_cdm_grps_no_data = sched_ctrl->active_ubwp ? 1 : 2; - const long f = sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats; - const int dci_format = sched_ctrl->active_ubwp ? (f ? NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0) : NR_UL_DCI_FORMAT_0_0; + const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_ubwp || ubwpd) ? 1 : 2; + int dci_format = get_dci_format(sched_ctrl); const int tda = sched_ctrl->active_ubwp ? nrmac->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; if (ps->time_domain_allocation != tda || ps->dci_format != dci_format || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) - nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); + nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; sched_pusch->mcs = 9; update_ul_ue_R_Qm(sched_pusch, ps); @@ -1158,6 +1172,7 @@ void pf_ul(module_id_t module_id, LOG_D(NR_MAC, "%4d.%2d no free CCE for UL DCI UE %04x\n", frame, slot, UE_info->rnti[UE_id]); continue; } + else LOG_D(NR_MAC, "%4d.%2d free CCE for UL DCI UE %04x\n",frame,slot, UE_info->rnti[UE_id]); /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */ max_num_ue--; @@ -1165,6 +1180,8 @@ void pf_ul(module_id_t module_id, return; NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + NR_CellGroupConfig_t *cg = UE_info->CellGroup[UE_id]; + NR_BWP_UplinkDedicated_t *ubwpd= cg ? cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP:NULL; NR_BWP_t *genericParameters = sched_ctrl->active_ubwp ? &sched_ctrl->active_ubwp->bwp_Common->genericParameters : &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; int rbStart = sched_ctrl->active_ubwp ? NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE) : 0; const uint16_t bwpSize = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); @@ -1182,19 +1199,19 @@ void pf_ul(module_id_t module_id, UE_id, UE_info->rnti[UE_id],rbStart,min_rb,bwpSize); return; } + else LOG_D(NR_MAC,"allocating UL data for UE %d/RNTI %04x (rbStsart %d, min_rb %d, bwpSize %d\n",UE_id, UE_info->rnti[UE_id],rbStart,min_rb,bwpSize); /* Save PUSCH field */ /* we want to avoid a lengthy deduction of DMRS and other parameters in * every TTI if we can save it, so check whether dci_format, TDA, or * num_dmrs_cdm_grps_no_data has changed and only then recompute */ - const uint8_t num_dmrs_cdm_grps_no_data = sched_ctrl->active_ubwp ? 1 : 2; - const long f = sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats; - const int dci_format = sched_ctrl->active_ubwp ? (f ? NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0) : NR_UL_DCI_FORMAT_0_0; + const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_ubwp || ubwpd) ? 1 : 2; + int dci_format = get_dci_format(sched_ctrl); const int tda = sched_ctrl->active_ubwp ? nrmac->preferred_ul_tda[sched_ctrl->active_ubwp->bwp_Id][slot] : 0; if (ps->time_domain_allocation != tda || ps->dci_format != dci_format || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) - nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); + nr_set_pusch_semi_static(scc, sched_ctrl->active_ubwp, ubwpd, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); update_ul_ue_R_Qm(sched_pusch, ps); /* Calculate the current scheduling bytes and the necessary RBs */ @@ -1211,8 +1228,8 @@ void pf_ul(module_id_t module_id, &rbSize); sched_pusch->rbSize = rbSize; sched_pusch->tb_size = TBS; - LOG_D(NR_MAC,"rbSize %d, TBS %d, est buf %d, sched_ul %d, B %d\n", - rbSize, sched_pusch->tb_size, sched_ctrl->estimated_ul_buffer, sched_ctrl->sched_ul_bytes, B); + LOG_D(NR_MAC,"rbSize %d, TBS %d, est buf %d, sched_ul %d, B %d, CCE %d, num_dmrs_symb %d, N_PRB_DMRS %d\n", + rbSize, sched_pusch->tb_size, sched_ctrl->estimated_ul_buffer, sched_ctrl->sched_ul_bytes, B,sched_ctrl->cce_index,ps->num_dmrs_symb,ps->N_PRB_DMRS); /* Mark the corresponding RBs as used */ n_rb_sched -= sched_pusch->rbSize; @@ -1276,6 +1293,10 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth: scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + const uint16_t bwpStart = NRRIV2PRBOFFSET(sched_ctrl->active_ubwp ? + sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth: + scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, + MAX_BWP_SIZE); const struct NR_PUSCH_TimeDomainResourceAllocationList *tdaList = sched_ctrl->active_ubwp ? sched_ctrl->active_ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList: scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; @@ -1285,11 +1306,14 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t const uint16_t symb = ((1 << nrOfSymbols) - 1) << startSymbolIndex; int st = 0, e = 0, len = 0; + for (int i = 0; i < bwpSize; i++) + if (RC.nrmac[module_id]->ulprbbl[i] == 1) vrb_map_UL[i]=symb; + for (int i = 0; i < bwpSize; i++) { - while ((vrb_map_UL[i] & symb) != 0 && i < bwpSize) + while ((vrb_map_UL[bwpStart + i] & symb) != 0 && i < bwpSize) i++; st = i; - while ((vrb_map_UL[i] & symb) == 0 && i < bwpSize) + while ((vrb_map_UL[bwpStart + i] & symb) == 0 && i < bwpSize) i++; if (i - st > len) { len = i - st; @@ -1298,6 +1322,8 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t } st = e - len + 1; + LOG_D(NR_MAC,"UL %d.%d : start_prb %d, end PRB %d\n",frame,slot,st,e); + uint8_t rballoc_mask[bwpSize]; /* Calculate mask: if any RB in vrb_map_UL is blocked (1), the current RB will be 0 */ @@ -1373,6 +1399,9 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; if (sched_ctrl->ul_failure == 1 && get_softmodem_params()->phy_test==0) continue; + + NR_CellGroupConfig_t *cg = UE_info->CellGroup[UE_id]; + NR_BWP_UplinkDedicated_t *ubwpd= cg ? cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP:NULL; UE_info->mac_stats[UE_id].ulsch_current_bytes = 0; /* dynamic PUSCH values (RB alloc, MCS, hence R, Qm, TBS) that change in @@ -1444,24 +1473,28 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) sched_ctrl->last_ul_slot = sched_pusch->slot; LOG_D(NR_MAC, - "%4d.%2d RNTI %04x UL sched %4d.%2d start %2d RBS %3d startSymbol %2d nb_symbol %2d MCS %2d TBS %4d HARQ PID %2d round %d NDI %d est %6d sched %6d est BSR %6d\n", + "ULSCH/PUSCH: %4d.%2d RNTI %04x UL sched %4d.%2d DCI L %d start %2d RBS %3d startSymbol %2d nb_symbol %2d dmrs_pos %x MCS %2d TBS %4d HARQ PID %2d round %d RV %d NDI %d est %6d sched %6d est BSR %6d TPC %d\n", frame, slot, rnti, sched_pusch->frame, sched_pusch->slot, + sched_ctrl->aggregation_level, sched_pusch->rbStart, sched_pusch->rbSize, ps->startSymbolIndex, ps->nrOfSymbols, + ps->ul_dmrs_symb_pos, sched_pusch->mcs, sched_pusch->tb_size, harq_id, cur_harq->round, + nr_rv_round_map[cur_harq->round], cur_harq->ndi, sched_ctrl->estimated_ul_buffer, sched_ctrl->sched_ul_bytes, - sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes); + sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes, + sched_ctrl->tpc0); /* PUSCH in a later slot, but corresponding DCI now! */ @@ -1500,8 +1533,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) pusch_pdu->mcs_index = sched_pusch->mcs; pusch_pdu->mcs_table = ps->mcs_table; pusch_pdu->transform_precoding = ps->transform_precoding; - if (ps->pusch_Config && - ps->pusch_Config->dataScramblingIdentityPUSCH) + if (ps->pusch_Config && ps->pusch_Config->dataScramblingIdentityPUSCH) pusch_pdu->data_scrambling_id = *ps->pusch_Config->dataScramblingIdentityPUSCH; else pusch_pdu->data_scrambling_id = *scc->physCellId; @@ -1553,6 +1585,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) pusch_pdu->pusch_data.tb_size = sched_pusch->tb_size; pusch_pdu->pusch_data.num_cb = 0; //CBG not supported + LOG_D(NR_MAC,"PUSCH PDU : data_scrambling_identity %x, dmrs_scrambling_id %x\n",pusch_pdu->data_scrambling_id,pusch_pdu->ul_dmrs_scrambling_id); /* TRANSFORM PRECODING --------------------------------------------------------*/ if (pusch_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled){ @@ -1592,8 +1625,8 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) /* look up the PDCCH PDU for this BWP and CORESET. If it does not exist, * create it */ const int bwpid = sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0; - NR_SearchSpace_t *ss = sched_ctrl->active_bwp ? sched_ctrl->search_space: RC.nrmac[module_id]->sched_ctrlCommon->search_space; - NR_ControlResourceSet_t *coreset = sched_ctrl->active_bwp? sched_ctrl->coreset: RC.nrmac[module_id]->sched_ctrlCommon->coreset; + NR_SearchSpace_t *ss = (sched_ctrl->active_bwp || ubwpd) ? sched_ctrl->search_space: RC.nrmac[module_id]->sched_ctrlCommon->search_space; + NR_ControlResourceSet_t *coreset = (sched_ctrl->active_bwp || ubwpd) ? sched_ctrl->coreset: RC.nrmac[module_id]->sched_ctrlCommon->coreset; const int coresetid = coreset->controlResourceSetId; nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu = pdcch_pdu_bwp_coreset[bwpid][coresetid]; if (!pdcch_pdu) { @@ -1603,11 +1636,11 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) ul_dci_request_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); pdcch_pdu = &ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15; ul_dci_req->numPdus += 1; - nr_configure_pdcch(pdcch_pdu, ss, coreset, scc, genericParameters, NULL); + nr_configure_pdcch(nr_mac, pdcch_pdu, ss, coreset, scc, genericParameters, NULL); pdcch_pdu_bwp_coreset[bwpid][coresetid] = pdcch_pdu; } - LOG_D(NR_MAC,"Configuring ULDCI/PDCCH in %d.%d\n", frame,slot); + LOG_D(NR_MAC,"Configuring ULDCI/PDCCH in %d.%d at CCE %d, rnti %x\n", frame,slot,sched_ctrl->cce_index,rnti); /* Fill PDCCH DL DCI PDU */ nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu->dci_pdu[pdcch_pdu->numDlDci]; @@ -1628,14 +1661,12 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) dci_pdu_rel15_t uldci_payload; memset(&uldci_payload, 0, sizeof(uldci_payload)); - NR_CellGroupConfig_t *CellGroup = UE_info->CellGroup[UE_id]; int n_ubwp=1; - if (CellGroup && CellGroup->spCellConfig && CellGroup->spCellConfig->spCellConfigDedicated && - CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig && - CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList) - n_ubwp = CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count; + if (cg->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList) + n_ubwp = cg->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count; config_uldci(sched_ctrl->active_ubwp, + ubwpd, scc, pusch_pdu, &uldci_payload, @@ -1645,7 +1676,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) n_ubwp, bwpid); fill_dci_pdu_rel15(scc, - CellGroup, + cg, dci_pdu, &uldci_payload, ps->dci_format, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 391b98af36..3b275ca8a0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -31,8 +31,6 @@ #ifndef __LAYER2_NR_MAC_PROTO_H__ #define __LAYER2_NR_MAC_PROTO_H__ -#include "PHY/defs_gNB.h" - #include "LAYER2/NR_MAC_gNB/nr_mac_gNB.h" #include "NR_TAG-Id.h" @@ -53,10 +51,10 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, int pusch_AntennaPorts, int sib1_tda, NR_ServingCellConfigCommon_t *scc, - int nsa_flag, + NR_BCCH_BCH_Message_t *mib, + int add_ue, uint32_t rnti, - NR_CellGroupConfig_t *CellGroup - ); + NR_CellGroupConfig_t *CellGroup); void clear_nr_nfapi_information(gNB_MAC_INST * gNB, int CC_idP, @@ -178,7 +176,8 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, void config_uldci(const NR_BWP_Uplink_t *ubwp, - const NR_ServingCellConfigCommon_t *scc, + const NR_BWP_UplinkDedicated_t *ubwpd, + const NR_ServingCellConfigCommon_t *scc, const nfapi_nr_pusch_pdu_t *pusch_pdu, dci_pdu_rel15_t *dci_pdu_rel15, int dci_format, @@ -204,11 +203,14 @@ int nr_acknack_scheduling(int Mod_idP, int UE_id, frame_t frameP, sub_frame_t slotP, - int r_pucch); + int r_pucch, + int do_common); void get_pdsch_to_harq_feedback(int Mod_idP, int UE_id, + int bwp_id, NR_SearchSpace__searchSpaceType_PR ss_type, + int *max_fb_time, uint8_t *pdsch_to_harq_feedback); void nr_configure_css_dci_initial(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu, @@ -234,6 +236,7 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, NR_ServingCellConfigCommon_t *scc, NR_CellGroupConfig_t *CellGroup, NR_BWP_Uplink_t *bwp, + NR_BWP_UplinkDedicated_t *bwpd, uint16_t rnti, uint8_t pucch_resource, uint16_t O_csi, @@ -245,7 +248,8 @@ void find_search_space(int ss_type, NR_BWP_Downlink_t *bwp, NR_SearchSpace_t *ss); -void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, +void nr_configure_pdcch(gNB_MAC_INST *gNB_mac, + nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, NR_SearchSpace_t *ss, NR_ControlResourceSet_t *coreset, NR_ServingCellConfigCommon_t *scc, @@ -267,8 +271,9 @@ void prepare_dci(const NR_CellGroupConfig_t *CellGroup, int bwp_id); /* find coreset within the search space */ -NR_ControlResourceSet_t *get_coreset(NR_ServingCellConfigCommon_t *scc, - NR_BWP_Downlink_t *bwp, +NR_ControlResourceSet_t *get_coreset(module_id_t module_idP, + NR_ServingCellConfigCommon_t *scc, + void *bwp, NR_SearchSpace_t *ss, NR_SearchSpace__searchSpaceType_PR ss_type); @@ -282,12 +287,14 @@ long get_K2(NR_ServingCellConfigCommon_t *scc, NR_BWP_Uplink_t *ubwp, int time_d void nr_set_pdsch_semi_static(const NR_ServingCellConfigCommon_t *scc, const NR_CellGroupConfig_t *secondaryCellGroup, const NR_BWP_Downlink_t *bwp, + const NR_BWP_DownlinkDedicated_t *bwpd0, int tda, const long dci_format, NR_pdsch_semi_static_t *ps); void nr_set_pusch_semi_static(const NR_ServingCellConfigCommon_t *scc, const NR_BWP_Uplink_t *ubwp, + const NR_BWP_UplinkDedicated_t *ubwpd, long dci_format, int tda, uint8_t num_dmrs_cdm_grps_no_data, @@ -435,4 +442,5 @@ bool nr_find_nb_rb(uint16_t Qm, void nr_sr_reporting(int Mod_idP, frame_t frameP, sub_frame_t slotP); +void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen); #endif /*__LAYER2_NR_MAC_PROTO_H__*/ diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 117c18ae8d..6e13e4bcc6 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -45,6 +45,86 @@ extern RAN_CONTEXT_t RC; +#define MACSTATSSTRLEN 16384 + +void *nrmac_stats_thread(void *arg) { + + gNB_MAC_INST *gNB = (gNB_MAC_INST *)arg; + + char output[MACSTATSSTRLEN]; + memset(output,0,MACSTATSSTRLEN); + FILE *fd=fopen("nrMAC_stats.log","w"); + AssertFatal(fd!=NULL,"Cannot open nrMAC_stats.log, error %s\n",strerror(errno)); + + while (oai_exit == 0) { + dump_mac_stats(gNB,output,MACSTATSSTRLEN); + fprintf(fd,"%s\n",output); + fflush(fd); + usleep(200000); + fseek(fd,0,SEEK_SET); + } + fclose(fd); + return (void *)0; +} + +void clear_mac_stats(gNB_MAC_INST *gNB) { + memset((void*)gNB->UE_info.mac_stats,0,MAX_MOBILES_PER_GNB*sizeof(NR_mac_stats_t)); +} + +void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen) +{ + NR_UE_info_t *UE_info = &gNB->UE_info; + int num = 1; + + int stroff=0; + if (UE_info->num_UEs == 0) return; + + for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) { + + stroff+=sprintf(output+stroff,"UE ID %d RNTI %04x (%d/%d) PH %d dB PCMAX %d dBm\n", + UE_id, + UE_info->rnti[UE_id], + num++, + UE_info->num_UEs, + UE_info->UE_sched_ctrl[UE_id].ph, + UE_info->UE_sched_ctrl[UE_id].pcmax); + + NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id]; + const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0; + stroff+=sprintf(output+stroff,"UE %d: dlsch_rounds %d/%d/%d/%d, dlsch_errors %d, pucch0_DTX %d average RSRP %d (%d meas)\n", + UE_id, + stats->dlsch_rounds[0], stats->dlsch_rounds[1], + stats->dlsch_rounds[2], stats->dlsch_rounds[3], stats->dlsch_errors, + stats->pucch0_DTX, + avg_rsrp, stats->num_rsrp_meas); + stats->num_rsrp_meas = 0; + stats->cumul_rsrp = 0 ; + stroff+=sprintf(output+stroff,"UE %d: dlsch_total_bytes %d\n", UE_id, stats->dlsch_total_bytes); + stroff+=sprintf(output+stroff,"UE %d: ulsch_rounds %d/%d/%d/%d, ulsch_DTX %d, ulsch_errors %d\n", + UE_id, + stats->ulsch_rounds[0], stats->ulsch_rounds[1], + stats->ulsch_rounds[2], stats->ulsch_rounds[3], + stats->ulsch_DTX, + stats->ulsch_errors); + stroff+=sprintf(output+stroff, + "UE %d: ulsch_total_bytes_scheduled %d, ulsch_total_bytes_received %d\n", + UE_id, + stats->ulsch_total_bytes_scheduled, stats->ulsch_total_bytes_rx); + for (int lc_id = 0; lc_id < 63; lc_id++) { + if (stats->lc_bytes_tx[lc_id] > 0) { + stroff+=sprintf(output+stroff, "UE %d: LCID %d: %d bytes TX\n", UE_id, lc_id, stats->lc_bytes_tx[lc_id]); + LOG_D(NR_MAC, "UE %d: LCID %d: %d bytes TX\n", UE_id, lc_id, stats->lc_bytes_tx[lc_id]); + } + if (stats->lc_bytes_rx[lc_id] > 0) { + stroff+=sprintf(output+stroff, "UE %d: LCID %d: %d bytes RX\n", UE_id, lc_id, stats->lc_bytes_rx[lc_id]); + LOG_D(NR_MAC, "UE %d: LCID %d: %d bytes RX\n", UE_id, lc_id, stats->lc_bytes_rx[lc_id]); + } + } + } + print_meas(&gNB->eNB_scheduler, "DL & UL scheduling timing stats", NULL, NULL); +} + + void mac_top_init_gNB(void) { module_id_t i; @@ -90,6 +170,7 @@ void mac_top_init_gNB(void) RC.nrmac[i]->pre_processor_dl = nr_init_fr1_dlsch_preprocessor(i, 0); RC.nrmac[i]->pre_processor_ul = nr_init_fr1_ulsch_preprocessor(i, 0); } + pthread_create(&RC.nrmac[i]->stats_thread,NULL,nrmac_stats_thread,(void*)RC.nrmac[i]); }//END for (i = 0; i < RC.nb_nr_macrlc_inst; i++) @@ -103,6 +184,7 @@ void mac_top_init_gNB(void) rrc_init_nr_global_param(); + } else { RC.nrmac = NULL; } diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 22da5223c0..699b92a831 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -145,6 +145,8 @@ typedef struct { uint8_t msg3_first_rb; /// Msg3 number of RB uint8_t msg3_nb_rb; + /// Msg3 BWP start + uint8_t msg3_bwp_start; /// Msg3 TPC command uint8_t msg3_TPC; /// Msg3 ULdelay command @@ -529,7 +531,8 @@ typedef struct { /// corresponding to the sched_pusch/sched_pdsch structures below int cce_index; uint8_t aggregation_level; - + /// maximum aggregation level for UE, can be used to select level + int maxL; /// PUCCH scheduling information. Array of two: HARQ+SR in the first field, /// CSI in second. This order is important for nr_acknack_scheduling()! NR_sched_pucch_t sched_pucch[2]; @@ -563,6 +566,7 @@ typedef struct { mac_rlc_status_resp_t rlc_status[MAX_NUM_LCID]; int lcid_mask; + int lcid_to_schedule; uint16_t ta_frame; int16_t ta_update; bool ta_apply; @@ -616,6 +620,7 @@ typedef struct { int ulsch_total_bytes_scheduled; int ulsch_total_bytes_rx; int ulsch_current_bytes; + int pucch0_DTX; int cumul_rsrp; uint8_t num_rsrp_meas; } NR_mac_stats_t; @@ -662,6 +667,7 @@ typedef struct gNB_MAC_INST_s { NR_TAG_t *tag; /// Pointer to IF module instance for PHY NR_IF_Module_t *if_inst; + pthread_t stats_thread; /// Pusch target SNR int pusch_target_snrx10; /// Pucch target SNR @@ -678,7 +684,8 @@ typedef struct gNB_MAC_INST_s { NR_COMMON_channels_t common_channels[NFAPI_CC_MAX]; /// current PDU index (BCH,DLSCH) uint16_t pdu_index[NFAPI_CC_MAX]; - + int num_ulprbbl; + int ulprbbl[275]; /// NFAPI Config Request Structure nfapi_nr_config_request_scf_t config[NFAPI_CC_MAX]; /// NFAPI DL Config Request Structure @@ -743,7 +750,7 @@ typedef struct gNB_MAC_INST_s { int *preferred_ul_tda[MAX_NUM_BWP]; /// maximum number of slots before a UE will be scheduled ULSCH automatically - uint32_t ulsch_max_slots_inactivity; + uint32_t ulsch_max_frame_inactivity; /// DL preprocessor for differentiated scheduling nr_pp_impl_dl pre_processor_dl; @@ -751,6 +758,8 @@ typedef struct gNB_MAC_INST_s { nr_pp_impl_ul pre_processor_ul; NR_UE_sched_ctrl_t *sched_ctrlCommon; + uint16_t cset0_bwp_start; + uint16_t cset0_bwp_size; NR_Type0_PDCCH_CSS_config_t type0_PDCCH_CSS_config[64]; bool first_MIB; diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c index cc44572abd..05e77a935d 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c @@ -603,7 +603,7 @@ void pdcp_fifo_read_input_sdus_frompc5s (const protocol_ctxt_t *const ctxt_pP) //int optval; int bytes_received; sidelink_pc5s_element *sl_pc5s_msg_send = NULL; - pc5s_header_t *pc5s_header = NULL; + pc5s_header_t *pc5s_header = NULL; rb_id_t rab_id = 0; //TTN for D2D (PC5S) // receive a message from ProSe App @@ -704,6 +704,12 @@ void pdcp_fifo_read_input_sdus_frompc5s (const protocol_ctxt_t *const ctxt_pP) pc5s_header->rb_id, rab_id, pc5s_header->data_size); + /* pointers to pc5s_header fields possibly not aligned because pc5s_header points to a packed structure + * Using these possibly unaligned pointers in a function call may trigger alignment errors at run time and + * gcc, from v9, now warns about it. fix these warnings by using local variables + */ + uint32_t sourceL2Id = pc5s_header->sourceL2Id; + uint32_t destinationL2Id = pc5s_header->destinationL2Id; pdcp_data_req( &ctxt, SRB_FLAG_NO, @@ -713,9 +719,11 @@ void pdcp_fifo_read_input_sdus_frompc5s (const protocol_ctxt_t *const ctxt_pP) pc5s_header->data_size, (unsigned char *)receive_buf, PDCP_TRANSMISSION_MODE_DATA, - &pc5s_header->sourceL2Id, - &pc5s_header->destinationL2Id + &sourceL2Id, + &destinationL2Id ); + pc5s_header->sourceL2Id = sourceL2Id; + pc5s_header->destinationL2Id=destinationL2Id; } else { /* else of h_rc == HASH_TABLE_OK */ MSC_LOG_RX_DISCARDED_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, @@ -759,6 +767,12 @@ void pdcp_fifo_read_input_sdus_frompc5s (const protocol_ctxt_t *const ctxt_pP) pc5s_header->rb_id, DEFAULT_RAB_ID, pc5s_header->data_size); + /* pointers to pc5s_header fields possibly not aligned because pc5s_header points to a packed structure + * Using these possibly unaligned pointers in a function call may trigger alignment errors at run time and + * gcc, from v9, now warns about it. fix these warnings by using local variables + */ + uint32_t sourceL2Id = pc5s_header->sourceL2Id; + uint32_t destinationL2Id = pc5s_header->destinationL2Id; pdcp_data_req ( &ctxt, SRB_FLAG_NO, @@ -768,9 +782,11 @@ void pdcp_fifo_read_input_sdus_frompc5s (const protocol_ctxt_t *const ctxt_pP) pc5s_header->data_size, (unsigned char *)receive_buf, PDCP_TRANSMISSION_MODE_DATA, - &pc5s_header->sourceL2Id, - &pc5s_header->destinationL2Id + &sourceL2Id, + &destinationL2Id ); + pc5s_header->sourceL2Id = sourceL2Id; + pc5s_header->destinationL2Id=destinationL2Id; } } /* end of !ctxt.enb_flag */ diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c index fff1db6da6..62aa101a50 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c @@ -102,6 +102,7 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity, entity->rb_id, rcvd_count, entity->is_gnb ? 0 : 1); if (memcmp(integrity, buffer + size - integrity_size, 4) != 0) { LOG_E(PDCP, "discard NR PDU, integrity failed\n"); +// return; } } diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_srb.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_srb.c deleted file mode 100644 index 73840aeb0a..0000000000 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_srb.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -#include "nr_pdcp_entity_srb.h" - -#include -#include -#include - -void nr_pdcp_entity_srb_recv_pdu(nr_pdcp_entity_t *_entity, char *buffer, int size) -{ - nr_pdcp_entity_srb_t *entity = (nr_pdcp_entity_srb_t *)_entity; - - if (size < 2) abort(); - entity->common.deliver_sdu(entity->common.deliver_sdu_data, - (nr_pdcp_entity_t *)entity, buffer+2, size-6); -} - -void nr_pdcp_entity_srb_recv_sdu(nr_pdcp_entity_t *_entity, char *buffer, int size, - int sdu_id) -{ - nr_pdcp_entity_srb_t *entity = (nr_pdcp_entity_srb_t *)_entity; - int sn; - char buf[size+6]; - - sn = entity->common.next_nr_pdcp_tx_sn; - - entity->common.next_nr_pdcp_tx_sn++; - if (entity->common.next_nr_pdcp_tx_sn > entity->common.maximum_nr_pdcp_sn) { - entity->common.next_nr_pdcp_tx_sn = 0; - entity->common.tx_hfn++; - } - - buf[0] = (sn >> 8) & 0x0f; - buf[1] = sn & 0xff; - memcpy(buf+2, buffer, size); - - /* For now use padding for the MAC-I bytes (normally carrying message authentication code) - * which come after the data payload bytes (38.323, section 6.2.2.1) */ - for (int i=size+2; icommon.deliver_pdu(entity->common.deliver_pdu_data, - (nr_pdcp_entity_t *)entity, buf, size+6, sdu_id); -} - -void nr_pdcp_entity_srb_set_integrity_key(nr_pdcp_entity_t *_entity, char *key) -{ - /* nothing to do */ -} - -void nr_pdcp_entity_srb_delete(nr_pdcp_entity_t *_entity) -{ - nr_pdcp_entity_srb_t *entity = (nr_pdcp_entity_srb_t *)_entity; - free(entity); -} - diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 35ef057527..f9a6838443 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -36,6 +36,7 @@ #include "pdcp.h" #include "LAYER2/nr_rlc/nr_rlc_oai_api.h" #include +#include "openair2/SDAP/nr_sdap/nr_sdap_gnb.h" #define TODO do { \ printf("%s:%d:%s: todo\n", __FILE__, __LINE__, __FUNCTION__); \ @@ -443,10 +444,18 @@ static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity, if(IS_SOFTMODEM_NOS1 || UE_NAS_USE_TUN){ LOG_D(PDCP, "IP packet received, to be sent to TUN interface"); - len = write(nas_sock_fd[0], buf, size); + + if(entity->has_sdapDLheader){ + size -= SDAP_HDR_LENGTH; + len = write(nas_sock_fd[0], &buf[SDAP_HDR_LENGTH], size); + } else { + len = write(nas_sock_fd[0], buf, size); + } + if (len != size) { LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); } + } else{ for (i = 0; i < 5; i++) { @@ -471,6 +480,7 @@ static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity, sizeof(gtpv1u_gnb_tunnel_data_req_t) + size + GTPU_HEADER_OVERHEAD_MAX - offset); AssertFatal(message_p != NULL, "OUT OF MEMORY"); + gtpv1u_gnb_tunnel_data_req_t *req=>PV1U_GNB_TUNNEL_DATA_REQ(message_p); gtpu_buffer_p = (uint8_t*)(req+1); memcpy(gtpu_buffer_p+GTPU_HEADER_OVERHEAD_MAX, buf+offset, size-offset); @@ -479,8 +489,10 @@ static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity, req->offset = GTPU_HEADER_OVERHEAD_MAX; req->rnti = ue->rnti; req->pdusession_id = entity->pdusession_id; - if (offset==1) - LOG_I(PDCP, "%s() (drb %d) SDAP header %2x\n",__func__, rb_id, buf[0]); + if (offset==1) { + LOG_I(PDCP, "%s() (drb %d) SDAP header %2x\n",__func__, rb_id, buf[0]); + sdap_gnb_ul_header_handler(buf[0]); // Handler for the UL gNB SDAP Header + } LOG_D(PDCP, "%s() (drb %d) sending message to gtp size %d\n", __func__, rb_id, size-offset); itti_send_msg_to_task(TASK_VARIABLE, INSTANCE_DEFAULT, message_p); } @@ -759,7 +771,11 @@ void pdcp_run(const protocol_ctxt_t *const ctxt_pP) } } -static void add_srb(int is_gnb, int rnti, struct NR_SRB_ToAddMod *s) +static void add_srb(int is_gnb, int rnti, struct NR_SRB_ToAddMod *s, + int ciphering_algorithm, + int integrity_algorithm, + unsigned char *ciphering_key, + unsigned char *integrity_key) { nr_pdcp_entity_t *pdcp_srb; nr_pdcp_ue_t *ue; @@ -780,8 +796,10 @@ static void add_srb(int is_gnb, int rnti, struct NR_SRB_ToAddMod *s) 0, 0, 0, 0, // sdap parameters deliver_sdu_srb, ue, deliver_pdu_srb, ue, 12, t_Reordering, -1, - 0, 0, - NULL, NULL); + ciphering_algorithm, + integrity_algorithm, + ciphering_key, + integrity_key); nr_pdcp_ue_add_srb_pdcp_entity(ue, srb_id, pdcp_srb); LOG_D(PDCP, "%s:%d:%s: added srb %d to ue rnti %x\n", __FILE__, __LINE__, __FUNCTION__, srb_id, rnti); @@ -803,12 +821,27 @@ static void add_drb_am(int is_gnb, int rnti, struct NR_DRB_ToAddMod *s, int sn_size_dl = decode_sn_size_dl(*s->pdcp_Config->drb->pdcp_SN_SizeDL); int discard_timer = decode_discard_timer(*s->pdcp_Config->drb->discardTimer); + int has_integrity; + int has_ciphering; + /* if pdcp_Config->t_Reordering is not present, it means infinity (-1) */ int t_reordering = -1; if (s->pdcp_Config->t_Reordering != NULL) { t_reordering = decode_t_reordering(*s->pdcp_Config->t_Reordering); } + if (s->pdcp_Config->drb != NULL + && s->pdcp_Config->drb->integrityProtection != NULL) + has_integrity = 1; + else + has_integrity = 0; + + if (s->pdcp_Config->ext1 != NULL + && s->pdcp_Config->ext1->cipheringDisabled != NULL) + has_ciphering = 0; + else + has_ciphering = 1; + if ((!s->cnAssociation) || s->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_NOTHING) { LOG_E(PDCP,"%s:%d:%s: fatal, cnAssociation is missing or present is NR_DRB_ToAddMod__cnAssociation_PR_NOTHING\n",__FILE__,__LINE__,__FUNCTION__); exit(-1); @@ -829,10 +862,6 @@ static void add_drb_am(int is_gnb, int rnti, struct NR_DRB_ToAddMod *s, has_sdap = 1; has_sdapULheader = s->cnAssociation->choice.sdap_Config->sdap_HeaderUL == NR_SDAP_Config__sdap_HeaderUL_present ? 1 : 0; has_sdapDLheader = s->cnAssociation->choice.sdap_Config->sdap_HeaderDL == NR_SDAP_Config__sdap_HeaderDL_present ? 1 : 0; - if (has_sdapDLheader==1) { - LOG_E(PDCP,"%s:%d:%s: fatal, no support for SDAP DL yet\n",__FILE__,__LINE__,__FUNCTION__); - exit(-1); - } } /* TODO(?): accept different UL and DL SN sizes? */ if (sn_size_ul != sn_size_dl) { @@ -850,15 +879,17 @@ static void add_drb_am(int is_gnb, int rnti, struct NR_DRB_ToAddMod *s, nr_pdcp_manager_lock(nr_pdcp_ue_manager); ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, rnti); if (ue->drb[drb_id-1] != NULL) { - LOG_D(PDCP, "%s:%d:%s: warning DRB %d already exist for ue %d, do nothing\n", + LOG_W(PDCP, "%s:%d:%s: warning DRB %d already exist for ue %d, do nothing\n", __FILE__, __LINE__, __FUNCTION__, drb_id, rnti); } else { pdcp_drb = new_nr_pdcp_entity(NR_PDCP_DRB_AM, is_gnb, drb_id,pdusession_id,has_sdap, has_sdapULheader,has_sdapDLheader, deliver_sdu_drb, ue, deliver_pdu_drb, ue, sn_size_dl, t_reordering, discard_timer, - ciphering_algorithm, integrity_algorithm, - ciphering_key, integrity_key); + has_ciphering ? ciphering_algorithm : 0, + has_integrity ? integrity_algorithm : 0, + has_ciphering ? ciphering_key : NULL, + has_integrity ? integrity_key : NULL); nr_pdcp_ue_add_drb_pdcp_entity(ue, drb_id, pdcp_drb); LOG_D(PDCP, "%s:%d:%s: added drb %d to ue rnti %x\n", __FILE__, __LINE__, __FUNCTION__, drb_id, rnti); @@ -902,9 +933,7 @@ boolean_t nr_rrc_pdcp_config_asn1_req( uint8_t *const kRRCint, uint8_t *const kUPenc, uint8_t *const kUPint -#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) ,LTE_PMCH_InfoList_r9_t *pmch_InfoList_r9 -#endif ,rb_id_t *const defaultDRB, struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_bearer2add_list) //struct NR_RLC_Config *rlc_Config) @@ -932,7 +961,9 @@ boolean_t nr_rrc_pdcp_config_asn1_req( if (srb2add_list != NULL) { for (i = 0; i < srb2add_list->list.count; i++) { - add_srb(ctxt_pP->enb_flag,rnti, srb2add_list->list.array[i]); + add_srb(ctxt_pP->enb_flag,rnti, srb2add_list->list.array[i], + security_modeP & 0x0f, (security_modeP >> 4) & 0x0f, + kRRCenc, kRRCint); } } @@ -972,9 +1003,7 @@ boolean_t rrc_pdcp_config_asn1_req( uint8_t *const kRRCenc, uint8_t *const kRRCint, uint8_t *const kUPenc -#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) ,LTE_PMCH_InfoList_r9_t *pmch_InfoList_r9 -#endif ,rb_id_t *const defaultDRB) { return 0; diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index 17af5611f1..7d2ce30494 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -270,7 +270,7 @@ mac_rlc_status_resp_t mac_rlc_status_ind( + buf_stat.retx_size + buf_stat.tx_size; } else { - if (!(frameP%128)) //to supress this warning message + if (!(frameP%128)) //to suppress this warning message LOG_W(RLC, "[%s] Radio Bearer (channel ID %d) is NULL for UE with rntiP %x\n", __FUNCTION__, channel_idP, rntiP); ret.bytes_in_buffer = 0; } @@ -334,6 +334,8 @@ rlc_buffer_occupancy_t mac_rlc_get_buffer_occupancy_ind( + buf_stat.retx_size + buf_stat.tx_size; } else { + if (!(frameP%128)) //to suppress this warning message + LOG_W(RLC, "[%s] Radio Bearer (channel ID %d) is NULL for UE with rntiP %x\n", __FUNCTION__, channel_idP, rntiP); ret = 0; } @@ -399,15 +401,22 @@ int rlc_module_init(int enb_flag) { static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; static int inited = 0; + static int inited_ue = 0; if (pthread_mutex_lock(&lock)) abort(); - if (inited) { - LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + if (enb_flag == 1 && inited) { + LOG_E(RLC, "%s:%d:%s: fatal, inited already 1\n", __FILE__, __LINE__, __FUNCTION__); exit(1); } - inited = 1; + if (enb_flag == 0 && inited_ue) { + LOG_E(RLC, "%s:%d:%s: fatal, inited_ue already 1\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + if (enb_flag == 1) inited = 1; + if (enb_flag == 0) inited_ue = 1; nr_rlc_ue_manager = new_nr_rlc_ue_manager(enb_flag); @@ -962,16 +971,16 @@ rlc_op_status_t nr_rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt if ((drb2add_listP != NULL) && (rlc_bearer2add_list != NULL)) { for (i = 0; i < drb2add_listP->list.count; i++) { if (rlc_bearer2add_list != NULL) { - for(j = 0; j < rlc_bearer2add_list->list.count; j++){ - if(rlc_bearer2add_list->list.array[j]->servedRadioBearer != NULL){ - if(rlc_bearer2add_list->list.array[j]->servedRadioBearer->present == NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity){ - if(drb2add_listP->list.array[i]->drb_Identity == rlc_bearer2add_list->list.array[j]->servedRadioBearer->choice.drb_Identity){ - add_drb(rnti, drb2add_listP->list.array[i], rlc_bearer2add_list->list.array[j]); + for(j = 0; j < rlc_bearer2add_list->list.count; j++){ + if(rlc_bearer2add_list->list.array[j]->servedRadioBearer != NULL){ + if(rlc_bearer2add_list->list.array[j]->servedRadioBearer->present == NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity){ + if(drb2add_listP->list.array[i]->drb_Identity == rlc_bearer2add_list->list.array[j]->servedRadioBearer->choice.drb_Identity){ + add_drb(rnti, drb2add_listP->list.array[i], rlc_bearer2add_list->list.array[j]); + } } - } + } } } - } } } diff --git a/openair2/RRC/LTE/rrc_UE.c b/openair2/RRC/LTE/rrc_UE.c index b2230df623..30fb20b727 100644 --- a/openair2/RRC/LTE/rrc_UE.c +++ b/openair2/RRC/LTE/rrc_UE.c @@ -2969,6 +2969,12 @@ int decode_SIB1( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index, UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIwindowsize = siWindowLength_int[sib1->si_WindowLength]; LOG_I( RRC, "[FRAME unknown][RRC_UE][MOD %02"PRIu8"][][--- MAC_CONFIG_REQ (SIB1 params eNB %"PRIu8") --->][MAC_UE][MOD %02"PRIu8"][]\n", ctxt_pP->module_id, eNB_index, ctxt_pP->module_id ); + /* pointers to SIperiod inthe Info struct points to a packed structure + * Using these possibly unaligned pointers in a function call may trigger alignment errors at run time and + * gcc, from v9, now warns about it. fix these warnings by removing the indirection on data + * Not sure if SiPeriod can be modified, reassign after function call for security + */ + uint16_t Aligned_SIperiod = UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIperiod; rrc_mac_config_req_ue(ctxt_pP->module_id, 0, eNB_index, (LTE_RadioResourceConfigCommonSIB_t *)NULL, (struct LTE_PhysicalConfigDedicated *)NULL, @@ -2981,7 +2987,7 @@ int decode_SIB1( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index, UE_rrc_inst[ctxt_pP->module_id].sib1[eNB_index]->tdd_Config, (LTE_MobilityControlInfo_t *) NULL, &UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIwindowsize, - &UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIperiod, + &Aligned_SIperiod, NULL, NULL, NULL, @@ -2995,6 +3001,7 @@ int decode_SIB1( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index, (struct LTE_NonMBSFN_SubframeConfig_r14 *)NULL, (LTE_MBSFN_AreaInfoList_r9_t *)NULL ); + UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIperiod=Aligned_SIperiod; LOG_I(RRC,"Setting SIStatus bit 0 to 1\n"); UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus = 1; UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIB1systemInfoValueTag = sib1->systemInfoValueTag; diff --git a/openair2/RRC/LTE/rrc_defs.h b/openair2/RRC/LTE/rrc_defs.h index 1c02c3de46..f5b1db8b8c 100644 --- a/openair2/RRC/LTE/rrc_defs.h +++ b/openair2/RRC/LTE/rrc_defs.h @@ -364,7 +364,7 @@ typedef struct UE_RRC_INFO_s { uint8_t SIwindowsize_MBMS; //!< Corresponds to the SIB1 si-WindowLength parameter. The unit is ms. Possible values are (final): 1,2,5,10,15,20,40 uint8_t handoverTarget; HO_STATE_t ho_state; - uint16_t SIperiod; //!< Corresponds to the SIB1 si-Periodicity parameter (multiplied by 10). Possible values are (final): 80,160,320,640,1280,2560,5120 + uint16_t SIperiod ; //!< Corresponds to the SIB1 si-Periodicity parameter (multiplied by 10). Possible values are (final): 80,160,320,640,1280,2560,5120 uint16_t SIperiod_MBMS; //!< Corresponds to the SIB1-MBMS si-Periodicity parameter (multiplied by 10). Possible values are (final): 80,160,320,640,1280,2560,5120 TODO unsigned short UE_index; uint32_t T300_active; diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c index abd015878e..a2115763cc 100644 --- a/openair2/RRC/LTE/rrc_eNB.c +++ b/openair2/RRC/LTE/rrc_eNB.c @@ -3618,9 +3618,7 @@ void rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t NULL, NULL, NULL -#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) , (LTE_PMCH_InfoList_r9_t *) NULL -#endif , NULL); /* Refresh SRBs/DRBs */ @@ -3629,11 +3627,9 @@ void rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t *SRB_configList2, // NULL, *DRB_configList, NULL -#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) , (LTE_PMCH_InfoList_r9_t *) NULL, 0, 0 -#endif ); } @@ -6331,9 +6327,7 @@ rrc_eNB_generate_HO_RRCConnectionReconfiguration(const protocol_ctxt_t *const ct NULL, NULL, NULL -#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) , (LTE_PMCH_InfoList_r9_t *) NULL -#endif , NULL); /* Refresh SRBs/DRBs */ @@ -6342,11 +6336,9 @@ rrc_eNB_generate_HO_RRCConnectionReconfiguration(const protocol_ctxt_t *const ct *SRB_configList2, // NULL, *DRB_configList, NULL -#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) , (LTE_PMCH_InfoList_r9_t *) NULL, 0, 0 -#endif ); } diff --git a/openair2/RRC/NR/L2_nr_interface.c b/openair2/RRC/NR/L2_nr_interface.c index dd9a5bb188..d2d761f817 100644 --- a/openair2/RRC/NR/L2_nr_interface.c +++ b/openair2/RRC/NR/L2_nr_interface.c @@ -285,7 +285,7 @@ int8_t mac_rrc_nr_data_req(const module_id_t Mod_idP, LOG_D(NR_RRC,"[gNB %d] Frame %d CCCH request (Srb_id %ld)\n", Mod_idP, frameP, Srb_id); - AssertFatal(ue_context_p!=NULL,"failed to get ue_context\n"); + AssertFatal(ue_context_p!=NULL,"failed to get ue_context, rnti %x\n",rnti); char payload_size = ue_context_p->ue_context.Srb0.Tx_buffer.payload_size; // check if data is there for MAC @@ -332,14 +332,16 @@ int8_t nr_mac_rrc_data_ind(const module_id_t module_idP, NR_CellGroupConfig_t cellGroupConfig; NR_ServingCellConfigCommon_t *scc=RC.nrrrc[module_idP]->carrier.servingcellconfigcommon; memset(&cellGroupConfig,0,sizeof(cellGroupConfig)); - fill_initial_cellGroupConfig(rntiP,&cellGroupConfig,scc); + + fill_initial_cellGroupConfig(rntiP,&cellGroupConfig,scc,&RC.nrrrc[module_idP]->carrier); MessageDef* tmp=itti_alloc_new_message_sized(TASK_RRC_GNB, 0, F1AP_INITIAL_UL_RRC_MESSAGE, sizeof(f1ap_initial_ul_rrc_message_t) + sdu_lenP); f1ap_initial_ul_rrc_message_t *msg = &F1AP_INITIAL_UL_RRC_MESSAGE(tmp); + asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, (void *)&cellGroupConfig, msg->du2cu_rrc_container, - sizeof(msg->du2cu_rrc_container)); + 1024); //sizeof(msg->du2cu_rrc_container)); if (enc_rval.encoded == -1) { LOG_E(F1AP,"Could not encoded cellGroupConfig, failed element %s\n",enc_rval.failed_type->name); diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 7dc7ba7589..9936fa1c2a 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -451,7 +451,7 @@ uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier, ss1->monitoringSlotPeriodicityAndOffset->present = NR_SearchSpace__monitoringSlotPeriodicityAndOffset_PR_sl1; ss1->monitoringSymbolsWithinSlot = calloc(1,sizeof(*ss1->monitoringSymbolsWithinSlot)); ss1->monitoringSymbolsWithinSlot->buf = calloc(1,2); - // should be '1100 0000 0000 00'B (LSB first!), first two symols in slot, adjust if needed + // should be '1000 0000 0000 00'B (LSB first!), first symbol in slot, adjust if needed ss1->monitoringSymbolsWithinSlot->buf[1] = 0; ss1->monitoringSymbolsWithinSlot->buf[0] = (1<<7); ss1->monitoringSymbolsWithinSlot->size = 2; @@ -459,7 +459,7 @@ uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier, ss1->nrofCandidates = calloc(1,sizeof(*ss1->nrofCandidates)); ss1->nrofCandidates->aggregationLevel1 = NR_SearchSpace__nrofCandidates__aggregationLevel1_n0; ss1->nrofCandidates->aggregationLevel2 = NR_SearchSpace__nrofCandidates__aggregationLevel2_n0; - ss1->nrofCandidates->aggregationLevel4 = NR_SearchSpace__nrofCandidates__aggregationLevel4_n4; + ss1->nrofCandidates->aggregationLevel4 = NR_SearchSpace__nrofCandidates__aggregationLevel4_n2; ss1->nrofCandidates->aggregationLevel8 = NR_SearchSpace__nrofCandidates__aggregationLevel8_n0; ss1->nrofCandidates->aggregationLevel16 = NR_SearchSpace__nrofCandidates__aggregationLevel16_n0; ss1->searchSpaceType = calloc(1,sizeof(*ss1->searchSpaceType)); @@ -987,8 +987,9 @@ uint8_t do_RRCReject(uint8_t Mod_id, } void fill_initial_SpCellConfig(rnti_t rnti, - NR_SpCellConfig_t *SpCellConfig, - NR_ServingCellConfigCommon_t *scc) { + NR_SpCellConfig_t *SpCellConfig, + NR_ServingCellConfigCommon_t *scc, + rrc_gNB_carrier_data_t *carrier) { SpCellConfig->servCellIndex = NULL; SpCellConfig->reconfigurationWithSync = NULL; @@ -1027,7 +1028,134 @@ void fill_initial_SpCellConfig(rnti_t rnti, pucchres0->format.choice.format0->nrofSymbols=1; pucchres0->format.choice.format0->startingSymbolIndex=13; ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres0); - + initialUplinkBWP->pusch_Config = calloc(1,sizeof(*initialUplinkBWP->pusch_Config)); + initialUplinkBWP->pusch_Config->present = NR_SetupRelease_PUSCH_Config_PR_setup; + NR_PUSCH_Config_t *pusch_Config = calloc(1,sizeof(*pusch_Config)); + initialUplinkBWP->pusch_Config->choice.setup = pusch_Config; + pusch_Config->dataScramblingIdentityPUSCH = NULL; + pusch_Config->txConfig=calloc(1,sizeof(*pusch_Config->txConfig)); + *pusch_Config->txConfig= NR_PUSCH_Config__txConfig_codebook; + pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA = NULL; + pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB = calloc(1,sizeof(*pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB)); + pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->present = NR_SetupRelease_DMRS_UplinkConfig_PR_setup; + pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup = calloc(1,sizeof(*pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup)); + NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup; + NR_DMRS_UplinkConfig->dmrs_Type = NULL; + NR_DMRS_UplinkConfig->dmrs_AdditionalPosition = NULL; /*calloc(1,sizeof(*NR_DMRS_UplinkConfig->dmrs_AdditionalPosition)); + *NR_DMRS_UplinkConfig->dmrs_AdditionalPosition = NR_DMRS_UplinkConfig__dmrs_AdditionalPosition_pos0;*/ + NR_DMRS_UplinkConfig->phaseTrackingRS=NULL; + NR_DMRS_UplinkConfig->maxLength=NULL; + NR_DMRS_UplinkConfig->transformPrecodingDisabled = calloc(1,sizeof(*NR_DMRS_UplinkConfig->transformPrecodingDisabled)); + NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID0 = NULL; + NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID1 = NULL; + NR_DMRS_UplinkConfig->transformPrecodingEnabled = NULL; + pusch_Config->pusch_PowerControl = calloc(1,sizeof(*pusch_Config->pusch_PowerControl)); + pusch_Config->pusch_PowerControl->tpc_Accumulation = NULL; + pusch_Config->pusch_PowerControl->msg3_Alpha = calloc(1,sizeof(*pusch_Config->pusch_PowerControl->msg3_Alpha)); + *pusch_Config->pusch_PowerControl->msg3_Alpha = NR_Alpha_alpha1; + pusch_Config->pusch_PowerControl->p0_NominalWithoutGrant = calloc(1,sizeof(*pusch_Config->pusch_PowerControl->p0_NominalWithoutGrant)); + *pusch_Config->pusch_PowerControl->p0_NominalWithoutGrant = -76; + pusch_Config->pusch_PowerControl->p0_AlphaSets = calloc(1,sizeof(*pusch_Config->pusch_PowerControl->p0_AlphaSets)); + NR_P0_PUSCH_AlphaSet_t *aset = calloc(1,sizeof(*aset)); + aset->p0_PUSCH_AlphaSetId=0; + aset->p0=calloc(1,sizeof(*aset->p0)); + *aset->p0 = 0; + aset->alpha=calloc(1,sizeof(*aset->alpha)); + *aset->alpha=NR_Alpha_alpha1; + ASN_SEQUENCE_ADD(&pusch_Config->pusch_PowerControl->p0_AlphaSets->list,aset); + pusch_Config->pusch_PowerControl->pathlossReferenceRSToAddModList = calloc(1,sizeof(*pusch_Config->pusch_PowerControl->pathlossReferenceRSToAddModList)); + NR_PUSCH_PathlossReferenceRS_t *plrefRS = calloc(1,sizeof(*plrefRS)); + plrefRS->pusch_PathlossReferenceRS_Id=0; + plrefRS->referenceSignal.present = NR_PathlossReferenceRS_Config_PR_ssb_Index; + plrefRS->referenceSignal.choice.ssb_Index = 0; + ASN_SEQUENCE_ADD(&pusch_Config->pusch_PowerControl->pathlossReferenceRSToAddModList->list,plrefRS); + pusch_Config->pusch_PowerControl->pathlossReferenceRSToReleaseList = NULL; + pusch_Config->pusch_PowerControl->twoPUSCH_PC_AdjustmentStates = NULL; + pusch_Config->pusch_PowerControl->deltaMCS = NULL; + pusch_Config->pusch_PowerControl->sri_PUSCH_MappingToAddModList = calloc(1,sizeof(*pusch_Config->pusch_PowerControl->sri_PUSCH_MappingToAddModList)); + NR_SRI_PUSCH_PowerControl_t *sriPUSCHPC=calloc(1,sizeof(*sriPUSCHPC)); + sriPUSCHPC->sri_PUSCH_PowerControlId=0; + sriPUSCHPC->sri_PUSCH_PathlossReferenceRS_Id=0; + sriPUSCHPC->sri_P0_PUSCH_AlphaSetId=0; + sriPUSCHPC->sri_PUSCH_ClosedLoopIndex=NR_SRI_PUSCH_PowerControl__sri_PUSCH_ClosedLoopIndex_i0; + ASN_SEQUENCE_ADD(&pusch_Config->pusch_PowerControl->sri_PUSCH_MappingToAddModList->list,sriPUSCHPC); + pusch_Config->pusch_PowerControl->sri_PUSCH_MappingToReleaseList = NULL; + pusch_Config->frequencyHopping=NULL; + pusch_Config->frequencyHoppingOffsetLists=NULL; + pusch_Config->resourceAllocation = NR_PUSCH_Config__resourceAllocation_resourceAllocationType1; + pusch_Config->pusch_TimeDomainAllocationList = NULL; + pusch_Config->pusch_AggregationFactor=NULL; + pusch_Config->mcs_Table=NULL; + pusch_Config->mcs_TableTransformPrecoder=NULL; + pusch_Config->transformPrecoder= NULL; + if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder == NULL) { + pusch_Config->transformPrecoder=calloc(1,sizeof(*pusch_Config->transformPrecoder)); + *pusch_Config->transformPrecoder = NR_PUSCH_Config__transformPrecoder_disabled; + } + pusch_Config->codebookSubset=calloc(1,sizeof(*pusch_Config->codebookSubset)); + *pusch_Config->codebookSubset = NR_PUSCH_Config__codebookSubset_nonCoherent; + pusch_Config->maxRank=calloc(1,sizeof(*pusch_Config->maxRank)); + *pusch_Config->maxRank= 1; + pusch_Config->rbg_Size=NULL; + pusch_Config->uci_OnPUSCH=NULL; + pusch_Config->tp_pi2BPSK=NULL; + + initialUplinkBWP->srs_Config = calloc(1,sizeof(*initialUplinkBWP->srs_Config)); + initialUplinkBWP->srs_Config->present = NR_SetupRelease_SRS_Config_PR_setup; + NR_SRS_Config_t *srs_Config = calloc(1,sizeof(*srs_Config)); + initialUplinkBWP->srs_Config->choice.setup=srs_Config; + srs_Config->srs_ResourceSetToReleaseList=NULL; + srs_Config->srs_ResourceSetToAddModList=calloc(1,sizeof(*srs_Config->srs_ResourceSetToAddModList)); + NR_SRS_ResourceSet_t *srs_resset0=calloc(1,sizeof(*srs_resset0)); + srs_resset0->srs_ResourceSetId = 0; + srs_resset0->srs_ResourceIdList=calloc(1,sizeof(*srs_resset0->srs_ResourceIdList)); + NR_SRS_ResourceId_t *srs_resset0_id=calloc(1,sizeof(*srs_resset0_id)); + *srs_resset0_id=0; + ASN_SEQUENCE_ADD(&srs_resset0->srs_ResourceIdList->list,srs_resset0_id); + srs_Config->srs_ResourceToReleaseList=NULL; + srs_resset0->resourceType.present = NR_SRS_ResourceSet__resourceType_PR_aperiodic; + srs_resset0->resourceType.choice.aperiodic = calloc(1,sizeof(*srs_resset0->resourceType.choice.aperiodic)); + srs_resset0->resourceType.choice.aperiodic->aperiodicSRS_ResourceTrigger=1; + srs_resset0->resourceType.choice.aperiodic->csi_RS=NULL; + srs_resset0->resourceType.choice.aperiodic->slotOffset= calloc(1,sizeof(*srs_resset0->resourceType.choice.aperiodic->slotOffset)); + *srs_resset0->resourceType.choice.aperiodic->slotOffset=2; + srs_resset0->resourceType.choice.aperiodic->ext1=NULL; + srs_resset0->usage=NR_SRS_ResourceSet__usage_codebook; + srs_resset0->alpha = calloc(1,sizeof(*srs_resset0->alpha)); + *srs_resset0->alpha = NR_Alpha_alpha1; + srs_resset0->p0=calloc(1,sizeof(*srs_resset0->p0)); + *srs_resset0->p0=-80; + srs_resset0->pathlossReferenceRS=NULL; + srs_resset0->srs_PowerControlAdjustmentStates=NULL; + ASN_SEQUENCE_ADD(&srs_Config->srs_ResourceSetToAddModList->list,srs_resset0); + srs_Config->srs_ResourceToReleaseList=NULL; + srs_Config->srs_ResourceToAddModList=calloc(1,sizeof(*srs_Config->srs_ResourceToAddModList)); + NR_SRS_Resource_t *srs_res0=calloc(1,sizeof(*srs_res0)); + srs_res0->srs_ResourceId=0; + srs_res0->nrofSRS_Ports=NR_SRS_Resource__nrofSRS_Ports_port1; + srs_res0->ptrs_PortIndex=NULL; + srs_res0->transmissionComb.present=NR_SRS_Resource__transmissionComb_PR_n2; + srs_res0->transmissionComb.choice.n2=calloc(1,sizeof(*srs_res0->transmissionComb.choice.n2)); + srs_res0->transmissionComb.choice.n2->combOffset_n2=0; + srs_res0->transmissionComb.choice.n2->cyclicShift_n2=0; + srs_res0->resourceMapping.startPosition=2; + srs_res0->resourceMapping.nrofSymbols=NR_SRS_Resource__resourceMapping__nrofSymbols_n1; + srs_res0->resourceMapping.repetitionFactor=NR_SRS_Resource__resourceMapping__repetitionFactor_n1; + srs_res0->freqDomainPosition=0; + srs_res0->freqDomainShift=0; + srs_res0->freqHopping.c_SRS = 0; + srs_res0->freqHopping.b_SRS=0; + srs_res0->freqHopping.b_hop=0; + srs_res0->groupOrSequenceHopping=NR_SRS_Resource__groupOrSequenceHopping_neither; + srs_res0->resourceType.present= NR_SRS_Resource__resourceType_PR_aperiodic; + srs_res0->resourceType.choice.aperiodic=calloc(1,sizeof(*srs_res0->resourceType.choice.aperiodic)); + srs_res0->sequenceId=40; + srs_res0->spatialRelationInfo=calloc(1,sizeof(*srs_res0->spatialRelationInfo)); + srs_res0->spatialRelationInfo->servingCellId=NULL; + srs_res0->spatialRelationInfo->referenceSignal.present=NR_SRS_SpatialRelationInfo__referenceSignal_PR_csi_RS_Index; + srs_res0->spatialRelationInfo->referenceSignal.choice.csi_RS_Index=0; + ASN_SEQUENCE_ADD(&srs_Config->srs_ResourceToAddModList->list,srs_res0); + // configure Scheduling request // 40 slot period pucch_Config->schedulingRequestResourceToAddModList = calloc(1,sizeof(*pucch_Config->schedulingRequestResourceToAddModList)); @@ -1036,20 +1164,30 @@ void fill_initial_SpCellConfig(rnti_t rnti, schedulingRequestResourceConfig->schedulingRequestID= 0; schedulingRequestResourceConfig->periodicityAndOffset = calloc(1,sizeof(*schedulingRequestResourceConfig->periodicityAndOffset)); schedulingRequestResourceConfig->periodicityAndOffset->present = NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl40; - // note: make sure that there is no issue here. Later choose the RNTI accordingly. - // Here we would be limited to 8 UEs on this resource (2 Frames 30 kHz SCS, 5 ms TDD periodicity => slots 8,9,18,19,28,29,38,39). + // note: make sure that there is no issue here. Later choose the RNTI accordingly. + // Here we would be limited to 3 UEs on this resource (1 1/2 Frames 30 kHz SCS, 5 ms TDD periodicity => slots 7,8,9). // This should be a temporary resource until the first RRCReconfiguration gives new pucch resources. // Check for above configuration and exit for now if it is not the case AssertFatal(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.subcarrierSpacing==NR_SubcarrierSpacing_kHz30, - "SCS != 30kHz\n"); + "SCS != 30kHz\n"); AssertFatal(scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity==NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms5, "TDD period != 5ms : %ld\n",scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity); - schedulingRequestResourceConfig->periodicityAndOffset->choice.sl40 = 10*((rnti>>1)&3) + (rnti&2); + schedulingRequestResourceConfig->periodicityAndOffset->choice.sl40 = 8 + 10*((rnti>>1)&3) + (rnti&1); schedulingRequestResourceConfig->resource = calloc(1,sizeof(*schedulingRequestResourceConfig->resource)); *schedulingRequestResourceConfig->resource = 0; ASN_SEQUENCE_ADD(&pucch_Config->schedulingRequestResourceToAddModList->list,schedulingRequestResourceConfig); + pucch_Config->dl_DataToUL_ACK = calloc(1,sizeof(*pucch_Config->dl_DataToUL_ACK)); + long *delay[8]; + for (int i=0;i<8;i++) { + delay[i] = calloc(1,sizeof(*delay[i])); + AssertFatal(carrier->minRXTXTIMEpdsch >=2 && carrier->minRXTXTIMEpdsch <7, + "check minRXTXTIMEpdsch %d\n",carrier->minRXTXTIMEpdsch); + *delay[i] = (i+carrier->minRXTXTIMEpdsch); + ASN_SEQUENCE_ADD(&pucch_Config->dl_DataToUL_ACK->list,delay[i]); + } + SpCellConfig->spCellConfigDedicated->initialDownlinkBWP = calloc(1,sizeof(*SpCellConfig->spCellConfigDedicated->initialDownlinkBWP)); NR_BWP_DownlinkDedicated_t *bwp_Dedicated = SpCellConfig->spCellConfigDedicated->initialDownlinkBWP; bwp_Dedicated->pdcch_Config=calloc(1,sizeof(*bwp_Dedicated->pdcch_Config)); @@ -1057,12 +1195,53 @@ void fill_initial_SpCellConfig(rnti_t rnti, bwp_Dedicated->pdcch_Config->choice.setup = calloc(1,sizeof(*bwp_Dedicated->pdcch_Config->choice.setup)); bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList = calloc(1,sizeof(*bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList)); + + bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList = calloc(1,sizeof(*bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList)); + + NR_ControlResourceSet_t *coreset = calloc(1,sizeof(*coreset)); + coreset->controlResourceSetId=1; + // frequency domain resources depends on BWP size + // options are 24, 48 or 96 + coreset->frequencyDomainResources.buf = calloc(1,6); + if (0) { + int curr_bwp = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; + if (curr_bwp < 48) + coreset->frequencyDomainResources.buf[0] = 0xf0; + else + coreset->frequencyDomainResources.buf[0] = 0xff; + if (curr_bwp < 96) + coreset->frequencyDomainResources.buf[1] = 0; + else + coreset->frequencyDomainResources.buf[1] = 0xff; + } else { + coreset->frequencyDomainResources.buf[0] = 0xf0; + coreset->frequencyDomainResources.buf[1] = 0; + } + coreset->frequencyDomainResources.buf[2] = 0; + coreset->frequencyDomainResources.buf[3] = 0; + coreset->frequencyDomainResources.buf[4] = 0; + coreset->frequencyDomainResources.buf[5] = 0; + coreset->frequencyDomainResources.size = 6; + coreset->frequencyDomainResources.bits_unused = 3; + coreset->duration=1; + coreset->cce_REG_MappingType.present = NR_ControlResourceSet__cce_REG_MappingType_PR_nonInterleaved; + coreset->precoderGranularity = NR_ControlResourceSet__precoderGranularity_sameAsREG_bundle; + + coreset->tci_StatesPDCCH_ToAddList=NULL; + coreset->tci_StatesPDCCH_ToReleaseList = NULL; + coreset->tci_PresentInDCI = NULL; + coreset->pdcch_DMRS_ScramblingID = NULL; + + ASN_SEQUENCE_ADD(&bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list, + coreset); + + bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList = calloc(1,sizeof(*bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList)); NR_SearchSpace_t *ss2 = calloc(1,sizeof(*ss2)); ss2->searchSpaceId=2; ss2->controlResourceSetId=calloc(1,sizeof(*ss2->controlResourceSetId)); - *ss2->controlResourceSetId=0; + *ss2->controlResourceSetId=1; ss2->monitoringSlotPeriodicityAndOffset=calloc(1,sizeof(*ss2->monitoringSlotPeriodicityAndOffset)); ss2->monitoringSlotPeriodicityAndOffset->present = NR_SearchSpace__monitoringSlotPeriodicityAndOffset_PR_sl1; ss2->monitoringSlotPeriodicityAndOffset->choice.sl1=(NULL_t)0; @@ -1075,19 +1254,64 @@ void fill_initial_SpCellConfig(rnti_t rnti, ss2->monitoringSymbolsWithinSlot->buf[1]=0x0; ss2->nrofCandidates=calloc(1,sizeof(*ss2->nrofCandidates)); ss2->nrofCandidates->aggregationLevel1 = NR_SearchSpace__nrofCandidates__aggregationLevel1_n0; - ss2->nrofCandidates->aggregationLevel2 = NR_SearchSpace__nrofCandidates__aggregationLevel2_n0; + ss2->nrofCandidates->aggregationLevel2 = NR_SearchSpace__nrofCandidates__aggregationLevel2_n2; ss2->nrofCandidates->aggregationLevel4 = NR_SearchSpace__nrofCandidates__aggregationLevel4_n1; ss2->nrofCandidates->aggregationLevel8 = NR_SearchSpace__nrofCandidates__aggregationLevel8_n0; ss2->nrofCandidates->aggregationLevel16 = NR_SearchSpace__nrofCandidates__aggregationLevel16_n0; ss2->searchSpaceType=calloc(1,sizeof(*ss2->searchSpaceType)); ss2->searchSpaceType->present = NR_SearchSpace__searchSpaceType_PR_ue_Specific; ss2->searchSpaceType->choice.ue_Specific = calloc(1,sizeof(*ss2->searchSpaceType->choice.ue_Specific)); - ss2->searchSpaceType->choice.ue_Specific->dci_Formats=NR_SearchSpace__searchSpaceType__ue_Specific__dci_Formats_formats0_0_And_1_0; + ss2->searchSpaceType->choice.ue_Specific->dci_Formats=NR_SearchSpace__searchSpaceType__ue_Specific__dci_Formats_formats0_1_And_1_1; ASN_SEQUENCE_ADD(&bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list, ss2); - + bwp_Dedicated->pdsch_Config=calloc(1,sizeof(*bwp_Dedicated->pdsch_Config)); + bwp_Dedicated->pdsch_Config->present = NR_SetupRelease_PDSCH_Config_PR_setup; + bwp_Dedicated->pdsch_Config->choice.setup = calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup)); + bwp_Dedicated->pdsch_Config->choice.setup->dataScramblingIdentityPDSCH = NULL; + bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA = calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA)); + bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->present= NR_SetupRelease_DMRS_DownlinkConfig_PR_setup; + bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup = calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup)); + + bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type=NULL; + bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->maxLength=NULL; + + bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition)); + *bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = NR_DMRS_DownlinkConfig__dmrs_AdditionalPosition_pos1; + bwp_Dedicated->pdsch_Config->choice.setup->resourceAllocation = NR_PDSCH_Config__resourceAllocation_resourceAllocationType1; + bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.present = NR_PDSCH_Config__prb_BundlingType_PR_staticBundling; + bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling = calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling)); + bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize = + calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize)); + *bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize = NR_PDSCH_Config__prb_BundlingType__staticBundling__bundleSize_wideband; + + bwp_Dedicated->pdsch_Config->choice.setup->tci_StatesToAddModList=calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->tci_StatesToAddModList)); + NR_TCI_State_t *tcic; + + tcic=calloc(1,sizeof(*tcic)); + tcic->tci_StateId=0; + tcic->qcl_Type1.cell=NULL; + tcic->qcl_Type1.bwp_Id=NULL; + tcic->qcl_Type1.referenceSignal.present = NR_QCL_Info__referenceSignal_PR_ssb; + tcic->qcl_Type1.referenceSignal.choice.ssb = 0; + tcic->qcl_Type1.qcl_Type=NR_QCL_Info__qcl_Type_typeD; + + ASN_SEQUENCE_ADD(&bwp_Dedicated->pdsch_Config->choice.setup->tci_StatesToAddModList->list,tcic); + SpCellConfig->spCellConfigDedicated->tag_Id=0; + SpCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig=calloc(1,sizeof(*SpCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig)); + NR_PDSCH_ServingCellConfig_t *pdsch_servingcellconfig = calloc(1,sizeof(*pdsch_servingcellconfig)); + SpCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->present = NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup; + SpCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup = pdsch_servingcellconfig; + pdsch_servingcellconfig->codeBlockGroupTransmission = NULL; + pdsch_servingcellconfig->xOverhead = NULL; + pdsch_servingcellconfig->nrofHARQ_ProcessesForPDSCH = calloc(1, sizeof(*pdsch_servingcellconfig->nrofHARQ_ProcessesForPDSCH)); + *pdsch_servingcellconfig->nrofHARQ_ProcessesForPDSCH = NR_PDSCH_ServingCellConfig__nrofHARQ_ProcessesForPDSCH_n16; + pdsch_servingcellconfig->pucch_Cell= NULL; + pdsch_servingcellconfig->ext1=calloc(1,sizeof(*pdsch_servingcellconfig->ext1)); + pdsch_servingcellconfig->ext1->maxMIMO_Layers = calloc(1,sizeof(*pdsch_servingcellconfig->ext1->maxMIMO_Layers)); + *pdsch_servingcellconfig->ext1->maxMIMO_Layers = 2; + } void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGroupConfig_t *ue_context_mastercellGroup, uint8_t SRB_config_present, uint8_t DRB_config_present) { @@ -1164,7 +1388,7 @@ void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGr rlc_Config_drb->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms80; rlc_Config_drb->choice.am->ul_AM_RLC.pollPDU = NR_PollPDU_p64; rlc_Config_drb->choice.am->ul_AM_RLC.pollByte = NR_PollByte_kB125; - rlc_Config_drb->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t4; + rlc_Config_drb->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t8; rlc_BearerConfig_drb->rlc_Config = rlc_Config_drb; logicalChannelConfig_drb = calloc(1, sizeof(NR_LogicalChannelConfig_t)); logicalChannelConfig_drb->ul_SpecificParameters = calloc(1, sizeof(*logicalChannelConfig_drb->ul_SpecificParameters)); @@ -1192,8 +1416,9 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGroupC } void fill_initial_cellGroupConfig(rnti_t rnti, - NR_CellGroupConfig_t *cellGroupConfig, - NR_ServingCellConfigCommon_t *scc) { + NR_CellGroupConfig_t *cellGroupConfig, + NR_ServingCellConfigCommon_t *scc, + rrc_gNB_carrier_data_t *carrier) { NR_RLC_BearerConfig_t *rlc_BearerConfig = NULL; NR_RLC_Config_t *rlc_Config = NULL; @@ -1246,15 +1471,17 @@ void fill_initial_cellGroupConfig(rnti_t rnti, /* mac CellGroup Config */ if (1) { mac_CellGroupConfig = calloc(1, sizeof(*mac_CellGroupConfig)); - mac_CellGroupConfig->schedulingRequestConfig = calloc(1, sizeof(*mac_CellGroupConfig->schedulingRequestConfig)); - mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList = CALLOC(1,sizeof(*mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList)); - struct NR_SchedulingRequestToAddMod *schedulingrequestlist; - schedulingrequestlist = CALLOC(1,sizeof(*schedulingrequestlist)); - schedulingrequestlist->schedulingRequestId = 0; - schedulingrequestlist->sr_ProhibitTimer = CALLOC(1,sizeof(*schedulingrequestlist->sr_ProhibitTimer)); - *(schedulingrequestlist->sr_ProhibitTimer) = 0; - schedulingrequestlist->sr_TransMax = 0; - ASN_SEQUENCE_ADD(&(mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList->list),schedulingrequestlist); + if (1) { + mac_CellGroupConfig->schedulingRequestConfig = calloc(1, sizeof(*mac_CellGroupConfig->schedulingRequestConfig)); + mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList = CALLOC(1,sizeof(*mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList)); + struct NR_SchedulingRequestToAddMod *schedulingrequestlist; + schedulingrequestlist = CALLOC(1,sizeof(*schedulingrequestlist)); + schedulingrequestlist->schedulingRequestId = 0; + schedulingrequestlist->sr_ProhibitTimer = CALLOC(1,sizeof(*schedulingrequestlist->sr_ProhibitTimer)); + *(schedulingrequestlist->sr_ProhibitTimer) = 0; + schedulingrequestlist->sr_TransMax = NR_SchedulingRequestToAddMod__sr_TransMax_n64; + ASN_SEQUENCE_ADD(&(mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList->list),schedulingrequestlist); + } mac_CellGroupConfig->bsr_Config = calloc(1, sizeof(*mac_CellGroupConfig->bsr_Config)); mac_CellGroupConfig->bsr_Config->periodicBSR_Timer = NR_BSR_Config__periodicBSR_Timer_sf10; mac_CellGroupConfig->bsr_Config->retxBSR_Timer = NR_BSR_Config__retxBSR_Timer_sf80; @@ -1276,13 +1503,13 @@ void fill_initial_cellGroupConfig(rnti_t rnti, physicalCellGroupConfig = calloc(1,sizeof(*physicalCellGroupConfig)); physicalCellGroupConfig->p_NR_FR1 = calloc(1,sizeof(*physicalCellGroupConfig->p_NR_FR1)); - *physicalCellGroupConfig->p_NR_FR1 = 20; + *physicalCellGroupConfig->p_NR_FR1 = 10; physicalCellGroupConfig->pdsch_HARQ_ACK_Codebook = NR_PhysicalCellGroupConfig__pdsch_HARQ_ACK_Codebook_dynamic; cellGroupConfig->physicalCellGroupConfig = physicalCellGroupConfig; cellGroupConfig->spCellConfig = calloc(1,sizeof(*cellGroupConfig->spCellConfig)); - fill_initial_SpCellConfig(rnti,cellGroupConfig->spCellConfig,scc); + fill_initial_SpCellConfig(rnti,cellGroupConfig->spCellConfig,scc,carrier); cellGroupConfig->sCellToAddModList = NULL; cellGroupConfig->sCellToReleaseList = NULL; @@ -1292,8 +1519,9 @@ void fill_initial_cellGroupConfig(rnti_t rnti, uint8_t do_RRCSetup(rrc_gNB_ue_context_t *const ue_context_pP, uint8_t *const buffer, const uint8_t transaction_id, - OCTET_STRING_t *masterCellGroup_from_DU, - NR_ServingCellConfigCommon_t *scc) + OCTET_STRING_t *masterCellGroup_from_DU, + NR_ServingCellConfigCommon_t *scc, + rrc_gNB_carrier_data_t *carrier) //------------------------------------------------------------------------------ { asn_enc_rval_t enc_rval; @@ -1360,7 +1588,7 @@ uint8_t do_RRCSetup(rrc_gNB_ue_context_t *const ue_context_pP, } else { cellGroupConfig = calloc(1, sizeof(NR_CellGroupConfig_t)); - fill_initial_cellGroupConfig(ue_context_pP->ue_context.rnti,cellGroupConfig,scc); + fill_initial_cellGroupConfig(ue_context_pP->ue_context.rnti,cellGroupConfig,scc,carrier); enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 4b248b8f1f..f4486aaf4d 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -100,11 +100,13 @@ uint8_t do_RRCReject(uint8_t Mod_id, void fill_initial_SpCellConfig(rnti_t rnti, NR_SpCellConfig_t *SpCellConfig, - NR_ServingCellConfigCommon_t *scc); + NR_ServingCellConfigCommon_t *scc, + rrc_gNB_carrier_data_t *carrier); void fill_initial_cellGroupConfig(rnti_t rnti, NR_CellGroupConfig_t *cellGroupConfig, - NR_ServingCellConfigCommon_t *scc); + NR_ServingCellConfigCommon_t *scc, + rrc_gNB_carrier_data_t *carrier); void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGroupConfig_t *ue_context_mastercellGroup); @@ -114,7 +116,8 @@ uint8_t do_RRCSetup(rrc_gNB_ue_context_t *const ue_context_pP, uint8_t *const buffer, const uint8_t transaction_id, OCTET_STRING_t *masterCellGroup_from_DU, - NR_ServingCellConfigCommon_t *scc); + NR_ServingCellConfigCommon_t *scc, + rrc_gNB_carrier_data_t *carrier); uint8_t do_NR_SecurityModeCommand( const protocol_ctxt_t *const ctxt_pP, diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 19120e8854..f33560f122 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -450,8 +450,7 @@ typedef struct { int sib1_tda; int pdsch_AntennaPorts; int pusch_AntennaPorts; - int pusch_TargetSNRx10; - int pucch_TargetSNRx10; + int minRXTXTIMEpdsch; int do_CSIRS; NR_BCCH_DL_SCH_Message_t *siblock1; NR_ServingCellConfigCommon_t *servingcellconfigcommon; @@ -474,6 +473,10 @@ typedef struct { /* nia0 = 0, nia1 = 1, ... */ int integrity_algorithms[4]; int integrity_algorithms_count; + + /* flags to enable/disable ciphering and integrity for DRBs */ + int do_drb_ciphering; + int do_drb_integrity; } nr_security_configuration_t; //---NR---(completely change)--------------------- diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index c3f415ee64..31165d8195 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -113,9 +113,7 @@ extern boolean_t nr_rrc_pdcp_config_asn1_req( uint8_t *const kRRCint, uint8_t *const kUPenc, uint8_t *const kUPint - #if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) ,LTE_PMCH_InfoList_r9_t *pmch_InfoList_r9 - #endif ,rb_id_t *const defaultDRB, struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_bearer2add_list); @@ -264,6 +262,7 @@ static void init_NR_SI(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration rrc->carrier.pusch_AntennaPorts, rrc->carrier.sib1_tda, (NR_ServingCellConfigCommon_t *)rrc->carrier.servingcellconfigcommon, + &rrc->carrier.mib, 0, 0, // WIP hardcoded rnti (NR_CellGroupConfig_t *)NULL @@ -355,6 +354,7 @@ char openair_rrc_gNB_configuration(const module_id_t gnb_mod_idP, gNB_RrcConfigu rrc->carrier.ssb_SubcarrierOffset = configuration->ssb_SubcarrierOffset; rrc->carrier.pdsch_AntennaPorts = configuration->pdsch_AntennaPorts; rrc->carrier.pusch_AntennaPorts = configuration->pusch_AntennaPorts; + rrc->carrier.minRXTXTIMEpdsch = configuration->minRXTXTIMEpdsch; rrc->carrier.sib1_tda = configuration->sib1_tda; rrc->carrier.do_CSIRS = configuration->do_CSIRS; /// System Information INIT @@ -415,6 +415,7 @@ void apply_macrlc_config(gNB_RRC_INST *rrc, rrc->carrier.pusch_AntennaPorts, rrc->carrier.sib1_tda, NULL, + NULL, 0, ue_context_pP->ue_context.rnti, get_softmodem_params()->sa ? ue_context_pP->ue_context.masterCellGroup : (NR_CellGroupConfig_t *)NULL); @@ -435,7 +436,7 @@ void apply_pdcp_config(rrc_gNB_ue_context_t *const ue_context_pP, ue_context_pP->ue_context.SRB_configList, NULL, NULL, - 0xff, + 0, NULL, NULL, NULL, @@ -457,7 +458,7 @@ rrc_gNB_generate_RRCSetup( ) //----------------------------------------------------------------------------- { - LOG_I(NR_RRC, "rrc_gNB_generate_RRCSetup \n"); + LOG_D(NR_RRC, "rrc_gNB_generate_RRCSetup \n"); MessageDef *message_p; // T(T_GNB_RRC_SETUP, @@ -466,17 +467,18 @@ rrc_gNB_generate_RRCSetup( // T_INT(ctxt_pP->subframe), // T_INT(ctxt_pP->rnti)); gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; + gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; ue_p->Srb0.Tx_buffer.payload_size = do_RRCSetup(ue_context_pP, (uint8_t *) ue_p->Srb0.Tx_buffer.Payload, rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id), masterCellGroup_from_DU, - scc); + scc,&rrc->carrier); LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)(ue_p->Srb0.Tx_buffer.Payload), ue_p->Srb0.Tx_buffer.payload_size, "[MSG] RRC Setup\n"); - gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; + switch (rrc->node_type) { case ngran_gNB_CU: // create an ITTI message @@ -485,7 +487,7 @@ rrc_gNB_generate_RRCSetup( ue_context_pP->ue_context.SRB_configList, NULL, NULL, - 0xff, + 0, NULL, NULL, NULL, @@ -589,7 +591,7 @@ rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest( (uint8_t *) ue_p->Srb0.Tx_buffer.Payload, rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id), NULL, - scc); + scc,&rrc_instance_p->carrier); LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)(ue_p->Srb0.Tx_buffer.Payload), @@ -606,6 +608,7 @@ rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest( rrc_instance_p->carrier.pusch_AntennaPorts, rrc_instance_p->carrier.sib1_tda, (NR_ServingCellConfigCommon_t *)rrc_instance_p->carrier.servingcellconfigcommon, + &rrc_instance_p->carrier.mib, 0, ue_context_pP->ue_context.rnti, (NR_CellGroupConfig_t *)NULL @@ -966,6 +969,7 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( ) //----------------------------------------------------------------------------- { + gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; NR_DRB_ToAddMod_t *DRB_config = NULL; NR_SRB_ToAddMod_t *SRB2_config = NULL; NR_SDAP_Config_t *sdap_config = NULL; @@ -1030,7 +1034,7 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( sdap_config = CALLOC(1, sizeof(NR_SDAP_Config_t)); memset(sdap_config, 0, sizeof(NR_SDAP_Config_t)); sdap_config->pdu_Session = ue_context_pP->ue_context.pduSession[i].param.pdusession_id; - sdap_config->sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_absent; + sdap_config->sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_present; sdap_config->sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_absent; sdap_config->defaultDRB = TRUE; sdap_config->mappedQoS_FlowsToAdd = calloc(1, sizeof(struct NR_SDAP_Config__mappedQoS_FlowsToAdd)); @@ -1063,9 +1067,20 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( DRB_config->pdcp_Config->moreThanOneRLC = NULL; DRB_config->pdcp_Config->t_Reordering = calloc(1, sizeof(*DRB_config->pdcp_Config->t_Reordering)); - *DRB_config->pdcp_Config->t_Reordering = NR_PDCP_Config__t_Reordering_ms750; + *DRB_config->pdcp_Config->t_Reordering = NR_PDCP_Config__t_Reordering_ms0; DRB_config->pdcp_Config->ext1 = NULL; + if (rrc->security.do_drb_integrity) { + DRB_config->pdcp_Config->drb->integrityProtection = calloc(1, sizeof(*DRB_config->pdcp_Config->drb->integrityProtection)); + *DRB_config->pdcp_Config->drb->integrityProtection = NR_PDCP_Config__drb__integrityProtection_enabled; + } + + if (!rrc->security.do_drb_ciphering) { + DRB_config->pdcp_Config->ext1 = calloc(1, sizeof(*DRB_config->pdcp_Config->ext1)); + DRB_config->pdcp_Config->ext1->cipheringDisabled = calloc(1, sizeof(*DRB_config->pdcp_Config->ext1->cipheringDisabled)); + *DRB_config->pdcp_Config->ext1->cipheringDisabled = NR_PDCP_Config__ext1__cipheringDisabled_true; + } + // Reference TS23501 Table 5.7.4-1: Standardized 5QI to QoS characteristics mapping for (qos_flow_index = 0; qos_flow_index < ue_context_pP->ue_context.pduSession[i].param.nb_qos; qos_flow_index++) { switch (ue_context_pP->ue_context.pduSession[i].param.qos[qos_flow_index].fiveQI) { @@ -1310,6 +1325,7 @@ rrc_gNB_process_RRCReconfigurationComplete( uint8_t *kRRCenc = NULL; uint8_t *kRRCint = NULL; uint8_t *kUPenc = NULL; + uint8_t *kUPint = NULL; NR_DRB_ToAddModList_t *DRB_configList = ue_context_pP->ue_context.DRB_configList2[xid]; NR_SRB_ToAddModList_t *SRB_configList = ue_context_pP->ue_context.SRB_configList2[xid]; NR_DRB_ToReleaseList_t *DRB_Release_configList2 = ue_context_pP->ue_context.DRB_Release_configList2[xid]; @@ -1319,21 +1335,22 @@ rrc_gNB_process_RRCReconfigurationComplete( ue_context_pP->ue_context.ue_reestablishment_timer = 0; -#ifndef PHYSIM /* Derive the keys from kgnb */ if (DRB_configList != NULL) { - derive_key_up_enc(ue_context_pP->ue_context.ciphering_algorithm, - ue_context_pP->ue_context.kgnb, - &kUPenc); + nr_derive_key_up_enc(ue_context_pP->ue_context.ciphering_algorithm, + ue_context_pP->ue_context.kgnb, + &kUPenc); + nr_derive_key_up_int(ue_context_pP->ue_context.integrity_algorithm, + ue_context_pP->ue_context.kgnb, + &kUPint); } - derive_key_rrc_enc(ue_context_pP->ue_context.ciphering_algorithm, - ue_context_pP->ue_context.kgnb, - &kRRCenc); - derive_key_rrc_int(ue_context_pP->ue_context.integrity_algorithm, - ue_context_pP->ue_context.kgnb, - &kRRCint); -#endif + nr_derive_key_rrc_enc(ue_context_pP->ue_context.ciphering_algorithm, + ue_context_pP->ue_context.kgnb, + &kRRCenc); + nr_derive_key_rrc_int(ue_context_pP->ue_context.integrity_algorithm, + ue_context_pP->ue_context.kgnb, + &kRRCint); /* Refresh SRBs/DRBs */ MSC_LOG_TX_MESSAGE(MSC_RRC_GNB, MSC_PDCP_ENB, NULL, 0, MSC_AS_TIME_FMT" CONFIG_REQ UE %x DRB (security unchanged)", MSC_AS_TIME_ARGS(ctxt_pP), @@ -1346,11 +1363,12 @@ rrc_gNB_process_RRCReconfigurationComplete( SRB_configList, // NULL, DRB_configList, DRB_Release_configList2, - 0, // already configured during the securitymodecommand + (ue_context_pP->ue_context.integrity_algorithm << 4) + | ue_context_pP->ue_context.ciphering_algorithm, kRRCenc, kRRCint, kUPenc, - NULL, + kUPint, NULL, NULL, get_softmodem_params()->sa ? ue_context_pP->ue_context.masterCellGroup->rlc_BearerToAddModList : NULL); @@ -1362,6 +1380,7 @@ rrc_gNB_process_RRCReconfigurationComplete( rrc->carrier.pusch_AntennaPorts, rrc->carrier.sib1_tda, NULL, + NULL, 0, ue_context_pP->ue_context.rnti, ue_context_pP->ue_context.masterCellGroup @@ -1793,7 +1812,7 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete( nr_rrc_pdcp_config_security( ctxt_pP, ue_context_pP, - send_security_mode_command); + send_security_mode_command ? 0 : 1); LOG_D(NR_RRC, "set security successfully \n"); } @@ -2569,6 +2588,9 @@ rrc_gNB_decode_dcch( xer_fprint(stdout, &asn_DEF_NR_UL_DCCH_Message, (void *)ul_dcch_msg); } + /* configure ciphering */ + nr_rrc_pdcp_config_security(ctxt_pP, ue_context_p, 1); + rrc_gNB_generate_UECapabilityEnquiry(ctxt_pP, ue_context_p); //rrc_gNB_generate_defaultRRCReconfiguration(ctxt_pP, ue_context_p); break; @@ -2885,7 +2907,7 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *f1_setup_req) { f1_setup_req->mib[i], f1_setup_req->mib_length[i]); AssertFatal(dec_rval.code == RC_OK, - "[gNB_DU %"PRIu8"] Failed to decode NR_BCCH_BCH_MESSAGE (%zu bits)\n", + "[gNB_CU %"PRIu8"] Failed to decode NR_BCCH_BCH_MESSAGE (%zu bits)\n", j, dec_rval.consumed ); NR_BCCH_BCH_Message_t *mib = &rrc->carrier.mib; @@ -3950,7 +3972,7 @@ void nr_rrc_subframe_process(protocol_ctxt_t *const ctxt_pP, const int CC_id) { ctxt_pP->module_id, ue_context_p, NGAP_CAUSE_RADIO_NETWORK, - 30); + NGAP_CAUSE_RADIO_NETWORK_RADIO_CONNECTION_WITH_UE_LOST); } // Remove here the MAC and RRC context when RRC is not connected or gNB is not connected to CN5G @@ -4113,7 +4135,7 @@ void *rrc_gnb_task(void *args_p) { NR_RRC_DCCH_DATA_IND(msg_p).rnti, msg_p->ittiMsgHeader.lte_time.frame, msg_p->ittiMsgHeader.lte_time.slot); - LOG_I(NR_RRC,"Decoding DCCH : ue %d, inst %ld, ctxt %p, size %d\n", + LOG_D(NR_RRC,"Decoding DCCH : ue %d, inst %ld, ctxt %p, size %d\n", ctxt.rnti, instance, &ctxt, diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 69d3e4a52b..46954b5734 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -297,7 +297,7 @@ void nr_rrc_pdcp_config_security( const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *const ue_context_pP, - const uint8_t send_security_mode_command + const uint8_t enable_ciphering ) //------------------------------------------------------------------------------ { @@ -309,40 +309,20 @@ nr_rrc_pdcp_config_security( uint8_t *k_kdf = NULL; static int print_keys= 1; -#ifndef PHYSIM + /* Derive the keys from kgnb */ if (SRB_configList != NULL) { - k_kdf = NULL; nr_derive_key_up_enc(ue_context_pP->ue_context.ciphering_algorithm, ue_context_pP->ue_context.kgnb, - &k_kdf); - /* kUPenc: last 128 bits of key derivation function which returns 256 bits */ - kUPenc = malloc(16); - if (kUPenc == NULL) exit(1); - memcpy(kUPenc, k_kdf+16, 16); - free(k_kdf); + &kUPenc); } - k_kdf = NULL; nr_derive_key_rrc_enc(ue_context_pP->ue_context.ciphering_algorithm, ue_context_pP->ue_context.kgnb, - &k_kdf); - /* kRRCenc: last 128 bits of key derivation function which returns 256 bits */ - kRRCenc = malloc(16); - if (kRRCenc == NULL) exit(1); - memcpy(kRRCenc, k_kdf+16, 16); - free(k_kdf); - - k_kdf = NULL; + &kRRCenc); nr_derive_key_rrc_int(ue_context_pP->ue_context.integrity_algorithm, ue_context_pP->ue_context.kgnb, - &k_kdf); - /* kRRCint: last 128 bits of key derivation function which returns 256 bits */ - kRRCint = malloc(16); - if (kRRCint == NULL) exit(1); - memcpy(kRRCint, k_kdf+16, 16); - free(k_kdf); -#endif + &kRRCint); if (!IS_SOFTMODEM_IQPLAYER) { SET_LOG_DUMP(DEBUG_SECURITY) ; } @@ -362,10 +342,11 @@ nr_rrc_pdcp_config_security( NULL, /* pdcp_pP not used anymore in NR */ DCCH, DCCH+2, - (send_security_mode_command == TRUE) ? - 0 | (ue_context_pP->ue_context.integrity_algorithm << 4) : - (ue_context_pP->ue_context.ciphering_algorithm ) | - (ue_context_pP->ue_context.integrity_algorithm << 4), + enable_ciphering ? + ue_context_pP->ue_context.ciphering_algorithm + | (ue_context_pP->ue_context.integrity_algorithm << 4) + : 0 + | (ue_context_pP->ue_context.integrity_algorithm << 4), kRRCenc, kRRCint, kUPenc); @@ -599,25 +580,10 @@ rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ( ue_context_p, NGAP_INITIAL_CONTEXT_SETUP_REQ(msg_p).security_key); - uint8_t send_security_mode_command = TRUE; + /* configure only integrity, ciphering comes after receiving SecurityModeComplete */ + nr_rrc_pdcp_config_security(&ctxt, ue_context_p, 0); - nr_rrc_pdcp_config_security( - &ctxt, - ue_context_p, - send_security_mode_command); - - if (send_security_mode_command) { - rrc_gNB_generate_SecurityModeCommand (&ctxt, ue_context_p); - send_security_mode_command = FALSE; - - nr_rrc_pdcp_config_security( - &ctxt, - ue_context_p, - send_security_mode_command); - } else { - /* rrc_gNB_generate_UECapabilityEnquiry */ - rrc_gNB_generate_UECapabilityEnquiry(&ctxt, ue_context_p); - } + rrc_gNB_generate_SecurityModeCommand (&ctxt, ue_context_p); // in case, send the S1SP initial context response if it is not sent with the attach complete message if (ue_context_p->ue_context.StatusRrc == NR_RRC_RECONFIGURED) { @@ -685,43 +651,76 @@ rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP( itti_send_msg_to_task (TASK_NGAP, ctxt_pP->instance, msg_p); } -static NR_CipheringAlgorithm_t rrc_gNB_select_ciphering(uint16_t algorithms) { +static NR_CipheringAlgorithm_t rrc_gNB_select_ciphering( + const protocol_ctxt_t *const ctxt_pP, + uint16_t algorithms) +{ + gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; + int i; + /* preset nea0 as fallback */ + int ret = 0; - return NR_CipheringAlgorithm_nea0; - - - if (algorithms & NGAP_ENCRYPTION_NEA3_MASK) { - return NR_CipheringAlgorithm_nea3; + /* Select ciphering algorithm based on gNB configuration file and + * UE's supported algorithms. + * We take the first from the list that is supported by the UE. + * The ordering of the list comes from the configuration file. + */ + for (i = 0; i < rrc->security.ciphering_algorithms_count; i++) { + int nea_mask[4] = { + 0, + NGAP_ENCRYPTION_NEA1_MASK, + NGAP_ENCRYPTION_NEA2_MASK, + NGAP_ENCRYPTION_NEA3_MASK + }; + if (rrc->security.ciphering_algorithms[i] == 0) { + /* nea0 */ + break; + } + if (algorithms & nea_mask[rrc->security.ciphering_algorithms[i]]) { + ret = rrc->security.ciphering_algorithms[i]; + break; + } } - if (algorithms & NGAP_ENCRYPTION_NEA2_MASK) { - return NR_CipheringAlgorithm_nea2; - } - - if (algorithms & NGAP_ENCRYPTION_NEA1_MASK) { - return NR_CipheringAlgorithm_nea1; - } + LOG_I(RRC, "selecting ciphering algorithm %d\n", ret); + return ret; } -static e_NR_IntegrityProtAlgorithm rrc_gNB_select_integrity(uint16_t algorithms) { - - //only NIA2 supported for now - return NR_IntegrityProtAlgorithm_nia2; +static e_NR_IntegrityProtAlgorithm rrc_gNB_select_integrity( + const protocol_ctxt_t *const ctxt_pP, + uint16_t algorithms) +{ + gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; + int i; + /* preset nia0 as fallback */ + int ret = 0; - if (algorithms & NGAP_INTEGRITY_NIA3_MASK) { - return NR_IntegrityProtAlgorithm_nia3; + /* Select integrity algorithm based on gNB configuration file and + * UE's supported algorithms. + * We take the first from the list that is supported by the UE. + * The ordering of the list comes from the configuration file. + */ + for (i = 0; i < rrc->security.integrity_algorithms_count; i++) { + int nia_mask[4] = { + 0, + NGAP_INTEGRITY_NIA1_MASK, + NGAP_INTEGRITY_NIA2_MASK, + NGAP_INTEGRITY_NIA3_MASK + }; + if (rrc->security.integrity_algorithms[i] == 0) { + /* nia0 */ + break; + } + if (algorithms & nia_mask[rrc->security.integrity_algorithms[i]]) { + ret = rrc->security.integrity_algorithms[i]; + break; + } } - if (algorithms & NGAP_INTEGRITY_NIA2_MASK) { - return NR_IntegrityProtAlgorithm_nia2; - } + LOG_I(RRC, "selecting integrity algorithm %d\n", ret); - if (algorithms & NGAP_INTEGRITY_NIA1_MASK) { - return NR_IntegrityProtAlgorithm_nia1; - } - - return NR_IntegrityProtAlgorithm_nia0; + return ret; } int @@ -744,14 +743,14 @@ rrc_gNB_process_security( ue_context_pP->ue_context.security_capabilities.nRintegrity_algorithms, ue_context_pP->ue_context.integrity_algorithm); /* Select relevant algorithms */ - cipheringAlgorithm = rrc_gNB_select_ciphering (ue_context_pP->ue_context.security_capabilities.nRencryption_algorithms); + cipheringAlgorithm = rrc_gNB_select_ciphering(ctxt_pP, ue_context_pP->ue_context.security_capabilities.nRencryption_algorithms); if (ue_context_pP->ue_context.ciphering_algorithm != cipheringAlgorithm) { ue_context_pP->ue_context.ciphering_algorithm = cipheringAlgorithm; changed = TRUE; } - integrityProtAlgorithm = rrc_gNB_select_integrity (ue_context_pP->ue_context.security_capabilities.nRintegrity_algorithms); + integrityProtAlgorithm = rrc_gNB_select_integrity(ctxt_pP, ue_context_pP->ue_context.security_capabilities.nRintegrity_algorithms); if (ue_context_pP->ue_context.integrity_algorithm != integrityProtAlgorithm) { ue_context_pP->ue_context.integrity_algorithm = integrityProtAlgorithm; diff --git a/openair2/RRC/NR/rrc_gNB_UE_context.c b/openair2/RRC/NR/rrc_gNB_UE_context.c index eb7559f69d..ad8bd01470 100644 --- a/openair2/RRC/NR/rrc_gNB_UE_context.c +++ b/openair2/RRC/NR/rrc_gNB_UE_context.c @@ -139,7 +139,7 @@ rrc_gNB_allocate_new_UE_context( new_p->ue_context.modify_e_rab[i].xid = -1; } - LOG_I(NR_RRC,"Returning new UE context at %p\n",new_p); + LOG_D(NR_RRC,"Returning new UE context at %p\n",new_p); return(new_p); } diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index 167f85ba48..f9fce48f41 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -52,9 +52,7 @@ extern boolean_t nr_rrc_pdcp_config_asn1_req( uint8_t *const kRRCint, uint8_t *const kUPenc, uint8_t *const kUPint - #if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) ,LTE_PMCH_InfoList_r9_t *pmch_InfoList_r9 - #endif ,rb_id_t *const defaultDRB, struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_bearer2add_list); @@ -142,6 +140,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ gtpv1u_enb_create_tunnel_resp_t create_tunnel_resp; protocol_ctxt_t ctxt={0}; unsigned char *kUPenc = NULL; + unsigned char *kUPint = NULL; int i; // NR RRCReconfiguration AssertFatal(rrc->Nb_ue < MAX_NR_RRC_UE_CONTEXTS,"cannot add another UE\n"); @@ -214,15 +213,12 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ LOG_I(RRC, "selecting integrity algorithm %d\n", ue_context_p->ue_context.integrity_algorithm); /* derive UP security key */ - unsigned char *kUPenc_kdf; nr_derive_key_up_enc(ue_context_p->ue_context.ciphering_algorithm, ue_context_p->ue_context.kgnb, - &kUPenc_kdf); - /* kUPenc: last 128 bits of key derivation function which returns 256 bits */ - kUPenc = malloc(16); - if (kUPenc == NULL) exit(1); - memcpy(kUPenc, kUPenc_kdf+16, 16); - free(kUPenc_kdf); + &kUPenc); + nr_derive_key_up_int(ue_context_p->ue_context.integrity_algorithm, + ue_context_p->ue_context.kgnb, + &kUPint); e_NR_CipheringAlgorithm cipher_algo; switch (ue_context_p->ue_context.ciphering_algorithm) { @@ -355,6 +351,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ rrc->carrier.pusch_AntennaPorts, rrc->carrier.sib1_tda, rrc->carrier.servingcellconfigcommon, + &rrc->carrier.mib, 1, // add_ue flag ue_context_p->ue_id_rnti, ue_context_p->ue_context.secondaryCellGroup); @@ -365,6 +362,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ rrc->carrier.pusch_AntennaPorts, rrc->carrier.sib1_tda, NULL, + NULL, 1, // add_ue flag ue_context_p->ue_id_rnti, ue_context_p->ue_context.secondaryCellGroup); @@ -387,7 +385,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ NULL, /* kRRCenc - unused */ NULL, /* kRRCint - unused */ kUPenc, /* kUPenc */ - NULL, /* kUPint - unused */ + kUPint, /* kUPint */ NULL, NULL, ue_context_p->ue_context.secondaryCellGroup->rlc_BearerToAddModList); diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index ad39b1b5e0..6892599ec0 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -187,9 +187,7 @@ extern boolean_t nr_rrc_pdcp_config_asn1_req( uint8_t *const kRRCint, uint8_t *const kUPenc, uint8_t *const kUPint - #if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) ,LTE_PMCH_InfoList_r9_t *pmch_InfoList_r9 - #endif ,rb_id_t *const defaultDRB, struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_bearer2add_list); @@ -237,8 +235,9 @@ int8_t nr_rrc_ue_decode_secondary_cellgroup_config(const module_id_t module_id, int8_t nr_rrc_ue_process_RadioBearerConfig(NR_RadioBearerConfig_t *RadioBearerConfig){ - - xer_fprint(stdout, &asn_DEF_NR_RadioBearerConfig, (const void*)RadioBearerConfig); + if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { + xer_fprint(stdout, &asn_DEF_NR_RadioBearerConfig, (const void *) RadioBearerConfig); + } // Configure PDCP return 0; @@ -268,7 +267,9 @@ int8_t nr_rrc_ue_process_rrcReconfiguration(const module_id_t module_id, NR_RRCR (uint8_t *)rrcReconfiguration->criticalExtensions.choice.rrcReconfiguration->secondaryCellGroup->buf, rrcReconfiguration->criticalExtensions.choice.rrcReconfiguration->secondaryCellGroup->size, 0, 0); - xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)cellGroupConfig); + if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { + xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig); + } if(NR_UE_rrc_inst[module_id].cell_group_config == NULL){ // first time receive the configuration, just use the memory allocated from uper_decoder. TODO this is not good implementation, need to maintain RRC_INST own structure every time. @@ -1257,7 +1258,10 @@ nr_rrc_ue_process_masterCellGroup( (void **)&cellGroupConfig, (uint8_t *)masterCellGroup->buf, masterCellGroup->size, 0, 0); - xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)cellGroupConfig); + + if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { + xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig); + } if( cellGroupConfig->spCellConfig != NULL && cellGroupConfig->spCellConfig->reconfigurationWithSync != NULL){ //TODO (perform Reconfiguration with sync according to 5.3.5.5.2) @@ -1415,11 +1419,11 @@ int8_t nr_rrc_ue_decode_ccch( const protocol_ctxt_t *const ctxt_pP, const NR_SRB &asn_DEF_NR_DL_CCCH_Message, (void **)&dl_ccch_msg, (uint8_t *)Srb_info->Rx_buffer.Payload, - 100,0,0); + Srb_info->Rx_buffer.payload_size,0,0); - if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { +// if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { xer_fprint(stdout,&asn_DEF_NR_DL_CCCH_Message,(void *)dl_ccch_msg); - } +// } if ((dec_rval.code != RC_OK) && (dec_rval.consumed==0)) { LOG_E(RRC,"[UE %d] Frame %d : Failed to decode DL-CCCH-Message (%zu bytes)\n",ctxt_pP->module_id,ctxt_pP->frame,dec_rval.consumed); @@ -1657,45 +1661,40 @@ int8_t nr_rrc_ue_decode_ccch( const protocol_ctxt_t *const ctxt_pP, const NR_SRB uint8_t *kRRCenc = NULL; uint8_t *kUPenc = NULL; uint8_t *kRRCint = NULL; - pdcp_t *pdcp_p = NULL; - hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; - hashtable_rc_t h_rc; - key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, DCCH, SRB_FLAG_YES); - h_rc = hashtable_get(pdcp_coll_p, key, (void **) &pdcp_p); + nr_derive_key_up_enc(NR_UE_rrc_inst[ctxt_pP->module_id].cipheringAlgorithm, + NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, + &kUPenc); + nr_derive_key_rrc_enc(NR_UE_rrc_inst[ctxt_pP->module_id].cipheringAlgorithm, + NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, + &kRRCenc); + nr_derive_key_rrc_int(NR_UE_rrc_inst[ctxt_pP->module_id].integrityProtAlgorithm, + NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, + &kRRCint); + LOG_I(NR_RRC, "driving kRRCenc, kRRCint and kUPenc from KgNB=" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x\n", + NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[0], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[1], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[2], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[3], + NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[4], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[5], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[6], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[7], + NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[8], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[9], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[10], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[11], + NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[12], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[13], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[14], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[15], + NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[16], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[17], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[18], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[19], + NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[20], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[21], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[22], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[23], + NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[24], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[25], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[26], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[27], + NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[28], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[29], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[30], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[31]); - if (h_rc == HASH_TABLE_OK) { - LOG_D(NR_RRC, "PDCP_COLL_KEY_VALUE() returns valid key = %ld\n", key); - LOG_D(NR_RRC, "driving kRRCenc, kRRCint and kUPenc from KgNB=" - "%02x%02x%02x%02x" - "%02x%02x%02x%02x" - "%02x%02x%02x%02x" - "%02x%02x%02x%02x" - "%02x%02x%02x%02x" - "%02x%02x%02x%02x" - "%02x%02x%02x%02x" - "%02x%02x%02x%02x\n", - NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[0], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[1], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[2], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[3], - NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[4], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[5], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[6], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[7], - NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[8], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[9], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[10], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[11], - NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[12], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[13], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[14], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[15], - NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[16], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[17], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[18], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[19], - NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[20], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[21], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[22], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[23], - NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[24], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[25], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[26], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[27], - NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[28], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[29], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[30], NR_UE_rrc_inst[ctxt_pP->module_id].kgnb[31]); - derive_key_rrc_enc(NR_UE_rrc_inst[ctxt_pP->module_id].cipheringAlgorithm,NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, &kRRCenc); - derive_key_rrc_int(NR_UE_rrc_inst[ctxt_pP->module_id].integrityProtAlgorithm,NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, &kRRCint); - derive_key_up_enc(NR_UE_rrc_inst[ctxt_pP->module_id].cipheringAlgorithm,NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, &kUPenc); - - if (securityMode != 0xff) { - pdcp_config_set_security(ctxt_pP, pdcp_p, 0, 0, - NR_UE_rrc_inst[ctxt_pP->module_id].cipheringAlgorithm - | (NR_UE_rrc_inst[ctxt_pP->module_id].integrityProtAlgorithm << 4), - kRRCenc, kRRCint, kUPenc); - } else { - LOG_I(NR_RRC, "skipped pdcp_config_set_security() as securityMode == 0x%02x", securityMode); - } + if (securityMode != 0xff) { + pdcp_config_set_security(ctxt_pP, NULL, DCCH, DCCH+2, + NR_UE_rrc_inst[ctxt_pP->module_id].cipheringAlgorithm + | (NR_UE_rrc_inst[ctxt_pP->module_id].integrityProtAlgorithm << 4), + kRRCenc, kRRCint, kUPenc); } else { - LOG_I(NR_RRC, "Could not get PDCP instance where key=0x%ld\n", key); + LOG_I(NR_RRC, "skipped pdcp_config_set_security() as securityMode == 0x%02x", securityMode); } if (securityModeCommand->criticalExtensions.present == NR_SecurityModeCommand__criticalExtensions_PR_securityModeCommand) { @@ -2042,10 +2041,11 @@ nr_rrc_ue_establish_srb2( uint8_t *kRRCenc = NULL; uint8_t *kRRCint = NULL; - derive_key_rrc_enc(NR_UE_rrc_inst[ctxt_pP->module_id].cipheringAlgorithm, - NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, &kRRCenc); - derive_key_rrc_int(NR_UE_rrc_inst[ctxt_pP->module_id].integrityProtAlgorithm, - NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, &kRRCint); + nr_derive_key_rrc_enc(NR_UE_rrc_inst[ctxt_pP->module_id].cipheringAlgorithm, + NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, &kRRCenc); + nr_derive_key_rrc_int(NR_UE_rrc_inst[ctxt_pP->module_id].integrityProtAlgorithm, + NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, &kRRCint); + // Refresh SRBs nr_rrc_pdcp_config_asn1_req(ctxt_pP, radioBearerConfig->srb_ToAddModList, @@ -2086,6 +2086,7 @@ nr_rrc_ue_establish_srb2( LOG_I(NR_RRC, "[FRAME %05d][RRC_UE][MOD %02d][][--- MAC_CONFIG_REQ (SRB1 gNB %d) --->][MAC_UE][MOD %02d][]\n", ctxt_pP->frame, ctxt_pP->module_id, gNB_index, ctxt_pP->module_id); + nr_rrc_mac_config_req_ue_logicalChannelBearer(ctxt_pP->module_id,0,gNB_index,1,true); //todo handle mac_LogicalChannelConfig // rrc_mac_config_req_ue } } else { @@ -2101,6 +2102,7 @@ nr_rrc_ue_establish_srb2( LOG_I(NR_RRC, "[FRAME %05d][RRC_UE][MOD %02d][][--- MAC_CONFIG_REQ (SRB2 gNB %d) --->][MAC_UE][MOD %02d][]\n", ctxt_pP->frame, ctxt_pP->module_id, gNB_index, ctxt_pP->module_id); + nr_rrc_mac_config_req_ue_logicalChannelBearer(ctxt_pP->module_id,0,gNB_index,2,true); //todo handle mac_LogicalChannelConfig // rrc_mac_config_req_ue } } // srb2 @@ -2121,14 +2123,34 @@ nr_rrc_ue_establish_srb2( memcpy(NR_UE_rrc_inst[ctxt_pP->module_id].DRB_config[gNB_index][DRB_id-1], radioBearerConfig->drb_ToAddModList->list.array[cnt], sizeof(NR_DRB_ToAddMod_t)); } else { - LOG_D(NR_RRC, "Adding DRB %ld %p\n", DRB_id-1, radioBearerConfig->drb_ToAddModList->list.array[cnt]); + //LOG_D(NR_RRC, "Adding DRB %ld %p\n", DRB_id-1, radioBearerConfig->drb_ToAddModList->list.array[cnt]); NR_UE_rrc_inst[ctxt_pP->module_id].DRB_config[gNB_index][DRB_id-1] = radioBearerConfig->drb_ToAddModList->list.array[cnt]; + int j; + struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_bearer2add_list = NR_UE_rrc_inst[ctxt_pP->module_id].cell_group_config->rlc_BearerToAddModList; + if (rlc_bearer2add_list != NULL) { + for(j = 0; j < rlc_bearer2add_list->list.count; j++){ + if(rlc_bearer2add_list->list.array[j]->servedRadioBearer != NULL){ + if(rlc_bearer2add_list->list.array[j]->servedRadioBearer->present == NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity){ + if(DRB_id == rlc_bearer2add_list->list.array[j]->servedRadioBearer->choice.drb_Identity){ + LOG_I(NR_RRC, "[FRAME %05d][RRC_UE][MOD %02d][][--- MAC_CONFIG_REQ (DRB lcid %ld gNB %d) --->][MAC_UE][MOD %02d][]\n", + ctxt_pP->frame, ctxt_pP->module_id, rlc_bearer2add_list->list.array[j]->logicalChannelIdentity, 0, ctxt_pP->module_id); + nr_rrc_mac_config_req_ue_logicalChannelBearer(ctxt_pP->module_id,0,0,rlc_bearer2add_list->list.array[j]->logicalChannelIdentity,true); //todo handle mac_LogicalChannelConfig + } + } + } + } + } } } uint8_t *kUPenc = NULL; - derive_key_up_enc(NR_UE_rrc_inst[ctxt_pP->module_id].cipheringAlgorithm, - NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, &kUPenc); + uint8_t *kUPint = NULL; + + nr_derive_key_up_enc(NR_UE_rrc_inst[ctxt_pP->module_id].cipheringAlgorithm, + NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, &kUPenc); + nr_derive_key_up_int(NR_UE_rrc_inst[ctxt_pP->module_id].integrityProtAlgorithm, + NR_UE_rrc_inst[ctxt_pP->module_id].kgnb, &kUPint); + MSC_LOG_TX_MESSAGE( MSC_RRC_UE, MSC_PDCP_UE, @@ -2149,7 +2171,7 @@ nr_rrc_ue_establish_srb2( NULL, NULL, kUPenc, - NULL, + kUPint, NULL, NR_UE_rrc_inst[ctxt_pP->module_id].defaultDRB, NR_UE_rrc_inst[ctxt_pP->module_id].cell_group_config->rlc_BearerToAddModList); @@ -2170,6 +2192,15 @@ nr_rrc_ue_establish_srb2( } } + if (NR_UE_rrc_inst[ctxt_pP->module_id].cell_group_config->rlc_BearerToReleaseList != NULL) { + for (i = 0; i < NR_UE_rrc_inst[ctxt_pP->module_id].cell_group_config->rlc_BearerToReleaseList->list.count; i++) { + NR_LogicalChannelIdentity_t lcid = *NR_UE_rrc_inst[ctxt_pP->module_id].cell_group_config->rlc_BearerToReleaseList->list.array[i]; + LOG_I(NR_RRC, "[FRAME %05d][RRC_UE][MOD %02d][][--- MAC_CONFIG_REQ (RB lcid %ld gNB %d release) --->][MAC_UE][MOD %02d][]\n", + ctxt_pP->frame, ctxt_pP->module_id, lcid, 0, ctxt_pP->module_id); + nr_rrc_mac_config_req_ue_logicalChannelBearer(ctxt_pP->module_id,0,0,lcid,false); //todo handle mac_LogicalChannelConfig + } + } + NR_UE_rrc_inst[ctxt_pP->module_id].Info[gNB_index].State = NR_RRC_CONNECTED; LOG_I(NR_RRC,"[UE %d] State = NR_RRC_CONNECTED (gNB %d)\n", ctxt_pP->module_id, gNB_index); } @@ -2306,9 +2337,9 @@ nr_rrc_ue_establish_srb2( return -1; } - // if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { - xer_fprint(stdout, &asn_DEF_NR_DL_DCCH_Message,(void *)dl_dcch_msg); - // } + if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { + xer_fprint(stdout, &asn_DEF_NR_DL_DCCH_Message,(void *)dl_dcch_msg); + } if (dl_dcch_msg->message.present == NR_DL_DCCH_MessageType_PR_c1) { switch (dl_dcch_msg->message.choice.c1->present) { @@ -2482,6 +2513,28 @@ nr_rrc_ue_establish_srb2( NR_RRC_DCCH_DATA_IND (msg_p).gNB_index); break; + case NAS_KENB_REFRESH_REQ: + memcpy((void *)NR_UE_rrc_inst[ue_mod_id].kgnb, (void *)NAS_KENB_REFRESH_REQ(msg_p).kenb, sizeof(NR_UE_rrc_inst[ue_mod_id].kgnb)); + LOG_D(RRC, "[UE %d] Received %s: refreshed RRC::KgNB = " + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x\n", + ue_mod_id, ITTI_MSG_NAME (msg_p), + NR_UE_rrc_inst[ue_mod_id].kgnb[0], NR_UE_rrc_inst[ue_mod_id].kgnb[1], NR_UE_rrc_inst[ue_mod_id].kgnb[2], NR_UE_rrc_inst[ue_mod_id].kgnb[3], + NR_UE_rrc_inst[ue_mod_id].kgnb[4], NR_UE_rrc_inst[ue_mod_id].kgnb[5], NR_UE_rrc_inst[ue_mod_id].kgnb[6], NR_UE_rrc_inst[ue_mod_id].kgnb[7], + NR_UE_rrc_inst[ue_mod_id].kgnb[8], NR_UE_rrc_inst[ue_mod_id].kgnb[9], NR_UE_rrc_inst[ue_mod_id].kgnb[10], NR_UE_rrc_inst[ue_mod_id].kgnb[11], + NR_UE_rrc_inst[ue_mod_id].kgnb[12], NR_UE_rrc_inst[ue_mod_id].kgnb[13], NR_UE_rrc_inst[ue_mod_id].kgnb[14], NR_UE_rrc_inst[ue_mod_id].kgnb[15], + NR_UE_rrc_inst[ue_mod_id].kgnb[16], NR_UE_rrc_inst[ue_mod_id].kgnb[17], NR_UE_rrc_inst[ue_mod_id].kgnb[18], NR_UE_rrc_inst[ue_mod_id].kgnb[19], + NR_UE_rrc_inst[ue_mod_id].kgnb[20], NR_UE_rrc_inst[ue_mod_id].kgnb[21], NR_UE_rrc_inst[ue_mod_id].kgnb[22], NR_UE_rrc_inst[ue_mod_id].kgnb[23], + NR_UE_rrc_inst[ue_mod_id].kgnb[24], NR_UE_rrc_inst[ue_mod_id].kgnb[25], NR_UE_rrc_inst[ue_mod_id].kgnb[26], NR_UE_rrc_inst[ue_mod_id].kgnb[27], + NR_UE_rrc_inst[ue_mod_id].kgnb[28], NR_UE_rrc_inst[ue_mod_id].kgnb[29], NR_UE_rrc_inst[ue_mod_id].kgnb[30], NR_UE_rrc_inst[ue_mod_id].kgnb[31]); + break; + case NAS_UPLINK_DATA_REQ: { uint32_t length; uint8_t *buffer; diff --git a/openair2/SDAP/nr_sdap/nr_sdap_gnb.c b/openair2/SDAP/nr_sdap/nr_sdap_gnb.c new file mode 100644 index 0000000000..5f0a2640e9 --- /dev/null +++ b/openair2/SDAP/nr_sdap/nr_sdap_gnb.c @@ -0,0 +1,87 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "nr_sdap_gnb.h" +#include + +boolean_t sdap_gnb_data_req(protocol_ctxt_t *ctxt_p, + const srb_flag_t srb_flag, + const rb_id_t rb_id, + const mui_t mui, + const confirm_t confirm, + const sdu_size_t sdu_buffer_size, + unsigned char *const sdu_buffer, + const pdcp_transmission_mode_t pt_mode, + const uint32_t *sourceL2Id, + const uint32_t *destinationL2Id + ) { + if(sdu_buffer == NULL) { + LOG_E(PDCP, "%s:%d:%s: SDAP Layer gNB - NULL sdu_buffer \n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + if(sdu_buffer_size == 0) { + LOG_E(PDCP, "%s:%d:%s: SDAP Layer gNB - NULL or 0 sdu_buffer_size \n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + uint8_t *sdap_buf = (uint8_t *)malloc(sdu_buffer_size+SDAP_HDR_LENGTH); + nr_sdap_dl_hdr_t sdap_hdr; + sdap_hdr.RDI = 0; // SDAP_Hardcoded - + sdap_hdr.RQI = 0; // SDAP_Hardcoded - Should get this info from DL_PDU_SESSION_INFORMATION + sdap_hdr.QFI = 1; // SDAP_Hardcoded - Should get this info from DL_PDU_SESSION_INFORMATION + memcpy(&sdap_buf[0], &sdap_hdr, 1); + memcpy(&sdap_buf[1], sdu_buffer, sdu_buffer_size); + rb_id_t sdap_drb_id = rb_id; // SDAP_Hardcoded - Should get this info from QFI to DRB mapping table + boolean_t ret = pdcp_data_req(ctxt_p, + srb_flag, + sdap_drb_id, + mui, + confirm, + sdu_buffer_size+1, + sdap_buf, + pt_mode, + sourceL2Id, + destinationL2Id); + + if(!ret) { + LOG_E(PDCP, "%s:%d:%s: SDAP Layer gNB - PDCP DL refused PDU\n", __FILE__, __LINE__, __FUNCTION__); + free(sdap_buf); + return 0; + } + + free(sdap_buf); + return 1; +} + +void sdap_gnb_ul_header_handler(char sdap_gnb_ul_hdr) { + nr_sdap_ul_hdr_t *sdap_hdr_ul = (nr_sdap_ul_hdr_t *)&sdap_gnb_ul_hdr; + + switch (sdap_hdr_ul->DC) { + case SDAP_HDR_UL_DATA_PDU: + LOG_I(PDCP, "%s:%d:%s: SDAP Layer gNB - UL Received SDAP Data PDU\n", __FILE__, __LINE__, __FUNCTION__); + break; + + case SDAP_HDR_UL_CTRL_PDU: + LOG_I(PDCP, "%s:%d:%s: SDAP Layer gNB - Received SDAP Control PDU\n", __FILE__, __LINE__, __FUNCTION__); + break; + } +} \ No newline at end of file diff --git a/openair2/SDAP/nr_sdap/nr_sdap_gnb.h b/openair2/SDAP/nr_sdap/nr_sdap_gnb.h new file mode 100644 index 0000000000..243aa89010 --- /dev/null +++ b/openair2/SDAP/nr_sdap/nr_sdap_gnb.h @@ -0,0 +1,61 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _NR_SDAP_GNB_ +#define _NR_SDAP_GNB_ + +#include "openair2/COMMON/platform_types.h" +#include "common/utils/LOG/log.h" + +#define SDAP_BITMASK_DC (0x80) +#define SDAP_BITMASK_R (0x40) +#define SDAP_BITMASK_QFI (0x3F) +#define SDAP_HDR_UL_DATA_PDU (1) +#define SDAP_HDR_UL_CTRL_PDU (0) +#define SDAP_HDR_LENGTH (1) + +typedef struct nr_sdap_dl_hdr_s { + uint8_t QFI:6; + uint8_t RQI:1; + uint8_t RDI:1; +} __attribute__((packed)) nr_sdap_dl_hdr_t; + +typedef struct nr_sdap_ul_hdr_s { + uint8_t QFI:6; + uint8_t R:1; + uint8_t DC:1; +} __attribute__((packed)) nr_sdap_ul_hdr_t; + +boolean_t sdap_gnb_data_req(protocol_ctxt_t *ctxt_p, + const srb_flag_t srb_flag, + const rb_id_t rb_id, + const mui_t mui, + const confirm_t confirm, + const sdu_size_t sdu_buffer_size, + unsigned char *const sdu_buffer, + const pdcp_transmission_mode_t pt_mode, + const uint32_t *sourceL2Id, + const uint32_t *destinationL2Id + ); + +void sdap_gnb_ul_header_handler(char sdap_gnb_ul_hdr); + +#endif \ No newline at end of file diff --git a/openair2/UTIL/OSA/osa_key_deriver.c b/openair2/UTIL/OSA/osa_key_deriver.c index 159ee7f159..c02b999490 100644 --- a/openair2/UTIL/OSA/osa_key_deriver.c +++ b/openair2/UTIL/OSA/osa_key_deriver.c @@ -121,6 +121,8 @@ int nr_derive_key(algorithm_type_dist_t alg_type, uint8_t alg_id, string[6] = 0x01; kdf(string, 7, key, 32, out, 32); + // in NR, we use the last 16 bytes, ignoring the first 16 ones + memcpy(*out, *out+16, 16); return 0; } diff --git a/openair3/NAS/COMMON/API/NETWORK/as_message.c b/openair3/NAS/COMMON/API/NETWORK/as_message.c index fd3f15cb4c..4a2da21594 100644 --- a/openair3/NAS/COMMON/API/NETWORK/as_message.c +++ b/openair3/NAS/COMMON/API/NETWORK/as_message.c @@ -81,7 +81,12 @@ int as_message_decode(const char* buffer, as_message_t* msg, int length) LOG_FUNC_IN; int bytes; - Byte_t** data = NULL; + /* pointers to msg fields possibly not aligned because msg points to a packed structure + * Using these possibly unaligned pointers in a function call may trigger alignment errors at run time and + * gcc, from v9, now warns about it. fix these warnings by removing the indirection on data + * (in fact i don't understand this code data seems to be useless...) + */ + Byte_t *data = NULL; /* Get the message type */ msg->msgID = *(uint16_t*)(buffer); @@ -91,49 +96,49 @@ int as_message_decode(const char* buffer, as_message_t* msg, int length) case AS_NAS_ESTABLISH_REQ: /* NAS signalling connection establish request */ bytes += sizeof(nas_establish_req_t) - sizeof(Byte_t*); - data = &msg->msg.nas_establish_req.initialNasMsg.data; + data = msg->msg.nas_establish_req.initialNasMsg.data; break; case AS_NAS_ESTABLISH_IND: /* NAS signalling connection establishment indication */ bytes += sizeof(nas_establish_ind_t) - sizeof(Byte_t*); - data = &msg->msg.nas_establish_ind.initialNasMsg.data; + data = msg->msg.nas_establish_ind.initialNasMsg.data; break; case AS_NAS_ESTABLISH_RSP: /* NAS signalling connection establishment response */ bytes += sizeof(nas_establish_rsp_t) - sizeof(Byte_t*); - data = &msg->msg.nas_establish_rsp.nasMsg.data; + data = msg->msg.nas_establish_rsp.nasMsg.data; break; case AS_NAS_ESTABLISH_CNF: /* NAS signalling connection establishment confirm */ bytes += sizeof(nas_establish_cnf_t) - sizeof(Byte_t*); - data = &msg->msg.nas_establish_cnf.nasMsg.data; + data = msg->msg.nas_establish_cnf.nasMsg.data; break; case AS_UL_INFO_TRANSFER_REQ: /* Uplink L3 data transfer request */ bytes += sizeof(ul_info_transfer_req_t) - sizeof(Byte_t*); - data = &msg->msg.ul_info_transfer_req.nasMsg.data; + data = msg->msg.ul_info_transfer_req.nasMsg.data; break; case AS_UL_INFO_TRANSFER_IND: /* Uplink L3 data transfer indication */ bytes += sizeof(ul_info_transfer_ind_t) - sizeof(Byte_t*); - data = &msg->msg.ul_info_transfer_ind.nasMsg.data; + data = msg->msg.ul_info_transfer_ind.nasMsg.data; break; case AS_DL_INFO_TRANSFER_REQ: /* Downlink L3 data transfer request */ bytes += sizeof(dl_info_transfer_req_t) - sizeof(Byte_t*); - data = &msg->msg.dl_info_transfer_req.nasMsg.data; + data = msg->msg.dl_info_transfer_req.nasMsg.data; break; case AS_DL_INFO_TRANSFER_IND: /* Downlink L3 data transfer indication */ bytes += sizeof(dl_info_transfer_ind_t) - sizeof(Byte_t*); - data = &msg->msg.dl_info_transfer_ind.nasMsg.data; + data = msg->msg.dl_info_transfer_ind.nasMsg.data; break; case AS_BROADCAST_INFO_IND: @@ -166,7 +171,8 @@ int as_message_decode(const char* buffer, as_message_t* msg, int length) if (bytes > 0) { if (data) { /* Set the pointer to dedicated NAS information */ - *data = (Byte_t*)(buffer + bytes); + /* wasn't data already computed above for specific cases here we override ?? */ + data = (Byte_t *)buffer + bytes; } /* Decode the message */ @@ -201,8 +207,10 @@ int as_message_encode(char* buffer, as_message_t* msg, int length) LOG_FUNC_IN; int bytes = sizeof(msg->msgID); - as_nas_info_t* nas_msg = NULL; - + as_nas_info_t nas_msg; + Byte_t *dataptr=NULL; + uint32_t len=0; + switch (msg->msgID) { case AS_BROADCAST_INFO_IND: /* Broadcast information */ @@ -237,25 +245,30 @@ int as_message_encode(char* buffer, as_message_t* msg, int length) case AS_NAS_ESTABLISH_REQ: /* NAS signalling connection establish request */ bytes += sizeof(nas_establish_req_t) - sizeof(Byte_t*); - nas_msg = &msg->msg.nas_establish_req.initialNasMsg; + nas_msg = msg->msg.nas_establish_req.initialNasMsg; break; case AS_NAS_ESTABLISH_IND: /* NAS signalling connection establish indication */ bytes += sizeof(nas_establish_ind_t) - sizeof(Byte_t*); - nas_msg = &msg->msg.nas_establish_ind.initialNasMsg; + nas_msg = msg->msg.nas_establish_ind.initialNasMsg; + dataptr=(Byte_t *)&(msg->msg.nas_establish_ind.initialNasMsg.data); + len=msg->msg.nas_establish_ind.initialNasMsg.length; break; case AS_NAS_ESTABLISH_RSP: /* NAS signalling connection establish response */ bytes += sizeof(nas_establish_rsp_t) - sizeof(Byte_t*); - nas_msg = &msg->msg.nas_establish_rsp.nasMsg; + nas_msg = msg->msg.nas_establish_rsp.nasMsg; + break; case AS_NAS_ESTABLISH_CNF: /* NAS signalling connection establish confirm */ bytes += sizeof(nas_establish_cnf_t) - sizeof(Byte_t*); - nas_msg = &msg->msg.nas_establish_cnf.nasMsg; + nas_msg = msg->msg.nas_establish_cnf.nasMsg; + dataptr=(Byte_t *)&(msg->msg.nas_establish_cnf.nasMsg.data); + len=msg->msg.nas_establish_ind.initialNasMsg.length; break; case AS_NAS_RELEASE_REQ: @@ -271,7 +284,7 @@ int as_message_encode(char* buffer, as_message_t* msg, int length) case AS_UL_INFO_TRANSFER_REQ: /* Uplink L3 data transfer request */ bytes += sizeof(ul_info_transfer_req_t) - sizeof(Byte_t*); - nas_msg = &msg->msg.ul_info_transfer_req.nasMsg; + nas_msg = msg->msg.ul_info_transfer_req.nasMsg; break; case AS_UL_INFO_TRANSFER_CNF: @@ -282,13 +295,13 @@ int as_message_encode(char* buffer, as_message_t* msg, int length) case AS_UL_INFO_TRANSFER_IND: /* Uplink L3 data transfer indication */ bytes += sizeof(ul_info_transfer_ind_t) - sizeof(Byte_t*); - nas_msg = &msg->msg.ul_info_transfer_ind.nasMsg; + nas_msg = msg->msg.ul_info_transfer_ind.nasMsg; break; case AS_DL_INFO_TRANSFER_REQ: /* Downlink L3 data transfer */ bytes += sizeof(dl_info_transfer_req_t) - sizeof(Byte_t*); - nas_msg = &msg->msg.dl_info_transfer_req.nasMsg; + nas_msg = msg->msg.dl_info_transfer_req.nasMsg; break; case AS_DL_INFO_TRANSFER_CNF: @@ -299,7 +312,8 @@ int as_message_encode(char* buffer, as_message_t* msg, int length) case AS_DL_INFO_TRANSFER_IND: /* Downlink L3 data transfer indication */ bytes += sizeof(dl_info_transfer_ind_t) - sizeof(Byte_t*); - nas_msg = &msg->msg.dl_info_transfer_ind.nasMsg; + nas_msg = msg->msg.dl_info_transfer_ind.nasMsg; + break; case AS_RAB_ESTABLISH_REQ: @@ -343,14 +357,14 @@ int as_message_encode(char* buffer, as_message_t* msg, int length) /* Encode the AS message */ memcpy(buffer, (unsigned char*)msg, bytes); - if ( nas_msg && (nas_msg->length > 0) ) { + if ( (dataptr!=NULL) && (len > 0) ) { /* Copy the NAS message */ - memcpy(buffer + bytes, nas_msg->data, nas_msg->length); - bytes += nas_msg->length; + memcpy(buffer + bytes, nas_msg.data, nas_msg.length); + bytes += len; /* Release NAS message memory */ - free(nas_msg->data); - nas_msg->length = 0; - nas_msg->data = NULL; + free(nas_msg.data); + len=0; + dataptr = NULL; } LOG_FUNC_RETURN (bytes); diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index e8596e66e9..2628c5b0b2 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -48,6 +48,8 @@ uint8_t *registration_request_buf; uint32_t registration_request_len; extern char *baseNetAddress; +extern uint16_t NB_UE_INST; +static ue_sa_security_key_t ** ue_security_key; static int nas_protected_security_header_encode( char *buffer, @@ -252,6 +254,108 @@ void derive_knas(algorithm_type_dist_t nas_alg_type, uint8_t nas_alg_id, uint8_t knas_int[i] = out[16 + i]; } +void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb){ + /* Compute the KDF input parameter + * S = FC(0x6E) || UL NAS Count || 0x00 0x04 || 0x01 || 0x00 0x01 + */ + uint8_t input[32]; + // uint16_t length = 4; + // int offset = 0; + uint8_t out[32] = { 0 }; + + LOG_TRACE(INFO, "%s with count= %d", __FUNCTION__, count); + memset(input, 0, 32); + input[0] = 0x6E; + // P0 + input[1] = count >> 24; + input[2] = (uint8_t)(count >> 16); + input[3] = (uint8_t)(count >> 8); + input[4] = (uint8_t)count; + // L0 + input[5] = 0; + input[6] = 4; + // P1 + input[7] = 0x01; + // L1 + input[8] = 0; + input[9] = 1; + + kdf(kamf, 32, input, 10, out, 32); + for (int i = 0; i < 32; i++) + kgnb[i] = out[i]; + printf("kgnb : "); + for(int pp=0;pp<32;pp++) + printf("%02x ",kgnb[pp]); + printf("\n"); +} + +void derive_ue_keys(int Mod_id, uint8_t *buf, uicc_t *uicc) { + uint8_t ak[6]; + uint8_t sqn[6]; + + AssertFatal (Mod_id < NB_UE_INST, "Failed, Mod_id %d is over NB_UE_INST!\n", Mod_id); + if(ue_security_key[Mod_id]){ + // clear old key + memset(ue_security_key[Mod_id],0,sizeof(ue_sa_security_key_t)); + }else{ + // Allocate new memory + ue_security_key[Mod_id]=(ue_sa_security_key_t *)calloc(1,sizeof(ue_sa_security_key_t)); + } + uint8_t *kausf = ue_security_key[Mod_id]->kausf; + uint8_t *kseaf = ue_security_key[Mod_id]->kseaf; + uint8_t *kamf = ue_security_key[Mod_id]->kamf; + uint8_t *knas_int = ue_security_key[Mod_id]->knas_int; + uint8_t *output = ue_security_key[Mod_id]->res; + uint8_t *rand = ue_security_key[Mod_id]->rand; + uint8_t *kgnb = ue_security_key[Mod_id]->kgnb; + + // get RAND for authentication request + for(int index = 0; index < 16;index++){ + rand[index] = buf[8+index]; + } + + uint8_t resTemp[16]; + uint8_t ck[16], ik[16]; + f2345(uicc->key, rand, resTemp, ck, ik, ak, uicc->opc); + + transferRES(ck, ik, resTemp, rand, output, uicc); + + for(int index = 0; index < 6; index++){ + sqn[index] = buf[26+index]; + } + + derive_kausf(ck, ik, sqn, kausf, uicc); + derive_kseaf(kausf, kseaf, uicc); + derive_kamf(kseaf, kamf, 0x0000, uicc); + derive_knas(0x02, 2, kamf, knas_int); + derive_kgnb(kamf,0,kgnb); + + printf("kausf:"); + for(int i = 0; i < 32; i++){ + printf("%x ", kausf[i]); + } + printf("\n"); + + printf("kseaf:"); + for(int i = 0; i < 32; i++){ + printf("%x ", kseaf[i]); + } + + printf("\n"); + + printf("kamf:"); + for(int i = 0; i < 32; i++){ + printf("%x ", kamf[i]); + } + printf("\n"); + + printf("knas_int:\n"); + for(int i = 0; i < 16; i++){ + printf("%x ", knas_int[i]); + } + printf("\n"); +} + void generateRegistrationRequest(as_nas_info_t *initialNasMsg, int Mod_id) { int size = sizeof(mm_msg_header_t); fgs_nas_message_t nas_msg={0}; @@ -374,69 +478,13 @@ void generateIdentityResponse(as_nas_info_t *initialNasMsg, uint8_t identitytype } -OctetString knas_int; -static void generateAuthenticationResp(as_nas_info_t *initialNasMsg, uint8_t *buf, uicc_t *uicc){ +static void generateAuthenticationResp(int Mod_id,as_nas_info_t *initialNasMsg, uint8_t *buf, uicc_t *uicc){ - uint8_t ak[6]; - - uint8_t kausf[32]; - uint8_t sqn[6]; - uint8_t kseaf[32]; - uint8_t kamf[32]; + derive_ue_keys(Mod_id,buf,uicc); OctetString res; - - // get RAND for authentication request - unsigned char rand[16]; - for(int index = 0; index < 16;index++){ - rand[index] = buf[8+index]; - } - - uint8_t resTemp[16]; - uint8_t ck[16], ik[16], output[16]; - f2345(uicc->key, rand, resTemp, ck, ik, ak, uicc->opc); - - transferRES(ck, ik, resTemp, rand, output, uicc); - - // get knas_int - knas_int.length = 16; - knas_int.value = malloc(knas_int.length); - for(int index = 0; index < 6; index++){ - sqn[index] = buf[26+index]; - } - - derive_kausf(ck, ik, sqn, kausf, uicc); - derive_kseaf(kausf, kseaf, uicc); - derive_kamf(kseaf, kamf, 0x0000, uicc); - derive_knas(0x02, 2, kamf, knas_int.value); - - printf("kausf:"); - for(int i = 0; i < 32; i++){ - printf("%x ", kausf[i]); - } - printf("\n"); - - printf("kseaf:"); - for(int i = 0; i < 32; i++){ - printf("%x ", kseaf[i]); - } - - printf("\n"); - - printf("kamf:"); - for(int i = 0; i < 32; i++){ - printf("%x ", kamf[i]); - } - printf("\n"); - - printf("knas_int:\n"); - for(int i = 0; i < 16; i++){ - printf("%x ", knas_int.value[i]); - } - printf("\n"); - - // set res res.length = 16; - res.value = output; + res.value = calloc(1,16); + memcpy(res.value,ue_security_key[Mod_id]->res,16); int size = sizeof(mm_msg_header_t); fgs_nas_message_t nas_msg; @@ -466,7 +514,14 @@ static void generateAuthenticationResp(as_nas_info_t *initialNasMsg, uint8_t *bu initialNasMsg->length = mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data), size); } -static void generateSecurityModeComplete(as_nas_info_t *initialNasMsg) +int nas_itti_kgnb_refresh_req(const uint8_t kgnb[32], int instance) { + MessageDef *message_p; + message_p = itti_alloc_new_message(TASK_NAS_NRUE, 0, NAS_KENB_REFRESH_REQ); + memcpy(NAS_KENB_REFRESH_REQ(message_p).kenb, kgnb, sizeof(NAS_KENB_REFRESH_REQ(message_p).kenb)); + return itti_send_msg_to_task(TASK_RRC_NRUE, instance, message_p); +} + +static void generateSecurityModeComplete(int Mod_id,as_nas_info_t *initialNasMsg) { int size = sizeof(mm_msg_header_t); fgs_nas_message_t nas_msg; @@ -513,7 +568,7 @@ static void generateSecurityModeComplete(as_nas_info_t *initialNasMsg) initialNasMsg->length = security_header_len + mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data+security_header_len), size-security_header_len); - stream_cipher.key = knas_int.value; + stream_cipher.key = ue_security_key[Mod_id]->knas_int; stream_cipher.key_length = 16; stream_cipher.count = 0; stream_cipher.bearer = 1; @@ -533,7 +588,7 @@ static void generateSecurityModeComplete(as_nas_info_t *initialNasMsg) } } -static void generateRegistrationComplete(as_nas_info_t *initialNasMsg, SORTransparentContainer *sortransparentcontainer) { +static void generateRegistrationComplete(int Mod_id, as_nas_info_t *initialNasMsg, SORTransparentContainer *sortransparentcontainer) { //wait send RRCReconfigurationComplete and InitialContextSetupResponse sleep(1); int length = 0; @@ -593,7 +648,7 @@ static void generateRegistrationComplete(as_nas_info_t *initialNasMsg, SORTransp } initialNasMsg->length = length; - stream_cipher.key = knas_int.value; + stream_cipher.key = ue_security_key[Mod_id]->knas_int; stream_cipher.key_length = 16; stream_cipher.count = 1; stream_cipher.bearer = 1; @@ -626,7 +681,7 @@ void decodeDownlinkNASTransport(as_nas_info_t *initialNasMsg, uint8_t * pdu_buff } } -static void generatePduSessionEstablishRequest(uicc_t * uicc, as_nas_info_t *initialNasMsg){ +static void generatePduSessionEstablishRequest(int Mod_id, uicc_t * uicc, as_nas_info_t *initialNasMsg){ //wait send RegistrationComplete usleep(100*150); int size = 0; @@ -700,7 +755,7 @@ static void generatePduSessionEstablishRequest(uicc_t * uicc, as_nas_info_t *ini initialNasMsg->length = security_header_len + mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data+security_header_len), size-security_header_len); - stream_cipher.key = knas_int.value; + stream_cipher.key = ue_security_key[Mod_id]->knas_int; stream_cipher.key_length = 16; stream_cipher.count = 0; stream_cipher.bearer = 1; @@ -754,6 +809,8 @@ void *nas_nrue_task(void *args_p) uint8_t msg_type = 0; uint8_t *pdu_buffer = NULL; + + ue_security_key=(ue_sa_security_key_t **)calloc(1,sizeof(ue_sa_security_key_t*)*NB_UE_INST); itti_mark_task_ready (TASK_NAS_NRUE); MSC_START_USE(); @@ -823,7 +880,7 @@ void *nas_nrue_task(void *args_p) as_nas_info_t initialNasMsg; memset(&initialNasMsg, 0, sizeof(as_nas_info_t)); - generateRegistrationComplete(&initialNasMsg, NULL); + generateRegistrationComplete(Mod_id,&initialNasMsg, NULL); if(initialNasMsg.length > 0){ MessageDef *message_p; message_p = itti_alloc_new_message(TASK_NAS_NRUE, 0, NAS_UPLINK_DATA_REQ); @@ -836,7 +893,7 @@ void *nas_nrue_task(void *args_p) as_nas_info_t pduEstablishMsg; memset(&pduEstablishMsg, 0, sizeof(as_nas_info_t)); - generatePduSessionEstablishRequest(uicc, &pduEstablishMsg); + generatePduSessionEstablishRequest(Mod_id, uicc, &pduEstablishMsg); if(pduEstablishMsg.length > 0){ MessageDef *message_p; message_p = itti_alloc_new_message(TASK_NAS_NRUE, 0, NAS_UPLINK_DATA_REQ); @@ -908,18 +965,20 @@ void *nas_nrue_task(void *args_p) msg_type = get_msg_type(pdu_buffer, NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length); switch(msg_type){ - case FGS_IDENTITY_REQUEST: - generateIdentityResponse(&initialNasMsg,*(pdu_buffer+3), uicc); - break; - case FGS_AUTHENTICATION_REQUEST: - generateAuthenticationResp(&initialNasMsg, pdu_buffer, uicc); - break; - case FGS_SECURITY_MODE_COMMAND: - generateSecurityModeComplete(&initialNasMsg); - break; - case FGS_DOWNLINK_NAS_TRANSPORT: - decodeDownlinkNASTransport(&initialNasMsg, pdu_buffer); - break; + + case FGS_IDENTITY_REQUEST: + generateIdentityResponse(&initialNasMsg,*(pdu_buffer+3), uicc); + break; + case FGS_AUTHENTICATION_REQUEST: + generateAuthenticationResp(Mod_id,&initialNasMsg, pdu_buffer, uicc); + break; + case FGS_SECURITY_MODE_COMMAND: + nas_itti_kgnb_refresh_req(ue_security_key[Mod_id]->kgnb, instance); + generateSecurityModeComplete(Mod_id,&initialNasMsg); + break; + case FGS_DOWNLINK_NAS_TRANSPORT: + decodeDownlinkNASTransport(&initialNasMsg, pdu_buffer); + break; case FGS_PDU_SESSION_ESTABLISHMENT_ACC: { uint8_t offset = 0; @@ -950,17 +1009,17 @@ void *nas_nrue_task(void *args_p) } } break; - - default: - LOG_W(NR_RRC,"unknow message type %d\n",msg_type); - break; - } - - if(initialNasMsg.length > 0){ - MessageDef *message_p; - message_p = itti_alloc_new_message(TASK_NAS_NRUE, 0, NAS_UPLINK_DATA_REQ); - NAS_UPLINK_DATA_REQ(message_p).UEid = Mod_id; - NAS_UPLINK_DATA_REQ(message_p).nasMsg.data = (uint8_t *)initialNasMsg.data; + default: + LOG_W(NR_RRC,"unknow message type %d\n",msg_type); + break; + } + + if(initialNasMsg.length > 0){ + MessageDef *message_p; + message_p = itti_alloc_new_message(TASK_NAS_NRUE, 0, NAS_UPLINK_DATA_REQ); + NAS_UPLINK_DATA_REQ(message_p).UEid = Mod_id; + NAS_UPLINK_DATA_REQ(message_p).nasMsg.data = (uint8_t *)initialNasMsg.data; + NAS_UPLINK_DATA_REQ(message_p).nasMsg.length = initialNasMsg.length; itti_send_msg_to_task(TASK_RRC_NRUE, instance, message_p); LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message\n"); diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.h b/openair3/NAS/NR_UE/nr_nas_msg_sim.h index fa7496da07..9655f87130 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.h +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.h @@ -69,6 +69,18 @@ #define PAYLOAD_CONTAINER_LENGTH_MIN 3 #define PAYLOAD_CONTAINER_LENGTH_MAX 65537 +/* Security Key for SA UE */ +typedef struct { + uint8_t kausf[32]; + uint8_t kseaf[32]; + uint8_t kamf[32]; + uint8_t knas_int[16]; + uint8_t res[16]; + uint8_t rand[16]; + uint8_t kgnb[32]; +} ue_sa_security_key_t; + + typedef enum fgs_protocol_discriminator_e { /* Protocol discriminator identifier for 5GS Mobility Management */ FGS_MOBILITY_MANAGEMENT_MESSAGE = 0x7E, diff --git a/openair3/NAS/UE/EMM/SAP/emm_as.c b/openair3/NAS/UE/EMM/SAP/emm_as.c index 10b118eac0..6b226be380 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_as.c +++ b/openair3/NAS/UE/EMM/SAP/emm_as.c @@ -136,17 +136,25 @@ static int _emm_as_encrypt( static int _emm_as_send(const nas_user_t *user, const emm_as_t *msg); -static int _emm_as_security_res(const emm_data_t *emm_data, const emm_as_security_t *, - ul_info_transfer_req_t *); -static int _emm_as_establish_req(const emm_data_t *emm_data, const emm_as_establish_t *, - nas_establish_req_t *); + + static int _emm_as_cell_info_req(const emm_as_cell_info_t *, cell_info_req_t *); - -static int _emm_as_data_req(const emm_data_t *emm_data, const emm_as_data_t *msg, ul_info_transfer_req_t *); -static int _emm_as_status_ind(const emm_data_t *emm_data, const emm_as_status_t *, ul_info_transfer_req_t *); -static int _emm_as_release_req(const emm_as_release_t *, nas_release_req_t *); +/* prototyping of the following function modified: the last parameter turned to a void pointer + * instead of a ponter to the union field of the as_msg packed structure. This is to avoid new warnings introduced + * from gcc V9 which warns when accessing fields in a packed structure which may result in an alignment problem + * at run time. Modifications allow gcc to know at compile time that it cannot assume any alignment for those pointers. + * On X86 this is not fatal, as at run time the problem can be fixed (but it's better for perf to avoid). On other + * processor as Arm i think it can end in seg fault + */ +static int _emm_as_security_res(const emm_data_t *emm_data, const emm_as_security_t *, + void *ul_info_transfer_req_unaligned); +static int _emm_as_establish_req(const emm_data_t *emm_data, const emm_as_establish_t *, + void *nas_establish_req_unaligned); +static int _emm_as_data_req(const emm_data_t *emm_data, const emm_as_data_t *msg, void *ul_info_transfer_req_unaligned); +static int _emm_as_status_ind(const emm_data_t *emm_data, const emm_as_status_t *, void *ul_info_transfer_req_unaligned); +static int _emm_as_release_req(const emm_as_release_t *, void *nas_release_req_unaligned); /****************************************************************************/ /****************** E X P O R T E D F U N C T I O N S ******************/ @@ -938,32 +946,32 @@ static int _emm_as_send(const nas_user_t *user, const emm_as_t *msg) case _EMMAS_DATA_REQ: as_msg.msgID = _emm_as_data_req(user->emm_data, &msg->u.data, - &as_msg.msg.ul_info_transfer_req); + (void *)(&as_msg.msg.ul_info_transfer_req)); break; case _EMMAS_STATUS_IND: as_msg.msgID = _emm_as_status_ind(user->emm_data, &msg->u.status, - &as_msg.msg.ul_info_transfer_req); + (void *)(&as_msg.msg.ul_info_transfer_req)); break; case _EMMAS_RELEASE_REQ: as_msg.msgID = _emm_as_release_req( &msg->u.release, - &as_msg.msg.nas_release_req); + (void *)(&as_msg.msg.nas_release_req)); break; case _EMMAS_SECURITY_RES: as_msg.msgID = _emm_as_security_res(user->emm_data, &msg->u.security, - &as_msg.msg.ul_info_transfer_req); + (void *)(&as_msg.msg.ul_info_transfer_req)); break; case _EMMAS_ESTABLISH_REQ: as_msg.msgID = _emm_as_establish_req(user->emm_data, &msg->u.establish, - &as_msg.msg.nas_establish_req); + (void *)(&as_msg.msg.nas_establish_req)); break; @@ -1069,10 +1077,10 @@ static int _emm_as_send(const nas_user_t *user, const emm_as_t *msg) ** ** ***************************************************************************/ static int _emm_as_data_req(const emm_data_t *emm_data, const emm_as_data_t *msg, - ul_info_transfer_req_t *as_msg) + void *ul_info_transfer_req_unaligned) { LOG_FUNC_IN; - + ul_info_transfer_req_t *as_msg = (ul_info_transfer_req_t *)ul_info_transfer_req_unaligned; int size = 0; int is_encoded = FALSE; @@ -1165,12 +1173,12 @@ static int _emm_as_data_req(const emm_data_t *emm_data, const emm_as_data_t *msg ** ** ***************************************************************************/ static int _emm_as_status_ind(const emm_data_t *emm_data, const emm_as_status_t *msg, - ul_info_transfer_req_t *as_msg) + void *ul_info_transfer_req_unaligned) { LOG_FUNC_IN; int size = 0; - + ul_info_transfer_req_t *as_msg = (ul_info_transfer_req_t *)ul_info_transfer_req_unaligned; LOG_TRACE(INFO, "EMMAS-SAP - Send AS status indication (cause=%d)", msg->emm_cause); @@ -1239,12 +1247,12 @@ static int _emm_as_status_ind(const emm_data_t *emm_data, const emm_as_status_t ** ** ***************************************************************************/ static int _emm_as_release_req(const emm_as_release_t *msg, - nas_release_req_t *as_msg) + void *nas_release_req_unaligned) { LOG_FUNC_IN; LOG_TRACE(INFO, "EMMAS-SAP - Send AS release request"); - + nas_release_req_t *as_msg = (nas_release_req_t *)nas_release_req_unaligned; /* Setup the AS message */ if (msg->guti) { as_msg->s_tmsi.MMEcode = msg->guti->gummei.MMEcode; @@ -1279,10 +1287,10 @@ static int _emm_as_release_req(const emm_as_release_t *msg, ** ** ***************************************************************************/ static int _emm_as_security_res(const emm_data_t *emm_data, const emm_as_security_t *msg, - ul_info_transfer_req_t *as_msg) + void *ul_info_transfer_req_unaligned) { LOG_FUNC_IN; - + ul_info_transfer_req_t *as_msg=(ul_info_transfer_req_t *)ul_info_transfer_req_unaligned; int size = 0; LOG_TRACE(INFO, "EMMAS-SAP - Send AS security response"); @@ -1373,12 +1381,12 @@ static int _emm_as_security_res(const emm_data_t *emm_data, const emm_as_securit ** ** ***************************************************************************/ static int _emm_as_establish_req(const emm_data_t *emm_data, const emm_as_establish_t *msg, - nas_establish_req_t *as_msg) + void *nas_establish_req_unaligned) { LOG_FUNC_IN; int size = 0; - + nas_establish_req_t *as_msg = (nas_establish_req_t *)nas_establish_req_unaligned; LOG_TRACE(INFO, "EMMAS-SAP - Send AS connection establish request"); nas_message_t nas_msg; diff --git a/openair3/NAS/UE/nas_network.c b/openair3/NAS/UE/nas_network.c index f8abba4900..f6b291bb7b 100644 --- a/openair3/NAS/UE/nas_network.c +++ b/openair3/NAS/UE/nas_network.c @@ -141,11 +141,11 @@ int nas_network_process_data(nas_user_t *user, int msg_id, const void *data) case AS_CELL_INFO_CNF: { /* Received cell information confirm */ - const cell_info_cnf_t *info = &msg->msg.cell_info_cnf; - int cell_found = (info->errCode == AS_SUCCESS); - rc = nas_proc_cell_info(user, cell_found, info->tac, - info->cellID, info->rat, - info->rsrp, info->rsrq); + /* remove using pointers to fiels of the packed structure msg as it + * triggers warnings with gcc version 9 */ + const cell_info_cnf_t info = msg->msg.cell_info_cnf; + int cell_found = (info.errCode == AS_SUCCESS); + rc = nas_proc_cell_info(user, cell_found, info.tac, info.cellID, info.rat, info.rsrp, info.rsrq); break; } @@ -157,12 +157,12 @@ int nas_network_process_data(nas_user_t *user, int msg_id, const void *data) case AS_NAS_ESTABLISH_CNF: { /* Received NAS signalling connection establishment confirm */ - const nas_establish_cnf_t *confirm = &msg->msg.nas_establish_cnf; + const nas_establish_cnf_t confirm = msg->msg.nas_establish_cnf; - if ( (confirm->errCode == AS_SUCCESS) || - (confirm->errCode == AS_TERMINATED_NAS) ) { - rc = nas_proc_establish_cnf(user, confirm->nasMsg.data, - confirm->nasMsg.length); + if ( (confirm.errCode == AS_SUCCESS) || + (confirm.errCode == AS_TERMINATED_NAS) ) { + rc = nas_proc_establish_cnf(user, confirm.nasMsg.data, + confirm.nasMsg.length); } else { LOG_TRACE(WARNING, "NET-MAIN - " "Initial NAS message not delivered"); @@ -191,10 +191,10 @@ int nas_network_process_data(nas_user_t *user, int msg_id, const void *data) break; case AS_DL_INFO_TRANSFER_IND: { - const dl_info_transfer_ind_t *info = &msg->msg.dl_info_transfer_ind; + const dl_info_transfer_ind_t info = msg->msg.dl_info_transfer_ind; /* Received downlink data transfer indication */ - rc = nas_proc_dl_transfer_ind(user, info->nasMsg.data, - info->nasMsg.length); + rc = nas_proc_dl_transfer_ind(user, info.nasMsg.data, + info.nasMsg.length); break; } diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index 401695473c..2b0e8aab7c 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -1127,12 +1127,11 @@ int ngap_gNB_handle_initial_context_request(uint32_t assoc_id, BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.eUTRAencryptionAlgorithms); NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).security_capabilities.eUTRAintegrity_algorithms = BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.eUTRAintegrityProtectionAlgorithms); - /* id-SecurityKey : Copy the security key */ } else {/* ie != NULL */ return -1; } - /* id-MobilityRestrictionList */ + /* id-SecurityKey : Copy the security key */ NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_SecurityKey, true); @@ -1144,7 +1143,7 @@ int ngap_gNB_handle_initial_context_request(uint32_t assoc_id, return -1; } - /* id-NAS-PDU */ + /* id-MobilityRestrictionList */ NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_MobilityRestrictionList, false); @@ -1160,6 +1159,7 @@ int ngap_gNB_handle_initial_context_request(uint32_t assoc_id, } + /* id-NAS-PDU */ NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_NAS_PDU, false); @@ -1171,7 +1171,6 @@ int ngap_gNB_handle_initial_context_request(uint32_t assoc_id, memcpy(NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).nas_pdu.buffer, ie->value.choice.NAS_PDU.buf, ie->value.choice.NAS_PDU.size); } - } itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p); diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index 86899520a0..78a130b672 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -17,6 +17,7 @@ extern "C" { #include #include #include +#include "openair2/SDAP/nr_sdap/nr_sdap_gnb.h" //#include #pragma pack(1) @@ -74,6 +75,12 @@ class gtpEndPoint { int ipVersion; map ue2te_mapping; map te2ue_mapping; + // we use the same port number for source and destination address + // this allow using non standard gtp port number (different from 2152) + // and so, for example tu run 4G and 5G cores on one system + tcp_udp_port_t get_dstport() { + return (tcp_udp_port_t)atol(addr.destinationService); + } }; class gtpEndPoints { @@ -99,6 +106,8 @@ instance_t legacyInstanceMapping=0; #define compatInst(a) ((a)==0 || (a)==INSTANCE_DEFAULT?legacyInstanceMapping:a) #define GTPV1U_HEADER_SIZE (8) + + static int gtpv1uCreateAndSendMsg(int h, uint32_t peerIp, uint16_t peerPort, teid_t teid, uint8_t *Msg,int msgLen, bool seqNumFlag, bool npduNumFlag, bool extHdrFlag, int seqNum, int npduNum, int extHdrType) { AssertFatal(extHdrFlag==false,"Not developped"); @@ -302,7 +311,6 @@ static int udpServerSocket(openAddr_s addr) { LOG_E(GTPU,"getaddrinfo error: %s\n", gai_strerror(status)); return -1; } - int sockfd=-1; // loop through all the results and bind to the first we can @@ -489,17 +497,18 @@ int ocp_gtpv1u_create_s1u_tunnel(instance_t instance, create_tunnel_req->rnti, create_tunnel_req->num_tunnels, create_tunnel_req->sgw_S1u_teid[0]); - + tcp_udp_port_t dstport=globGtp.instances[compatInst(instance)].get_dstport(); for (int i = 0; i < create_tunnel_req->num_tunnels; i++) { AssertFatal(create_tunnel_req->eps_bearer_id[i] > 4, "From legacy code not clear, seems impossible (bearer=%d)\n", create_tunnel_req->eps_bearer_id[i]); int incoming_rb_id=create_tunnel_req->eps_bearer_id[i]-4; - teid_t teid=newGtpuCreateTunnel(instance, create_tunnel_req->rnti, + + teid_t teid=newGtpuCreateTunnel(compatInst(instance), create_tunnel_req->rnti, incoming_rb_id, create_tunnel_req->eps_bearer_id[i], create_tunnel_req->sgw_S1u_teid[i], - create_tunnel_req->sgw_addr[i], 2152, + create_tunnel_req->sgw_addr[i], dstport, pdcp_data_req); create_tunnel_resp->status=0; create_tunnel_resp->rnti=create_tunnel_req->rnti; @@ -557,14 +566,14 @@ int gtpv1u_create_ngu_tunnel( const instance_t instance, create_tunnel_req->rnti, create_tunnel_req->num_tunnels, create_tunnel_req->outgoing_teid[0]); - + tcp_udp_port_t dstport=globGtp.instances[compatInst(instance)].get_dstport(); for (int i = 0; i < create_tunnel_req->num_tunnels; i++) { teid_t teid=newGtpuCreateTunnel(instance, create_tunnel_req->rnti, create_tunnel_req->incoming_rb_id[i], create_tunnel_req->pdusession_id[i], - create_tunnel_req->outgoing_teid[i], - create_tunnel_req->dst_addr[i], 2152, - pdcp_data_req); + create_tunnel_req->outgoing_teid[i], + create_tunnel_req->dst_addr[i], dstport, + sdap_gnb_data_req); create_tunnel_resp->status=0; create_tunnel_resp->rnti=create_tunnel_req->rnti; create_tunnel_resp->num_tunnels=create_tunnel_req->num_tunnels; @@ -894,17 +903,11 @@ void *ocp_gtpv1uTask(void *args) { abort(); break; - case GTPV1U_ENB_S1_REQ: + case GTPV1U_REQ: // to be dev: should be removed, to use API - strcpy(addr.originHost, GTPV1U_ENB_S1_REQ(message_p).addrStr); - strcpy(addr.originService, GTPV1U_ENB_S1_REQ(message_p).portStr); - AssertFatal((legacyInstanceMapping=ocp_gtpv1Init(addr))!=0,"Instance 0 reserved for legacy\n"); - break; - - case GTPV1U_GNB_NG_REQ: - // to be dev: should be removed, to use API - strcpy(addr.originHost, GTPV1U_GNB_NG_REQ(message_p).addrStr); - strcpy(addr.originService, GTPV1U_GNB_NG_REQ(message_p).portStr); + strcpy(addr.originHost, GTPV1U_REQ(message_p).localAddrStr); + strcpy(addr.originService, GTPV1U_REQ(message_p).localPortStr); + strcpy(addr.destinationService,addr.originService); AssertFatal((legacyInstanceMapping=ocp_gtpv1Init(addr))!=0,"Instance 0 reserved for legacy\n"); break; diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp index 877f607990..d268855566 100644 --- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp +++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp @@ -555,6 +555,7 @@ void *trx_usrp_write_thread(void * arg){ s->tx_md.start_of_burst = (s->tx_count==0) ? true : first_packet; s->tx_md.end_of_burst = last_packet; s->tx_md.time_spec = uhd::time_spec_t::from_ticks(timestamp, s->sample_rate); + LOG_D(PHY,"usrp_tx_write: tx_count %llu SoB %d, EoB %d, TS %llu\n",(unsigned long long)s->tx_count,s->tx_md.start_of_burst,s->tx_md.end_of_burst,(unsigned long long)timestamp); s->tx_count++; // bit 3 enables gpio (for backward compatibility) @@ -940,6 +941,7 @@ extern "C" { LOG_I(HW, "openair0_cfg[0].sdr_addrs == '%s'\n", openair0_cfg[0].sdr_addrs); LOG_I(HW, "openair0_cfg[0].clock_source == '%d' (internal = %d, external = %d)\n", openair0_cfg[0].clock_source,internal,external); usrp_state_t *s ; + int choffset = 0; if ( device->priv == NULL) { s=(usrp_state_t *)calloc(sizeof(usrp_state_t),1); @@ -1094,6 +1096,7 @@ extern "C" { if (device->type==USRP_X300_DEV) { openair0_cfg[0].rx_gain_calib_table = calib_table_x310; std::cerr << "-- Using calibration table: calib_table_x310" << std::endl; + s->usrp->set_rx_dc_offset(true); } if (device->type==USRP_N300_DEV) { @@ -1248,10 +1251,10 @@ extern "C" { for(int i=0; i<((int) s->usrp->get_rx_num_channels()); i++) { if (iusrp->set_rx_rate(openair0_cfg[0].sample_rate,i); - s->usrp->set_rx_freq(openair0_cfg[0].rx_freq[i],i); + s->usrp->set_rx_rate(openair0_cfg[0].sample_rate,i+choffset); + s->usrp->set_rx_freq(openair0_cfg[0].rx_freq[i],i+choffset); set_rx_gain_offset(&openair0_cfg[0],i,bw_gain_adjust); - ::uhd::gain_range_t gain_range = s->usrp->get_rx_gain_range(i); + ::uhd::gain_range_t gain_range = s->usrp->get_rx_gain_range(i+choffset); // limit to maximum gain double gain=openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i]; if ( gain > gain_range.stop()) { @@ -1260,7 +1263,7 @@ extern "C" { gain=gain_range.stop(); } - s->usrp->set_rx_gain(gain,i); + s->usrp->set_rx_gain(gain,i+choffset); LOG_I(HW,"RX Gain %d %f (%f) => %f (max %f)\n",i, openair0_cfg[0].rx_gain[i],openair0_cfg[0].rx_gain_offset[i], openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i],gain_range.stop()); @@ -1274,9 +1277,9 @@ extern "C" { ::uhd::gain_range_t gain_range_tx = s->usrp->get_tx_gain_range(i); if (iusrp->set_tx_rate(openair0_cfg[0].sample_rate,i); - s->usrp->set_tx_freq(openair0_cfg[0].tx_freq[i],i); - s->usrp->set_tx_gain(gain_range_tx.stop()-openair0_cfg[0].tx_gain[i],i); + s->usrp->set_tx_rate(openair0_cfg[0].sample_rate,i+choffset); + s->usrp->set_tx_freq(openair0_cfg[0].tx_freq[i],i+choffset); + s->usrp->set_tx_gain(gain_range_tx.stop()-openair0_cfg[0].tx_gain[i],i+choffset); LOG_I(HW,"USRP TX_GAIN:%3.2lf gain_range:%3.2lf tx_gain:%3.2lf\n", gain_range_tx.stop()-openair0_cfg[0].tx_gain[i], gain_range_tx.stop(), openair0_cfg[0].tx_gain[i]); } } @@ -1303,41 +1306,41 @@ extern "C" { s->usrp->get_rx_stream(stream_args_rx)->get_max_num_samps()); for (int i = 0; irx_stream = s->usrp->get_rx_stream(stream_args_rx); uhd::stream_args_t stream_args_tx("sc16", "sc16"); for (int i = 0; itx_stream = s->usrp->get_tx_stream(stream_args_tx); /* Setting TX/RX BW after streamers are created due to USRP calibration issue */ for(int i=0; i<((int) s->usrp->get_tx_num_channels()) && iusrp->set_tx_bandwidth(openair0_cfg[0].tx_bw,i); + s->usrp->set_tx_bandwidth(openair0_cfg[0].tx_bw,i+choffset); for(int i=0; i<((int) s->usrp->get_rx_num_channels()) && iusrp->set_rx_bandwidth(openair0_cfg[0].rx_bw,i); + s->usrp->set_rx_bandwidth(openair0_cfg[0].rx_bw,i+choffset); for (int i=0; iusrp->get_rx_rate(i)/1e6); - LOG_I(HW," Actual RX frequency: %fGHz...\n", s->usrp->get_rx_freq(i)/1e9); - LOG_I(HW," Actual RX gain: %f...\n", s->usrp->get_rx_gain(i)); - LOG_I(HW," Actual RX bandwidth: %fM...\n", s->usrp->get_rx_bandwidth(i)/1e6); - LOG_I(HW," Actual RX antenna: %s...\n", s->usrp->get_rx_antenna(i).c_str()); + LOG_I(HW," Actual RX sample rate: %fMSps...\n",s->usrp->get_rx_rate(i+choffset)/1e6); + LOG_I(HW," Actual RX frequency: %fGHz...\n", s->usrp->get_rx_freq(i+choffset)/1e9); + LOG_I(HW," Actual RX gain: %f...\n", s->usrp->get_rx_gain(i+choffset)); + LOG_I(HW," Actual RX bandwidth: %fM...\n", s->usrp->get_rx_bandwidth(i+choffset)/1e6); + LOG_I(HW," Actual RX antenna: %s...\n", s->usrp->get_rx_antenna(i+choffset).c_str()); } for (int i=0; iusrp->get_tx_rate(i)/1e6); - LOG_I(HW," Actual TX frequency: %fGHz...\n", s->usrp->get_tx_freq(i)/1e9); - LOG_I(HW," Actual TX gain: %f...\n", s->usrp->get_tx_gain(i)); - LOG_I(HW," Actual TX bandwidth: %fM...\n", s->usrp->get_tx_bandwidth(i)/1e6); - LOG_I(HW," Actual TX antenna: %s...\n", s->usrp->get_tx_antenna(i).c_str()); + LOG_I(HW," Actual TX sample rate: %fMSps...\n", s->usrp->get_tx_rate(i+choffset)/1e6); + LOG_I(HW," Actual TX frequency: %fGHz...\n", s->usrp->get_tx_freq(i+choffset)/1e9); + LOG_I(HW," Actual TX gain: %f...\n", s->usrp->get_tx_gain(i+choffset)); + LOG_I(HW," Actual TX bandwidth: %fM...\n", s->usrp->get_tx_bandwidth(i+choffset)/1e6); + LOG_I(HW," Actual TX antenna: %s...\n", s->usrp->get_tx_antenna(i+choffset).c_str()); LOG_I(HW," Actual TX packet size: %lu\n",s->tx_stream->get_max_num_samps()); } diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpn300.conf index 0fd0dd4551..0306fe5d0b 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpn300.conf @@ -268,6 +268,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf index 2c97e2cad3..c14ad17b42 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf @@ -252,6 +252,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf index 3ec84d34ce..ff0fdd96bb 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf @@ -247,6 +247,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf index 90ae80fb8d..937790d4ac 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf @@ -266,6 +266,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpn300.conf index cd57096e00..c9a95d59e8 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpn300.conf @@ -258,6 +258,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpx300.conf index 5230fa91ef..524407c4de 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpx300.conf @@ -258,6 +258,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.30kHz,usrpb2x0.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.30kHz,usrpb2x0.conf index f90adae46b..d191b67988 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.30kHz,usrpb2x0.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.30kHz,usrpb2x0.conf @@ -259,6 +259,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.slave.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.slave.conf index 51b252e1a4..2dfa329346 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.slave.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.slave.conf @@ -263,6 +263,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.slave.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.slave.conf index a0ee7f8a6d..7f0829e40a 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.slave.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.slave.conf @@ -261,6 +261,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.PTRS.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.PTRS.usrpx300.conf index 5530f33d65..6248afab2f 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.PTRS.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.PTRS.usrpx300.conf @@ -306,6 +306,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpb210.conf index 1cd08ec115..6f28cd36c1 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpb210.conf @@ -255,6 +255,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf index 8a5fbb740f..30194647b8 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf @@ -255,6 +255,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpx300.conf index 705fa277e0..fcbd3c0f02 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpx300.conf @@ -256,6 +256,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf index 7d8b80f83c..63123b8201 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf @@ -271,6 +271,23 @@ THREAD_STRUCT = ( # modelname = "AWGN"; #}; +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpx300.conf index a1a4972470..217ff76376 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpx300.conf @@ -246,6 +246,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpb210.conf index 44d238bce2..a1acfc313b 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpb210.conf @@ -258,6 +258,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpn300.conf index a4df8399ea..540dddad21 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpn300.conf @@ -256,6 +256,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpx300.conf index 2899f6982d..edc5eaa0d4 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpx300.conf @@ -256,6 +256,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.273PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.273PRB.usrpn300.conf index 2b646fcacd..362a280ccb 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.273PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.273PRB.usrpn300.conf @@ -247,6 +247,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf index 95b05f320b..b1c78bc978 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf @@ -268,12 +268,17 @@ security = { # preferred ciphering algorithms # the first one of the list that an UE supports in chosen # valid values: nea0, nea1, nea2, nea3 - ciphering_algorithms = ( "nea0", "nea2" ); + ciphering_algorithms = ( "nea0" ); # preferred integrity algorithms # the first one of the list that an UE supports in chosen # valid values: nia0, nia1, nia2, nia3 - integrity_algorithms = ( "nia0" ); + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; }; log_config : diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_24PRB.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_24PRB.conf index f7546cde79..96f2909031 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_24PRB.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_24PRB.conf @@ -288,6 +288,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_n310.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_n310.conf index 767459aecb..f51f59ae30 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_n310.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_n310.conf @@ -262,6 +262,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_nsa_n310.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_nsa_n310.conf new file mode 100644 index 0000000000..59e507ed3e --- /dev/null +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_nsa_n310.conf @@ -0,0 +1,296 @@ +Active_gNBs = ( "gNB-Eurecom-5GNRBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + + cell_type = "CELL_MACRO_GNB"; + + gNB_name = "gNB-Eurecom-5GNRBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + + plmn_list = ({mcc = 222; mnc = 01; mnc_length = 2;}); + + tr_s_preference = "local_mac" + + ////////// Physical parameters: + + ssb_SubcarrierOffset = 31; //0; + pdsch_AntennaPorts = 1; + pusch_AntennaPorts = 1; + pusch_TargetSNRx10 = 200; + pucch_TargetSNRx10 = 200; + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3600 MHz + 84 PRBs@30kHz SCS (same as initial BWP) + absoluteFrequencySSB = 641272; //641032; #641968; 641968=start of ssb at 3600MHz + 82 RBs 641032=center of SSB at center of cell + dl_frequencyBand = 78; + # this is 3600 MHz + dl_absoluteFrequencyPointA = 640000; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 106; + #initialDownlinkBWP + #genericParameters + # this is RBstart=84,L=13 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 6368; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 0; + initialDLBWPsearchSpaceZero = 0; + #pdsch-ConfigCommon + #pdschTimeDomainAllocationList (up to 16 entries) + initialDLBWPk0_0 = 0; #for DL slot + initialDLBWPmappingType_0 = 0; #0=typeA,1=typeB + initialDLBWPstartSymbolAndLength_0 = 40; #this is SS=1,L=13 + + initialDLBWPk0_1 = 0; #for mixed slot + initialDLBWPmappingType_1 = 0; + initialDLBWPstartSymbolAndLength_1 = 57; #this is SS=1,L=5 + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 106; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 6368; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 13; + preambleReceivedTargetPower = -100; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 5; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14; //15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, + +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + # pusch-ConfigCommon (up to 16 elements) + initialULBWPk2_0 = 2; # used for UL slot + initialULBWPmappingType_0 = 1 + initialULBWPstartSymbolAndLength_0 = 41; # this is SS=0 L=13 + + initialULBWPk2_1 = 2; # used for mixed slot + initialULBWPmappingType_1 = 1; + initialULBWPstartSymbolAndLength_1 = 24; # this is SS=10 L=2 + + initialULBWPk2_2 = 7; # used for Msg.3 during RA + initialULBWPmappingType_2 = 1; + initialULBWPstartSymbolAndLength_2 = 52; # this is SS=10 L=4 + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; +# ssb_PositionsInBurs_BitmapPR +# 1=short, 2=medium, 3=long + ssb_PositionsInBurst_PR = 2; + ssb_PositionsInBurst_Bitmap = 1; #0x80; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; //8; //7; + nrofDownlinkSymbols = 6; //0; //6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; //0; //4; + + ssPBCH_BlockPower = -25; + } + + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// MME parameters: + amf_ip_address = ( { ipv4 = "192.168.18.99"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + ///X2 + enable_x2 = "yes"; + t_reloc_prep = 1000; /* unit: millisecond */ + tx2_reloc_overall = 2000; /* unit: millisecond */ + t_dc_prep = 1000; /* unit: millisecond */ + t_dc_overall = 2000; /* unit: millisecond */ + target_enb_x2_ip_address = ( + { ipv4 = "192.168.18.199"; + ipv6 = "192:168:30::17"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + + GNB_INTERFACE_NAME_FOR_NG_AMF = "eth0"; + GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.18.198/24"; + GNB_INTERFACE_NAME_FOR_NGU = "eth0"; + GNB_IPV4_ADDRESS_FOR_NGU = "192.168.18.198/24"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + GNB_IPV4_ADDRESS_FOR_X2C = "192.168.18.198/24"; + GNB_PORT_FOR_X2C = 36422; # Spec 36422 + }; + } +); + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + } +); + +L1s = ( + { + num_cc = 1; + tr_n_preference = "local_mac"; + pusch_proc_threads = 8; + } +); + +RUs = ( + { + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0 + att_rx = 0; + bands = [7]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 75; + eNB_instances = [0]; + sdr_addrs = "mgmt_addr=192.168.18.252,addr=192.168.80.50,clock_source=internal,time_source= internal" + #clock_src = "external"; + } +); + +THREAD_STRUCT = ( + { + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_RU_L1_TRX_SPLIT"; + //parallel_config = "PARALLEL_SINGLE_THREAD"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; + } +); + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0", "nea2" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia0" ); +}; + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; + diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf index 05e441d396..ca11c5f852 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf @@ -79,7 +79,7 @@ gNBs = # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 initialDLBWPsubcarrierSpacing = 1; #pdcch-ConfigCommon - initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPcontrolResourceSetZero = 11; initialDLBWPsearchSpaceZero = 0; #pdsch-ConfigCommon #pdschTimeDomainAllocationList (up to 16 entries) @@ -88,22 +88,12 @@ gNBs = #0=typeA,1=typeB initialDLBWPmappingType_0 = 0; #this is SS=1,L=13 - initialDLBWPstartSymbolAndLength_0 = 53; + initialDLBWPstartSymbolAndLength_0 = 40; initialDLBWPk0_1 = 0; initialDLBWPmappingType_1 = 0; #this is SS=2,L=12 - initialDLBWPstartSymbolAndLength_1 = 81; - - initialDLBWPk0_2 = 0; - initialDLBWPmappingType_2 = 0; - #this is SS=1,L=12 - initialDLBWPstartSymbolAndLength_2 = 54; - - initialDLBWPk0_3 = 0; - initialDLBWPmappingType_3 = 0; - #this is SS=1,L=5 - initialDLBWPstartSymbolAndLength_3 = 57; + initialDLBWPstartSymbolAndLength_1 = 57; #uplinkConfigCommon #frequencyInfoUL @@ -162,12 +152,12 @@ gNBs = initialULBWPk2_0 = 6; initialULBWPmappingType_0 = 1 # this is SS=2 L=12 - initialULBWPstartSymbolAndLength_0 = 53; + initialULBWPstartSymbolAndLength_0 = 41; initialULBWPk2_1 = 6; initialULBWPmappingType_1 = 1; # this is SS=0 L=12 - initialULBWPstartSymbolAndLength_1 = 69; + initialULBWPstartSymbolAndLength_1 = 52; initialULBWPk2_2 = 7; initialULBWPmappingType_2 = 1; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf index 1b0c15ea7a..3bd884b602 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf @@ -283,6 +283,23 @@ THREAD_STRUCT = ( } ); +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf index 3fd543f70f..62b89188f9 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf @@ -230,8 +230,7 @@ MACRLCs = ( num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "local_RRC"; - ulsch_max_slots_inactivity = 100; - pusch_TargetSNRx10 = 200; + pusch_TargetSNRx10 = 150; pucch_TargetSNRx10 = 200; } ); @@ -241,7 +240,9 @@ L1s = ( num_cc = 1; tr_n_preference = "local_mac"; pusch_proc_threads = 8; - ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 + prach_dtx_threshold = 120; + pucch0_dtx_threshold = 150; + ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 } ); @@ -252,7 +253,7 @@ RUs = ( nb_rx = 1 att_tx = 0 att_rx = 0; - bands = [7]; + bands = [41]; max_pdschReferenceSignalPower = -27; max_rxgain = 114; eNB_instances = [0]; @@ -280,6 +281,23 @@ rfsimulator : IQfile = "/tmp/rfsimulator.iqs"; }; +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf index e69607ee57..ac8622fbc5 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf @@ -66,7 +66,7 @@ gNBs = #initialDownlinkBWP #genericParameters # this is RBstart=27,L=48 (275*(L-1))+RBstart - initialDLBWPlocationAndBandwidth = 12952; # 6366 12925 12956 28875 12952 + initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952 # subcarrierSpacing # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 initialDLBWPsubcarrierSpacing = 1; @@ -95,7 +95,7 @@ gNBs = pMax = 20; #initialUplinkBWP #genericParameters - initialULBWPlocationAndBandwidth = 12952; + initialULBWPlocationAndBandwidth = 28875; # subcarrierSpacing # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 initialULBWPsubcarrierSpacing = 1; @@ -230,8 +230,7 @@ MACRLCs = ( num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "local_RRC"; - ulsch_max_slots_inactivity = 100; - pusch_TargetSNRx10 = 200; + pusch_TargetSNRx10 = 150; pucch_TargetSNRx10 = 200; } ); @@ -241,7 +240,9 @@ L1s = ( num_cc = 1; tr_n_preference = "local_mac"; pusch_proc_threads = 8; - ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 + prach_dtx_threshold = 120; + pucch0_dtx_threshold = 150; + ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 } ); @@ -252,7 +253,7 @@ RUs = ( nb_rx = 1 att_tx = 0 att_rx = 0; - bands = [7]; + bands = [78]; max_pdschReferenceSignalPower = -27; max_rxgain = 114; eNB_instances = [0]; @@ -280,6 +281,23 @@ rfsimulator : IQfile = "/tmp/rfsimulator.iqs"; }; +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.sabox.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.sabox.conf index 9892f97467..a0d25053b6 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.sabox.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.sabox.conf @@ -306,6 +306,23 @@ rfsimulator : IQfile = "/tmp/rfsimulator.iqs"; }; +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + log_config : { global_log_level ="info"; From 12792eece7910dcb2a1f6eff4ddd84b687f849bf Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Fri, 19 Nov 2021 18:52:51 +0100 Subject: [PATCH 023/267] Modifications in the cellGroupConfig container content of F1 UE context response messages --- openair2/RRC/NR/rrc_gNB.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 8dcf0caafa..8aabd29a20 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2783,12 +2783,12 @@ rrc_gNB_decode_dcch( ul_dcch_msg->message.choice.c1->choice.ueCapabilityInformation->criticalExtensions.choice.ueCapabilityInformation->ue_CapabilityRAT_ContainerList; req->cu_to_du_rrc_information = calloc(1,sizeof(cu_to_du_rrc_information_t)); - req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList = calloc(1,1024); + req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList = calloc(1,4096); asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_UE_CapabilityRAT_ContainerList, NULL, (void *)ue_CapabilityRAT_ContainerList, req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, - 1024); + 4096); AssertFatal (enc_rval.encoded > 0, "ASN1 ue_CapabilityRAT_ContainerList encoding failed (%s, %jd)!\n", enc_rval.failed_type->name, enc_rval.encoded); req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length = (enc_rval.encoded+7)>>3; @@ -3287,7 +3287,7 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha SEQUENCE_free( &asn_DEF_NR_UE_CapabilityRAT_ContainerList, ue_CapabilityRAT_ContainerList, 1 ); return; } - /*To fill ue_context.UE_Capability_MRDC, ue_context.UE_Capability_nr ...*/ + //To fill ue_context.UE_Capability_MRDC, ue_context.UE_Capability_nr ... int NR_index = -1; for(int i = 0;i < ue_CapabilityRAT_ContainerList->list.count; i++){ if(ue_CapabilityRAT_ContainerList->list.array[i]->rat_Type == @@ -3470,7 +3470,7 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha resp->du_to_cu_rrc_information = calloc(1,1024*sizeof(uint8_t)); asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, - (void *)cellGroupConfig, + ue_context_p->ue_context.masterCellGroup, //(void *)cellGroupConfig, resp->du_to_cu_rrc_information, 1024); if (enc_rval.encoded == -1) { @@ -3596,15 +3596,15 @@ static void rrc_DU_process_ue_context_modification_request(MessageDef *msg_p, co LOG_W(NR_RRC, "No SRB added upon reception of F1 UE Context modification request at the DU\n"); } - if(cellGroupConfig != NULL) { + //if(cellGroupConfig != NULL) { resp->du_to_cu_rrc_information = calloc(1,1024*sizeof(uint8_t)); asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, - (void *)cellGroupConfig, + ue_context_p->ue_context.masterCellGroup, //(void *)cellGroupConfig, resp->du_to_cu_rrc_information, 1024); resp->du_to_cu_rrc_information_length = (enc_rval.encoded+7)>>3; - } + //} itti_send_msg_to_task (TASK_DU_F1, ctxt.module_id, message_p); } From 2d4453648f699a55afae575241aa224418b94ce3 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Wed, 15 Dec 2021 18:38:25 +0100 Subject: [PATCH 024/267] Correct how gtp-u extension header is parsed --- openair2/F1AP/f1ap_cu_ue_context_management.c | 2 +- openair3/ocp-gtpu/gtp_itf.cpp | 21 +++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index 141d89ac51..037be0c8d4 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -144,7 +144,7 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(instance_t instance, if(f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList!=NULL){ asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList, uE_CapabilityRAT_ContainerList ); OCTET_STRING_fromBuf(uE_CapabilityRAT_ContainerList, (const char *)f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, - f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length) ; + f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length); } /* optional */ /* 6.3 measConfig */ diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index 59aeb824fb..585a7d5a4b 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -758,10 +758,27 @@ static int Gtpv1uHandleGpdu(int h, return GTPNOK; } - int offset=8; + /*int offset=8; if( msgHdr->E || msgHdr->S ||msgHdr->PN) - offset+=8; + offset+=8;*/ + + +//Minimum length of GTP-U header if non of the optional fields are present + int offset= sizeof(Gtpv1uMsgHeaderT); + + //Consider additional length for GTP-U header if at least one of the optional fields is present + if( msgHdr->E || msgHdr->S ||msgHdr->PN) + offset+=4; + + //Consider the length of 1 or more extension headers that can be present in the GTP-U PDU + if(msgHdr->E) { + while (msgBuf[offset]!=0) { + LOG_D(GTPU, "Extension header length in multiple of 4 bytes is: %d \n", msgBuf[offset]); + offset+=msgBuf[offset]*4 -1; + } + offset++; + } // This context is not good for gtp // frame, ... has no meaning From 0d86181a58865368fc0dfcdbcff9a23a5119c894 Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 20 Jan 2022 18:56:44 +0100 Subject: [PATCH 025/267] using uid also in SA --- openair2/RRC/NR/L2_nr_interface.c | 16 ++++++++-------- openair2/RRC/NR/MESSAGES/asn1_msg.c | 13 ++++++------- openair2/RRC/NR/MESSAGES/asn1_msg.h | 4 ++-- openair2/RRC/NR/rrc_gNB_reconfig.c | 2 -- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/openair2/RRC/NR/L2_nr_interface.c b/openair2/RRC/NR/L2_nr_interface.c index eb402092b9..2040c3e11e 100644 --- a/openair2/RRC/NR/L2_nr_interface.c +++ b/openair2/RRC/NR/L2_nr_interface.c @@ -325,7 +325,14 @@ int8_t nr_mac_rrc_data_ind(const module_id_t module_idP, NR_ServingCellConfigCommon_t *scc=RC.nrrrc[module_idP]->carrier.servingcellconfigcommon; memset(&cellGroupConfig,0,sizeof(cellGroupConfig)); - fill_initial_cellGroupConfig(rntiP,&cellGroupConfig,scc,&RC.nrrrc[module_idP]->carrier); + struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_allocate_new_UE_context(RC.nrrrc[module_idP]); + ue_context_p->ue_id_rnti = rntiP; + ue_context_p->ue_context.rnti = rntiP; + ue_context_p->ue_context.random_ue_identity = rntiP; + ue_context_p->ue_context.Srb0.Active = 1; + RB_INSERT(rrc_nr_ue_tree_s, &RC.nrrrc[module_idP]->rrc_ue_head, ue_context_p); + + fill_initial_cellGroupConfig(ue_context_p->local_uid,&cellGroupConfig,scc,&RC.nrrrc[module_idP]->carrier); MessageDef* tmp=itti_alloc_new_message_sized(TASK_RRC_GNB, 0, F1AP_INITIAL_UL_RRC_MESSAGE, sizeof(f1ap_initial_ul_rrc_message_t) + sdu_lenP); f1ap_initial_ul_rrc_message_t *msg = &F1AP_INITIAL_UL_RRC_MESSAGE(tmp); @@ -347,13 +354,6 @@ int8_t nr_mac_rrc_data_ind(const module_id_t module_idP, msg->rrc_container_length=sdu_lenP; itti_send_msg_to_task(TASK_DU_F1, 0, tmp); - struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_allocate_new_UE_context(RC.nrrrc[module_idP]); - ue_context_p->ue_id_rnti = rntiP; - ue_context_p->ue_context.rnti = rntiP; - ue_context_p->ue_context.random_ue_identity = rntiP; - ue_context_p->ue_context.Srb0.Active = 1; - RB_INSERT(rrc_nr_ue_tree_s, &RC.nrrrc[module_idP]->rrc_ue_head, ue_context_p); - return(0); } diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 84a0cf75d1..ecaaabe045 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -976,7 +976,7 @@ uint8_t do_RRCReject(uint8_t Mod_id, return((enc_rval.encoded+7)/8); } -void fill_initial_SpCellConfig(rnti_t rnti, +void fill_initial_SpCellConfig(int uid, NR_SpCellConfig_t *SpCellConfig, NR_ServingCellConfigCommon_t *scc, rrc_gNB_carrier_data_t *carrier) { @@ -1009,9 +1009,8 @@ void fill_initial_SpCellConfig(rnti_t rnti, // one symbol (13) NR_PUCCH_Resource_t *pucchres0=calloc(1,sizeof(*pucchres0)); pucchres0->pucch_ResourceId=0; - //pucchres0->startingPRB=0; - pucchres0->startingPRB=(8+rnti) % curr_bwp; - LOG_D(NR_RRC, "pucchres0->startPRB %ld rnti %d curr_bwp %d\n", pucchres0->startingPRB, rnti, curr_bwp); + pucchres0->startingPRB=(8+uid) % curr_bwp; + LOG_D(NR_RRC, "pucchres0->startPRB %ld uid %d curr_bwp %d\n", pucchres0->startingPRB, uid, curr_bwp); pucchres0->intraSlotFrequencyHopping=NULL; pucchres0->secondHopPRB=NULL; pucchres0->format.present= NR_PUCCH_Resource__format_PR_format0; @@ -1396,7 +1395,7 @@ void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGr ASN_SEQUENCE_ADD(&ue_context_mastercellGroup->rlc_BearerToAddModList->list, rlc_BearerConfig_drb); } -void fill_initial_cellGroupConfig(rnti_t rnti, +void fill_initial_cellGroupConfig(int uid, NR_CellGroupConfig_t *cellGroupConfig, NR_ServingCellConfigCommon_t *scc, rrc_gNB_carrier_data_t *carrier) { @@ -1490,7 +1489,7 @@ void fill_initial_cellGroupConfig(rnti_t rnti, cellGroupConfig->spCellConfig = calloc(1,sizeof(*cellGroupConfig->spCellConfig)); - fill_initial_SpCellConfig(rnti,cellGroupConfig->spCellConfig,scc,carrier); + fill_initial_SpCellConfig(uid,cellGroupConfig->spCellConfig,scc,carrier); cellGroupConfig->sCellToAddModList = NULL; cellGroupConfig->sCellToReleaseList = NULL; @@ -1569,7 +1568,7 @@ uint8_t do_RRCSetup(rrc_gNB_ue_context_t *const ue_context_pP, } else { cellGroupConfig = calloc(1, sizeof(NR_CellGroupConfig_t)); - fill_initial_cellGroupConfig(ue_context_pP->ue_context.rnti,cellGroupConfig,scc,carrier); + fill_initial_cellGroupConfig(ue_context_pP->local_uid,cellGroupConfig,scc,carrier); enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 6803cf21d7..cb971acd60 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -100,12 +100,12 @@ void do_SpCellConfig(gNB_RRC_INST *rrc, uint8_t do_RRCReject(uint8_t Mod_id, uint8_t *const buffer); -void fill_initial_SpCellConfig(rnti_t rnti, +void fill_initial_SpCellConfig(int uid, NR_SpCellConfig_t *SpCellConfig, NR_ServingCellConfigCommon_t *scc, rrc_gNB_carrier_data_t *carrier); -void fill_initial_cellGroupConfig(rnti_t rnti, +void fill_initial_cellGroupConfig(int uid, NR_CellGroupConfig_t *cellGroupConfig, NR_ServingCellConfigCommon_t *scc, rrc_gNB_carrier_data_t *carrier); diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index 30604cd015..1bde92568c 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -889,9 +889,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco pucch_Config->resourceToAddModList = calloc(1,sizeof(*pucch_Config->resourceToAddModList)); pucch_Config->resourceToReleaseList = NULL; NR_PUCCH_Resource_t *pucchres0=calloc(1,sizeof(*pucchres0)); - NR_PUCCH_Resource_t *pucchres1=calloc(1,sizeof(*pucchres1)); NR_PUCCH_Resource_t *pucchres2=calloc(1,sizeof(*pucchres2)); - NR_PUCCH_Resource_t *pucchres3=calloc(1,sizeof(*pucchres3)); pucchres0->pucch_ResourceId=1; pucchres0->startingPRB= (8 + uid) % curr_bwp; From 299ba03b841ab63dc930bebf2a32f0512e8ac8f2 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 22 Dec 2021 10:43:08 +0100 Subject: [PATCH 026/267] passing UECAP structure to RRC reconfiguration functions --- openair1/SIMULATION/NR_PHY/dlsim.c | 3 ++- openair1/SIMULATION/NR_PHY/ulsim.c | 3 ++- openair2/RRC/NR/MESSAGES/asn1_msg.c | 20 +++++++++++--------- openair2/RRC/NR/MESSAGES/asn1_msg.h | 6 ++++++ openair2/RRC/NR/nr_rrc_proto.h | 2 ++ openair2/RRC/NR/rrc_gNB.c | 8 ++++++++ openair2/RRC/NR/rrc_gNB_nsa.c | 2 ++ openair2/RRC/NR/rrc_gNB_reconfig.c | 3 +++ 8 files changed, 36 insertions(+), 11 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 84c6c3ee5f..8e84c830fc 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -775,7 +775,8 @@ int main(int argc, char **argv) prepare_scd(scd); - fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, 0, 1, n_tx, 6, 0, 0, 0); + // TODO do a UECAP for phy-sim + fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, NULL, 0, 1, n_tx, 6, 0, 0, 0); /* RRC parameter validation for secondaryCellGroup */ fix_scd(scd); diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index db8d54f86d..fc7b7c6372 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -716,7 +716,8 @@ int main(int argc, char **argv) prepare_scd(scd); - fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, 0, 1, n_tx, 0, 0, 0, 0); + // TODO do a UECAP for phy-sim + fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, NULL, 0, 1, n_tx, 0, 0, 0, 0); // xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup); diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index ecaaabe045..6c209381af 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1395,6 +1395,12 @@ void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGr ASN_SEQUENCE_ADD(&ue_context_mastercellGroup->rlc_BearerToAddModList->list, rlc_BearerConfig_drb); } +void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, + rrc_gNB_carrier_data_t *carrier, + NR_UE_NR_Capability_t *uecap) { + +} + void fill_initial_cellGroupConfig(int uid, NR_CellGroupConfig_t *cellGroupConfig, NR_ServingCellConfigCommon_t *scc, @@ -1814,6 +1820,8 @@ int16_t do_RRCReconfiguration( NR_SDAP_Config_t *sdap_config, NR_MeasConfig_t *meas_config, struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList, + rrc_gNB_ue_context_t *const ue_context_pP, + rrc_gNB_carrier_data_t *carrier, NR_MAC_CellGroupConfig_t *mac_CellGroupConfig, NR_CellGroupConfig_t *cellGroupConfig) //------------------------------------------------------------------------------ @@ -1850,15 +1858,6 @@ int16_t do_RRCReconfiguration( ie->radioBearerConfig->srb3_ToRelease = NULL; ie->radioBearerConfig->drb_ToReleaseList = DRB_releaseList; } - /******************** Secondary Cell Group ********************/ - // rrc_gNB_carrier_data_t *carrier = &(gnb_rrc_inst->carrier); - // fill_default_secondaryCellGroup( carrier->servingcellconfigcommon, - // ue_context_pP->ue_context.secondaryCellGroup, - // 1, - // 1, - // carrier->pdsch_AntennaPorts, - // carrier->initial_csi_index[ue_context_p->local_uid + 1], - // ue_context_pP->local_uid); /******************** Meas Config ********************/ // measConfig @@ -1874,6 +1873,9 @@ int16_t do_RRCReconfiguration( } if(cellGroupConfig!=NULL){ + update_cellGroupConfig(cellGroupConfig, + carrier, + ue_context_pP->ue_context.UE_Capability_nr); enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, (void *)cellGroupConfig, diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index cb971acd60..7fe08704c2 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -110,6 +110,10 @@ void fill_initial_cellGroupConfig(int uid, NR_ServingCellConfigCommon_t *scc, rrc_gNB_carrier_data_t *carrier); +void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, + rrc_gNB_carrier_data_t *carrier, + NR_UE_NR_Capability_t *uecap); + void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGroupConfig_t *ue_context_mastercellGroup); uint8_t do_RRCSetup(rrc_gNB_ue_context_t *const ue_context_pP, @@ -145,6 +149,8 @@ int16_t do_RRCReconfiguration( NR_SDAP_Config_t *sdap_config, NR_MeasConfig_t *meas_config, struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList, + rrc_gNB_ue_context_t *const ue_context_pP, + rrc_gNB_carrier_data_t *carrier, NR_MAC_CellGroupConfig_t *mac_CellGroupConfig, NR_CellGroupConfig_t *cellGroupConfig); diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 22109c3029..7309bcf2d9 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -76,6 +76,7 @@ void rrc_remove_nsa_user(gNB_RRC_INST *rrc, int rnti); void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellconfigcommon, NR_ServingCellConfig_t *servingcellconfigdedicated, NR_CellGroupConfig_t *secondaryCellGroup, + NR_UE_NR_Capability_t *uecap, int scg_id, int servCellIndex, int dl_antenna_ports, @@ -90,6 +91,7 @@ void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon NR_ServingCellConfig_t *servingcellconfigdedicated, NR_RRCReconfiguration_IEs_t *reconfig, NR_CellGroupConfig_t *secondaryCellGroup, + NR_UE_NR_Capability_t *uecap, int dl_antenna_ports, int minRXTXTIMEpdsch, int do_csirs, diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 2c2020412d..7824d4c85b 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -759,6 +759,8 @@ rrc_gNB_generate_defaultRRCReconfiguration( NULL, dedicatedNAS_MessageList, NULL, + NULL, + NULL, NULL); free(ue_context_pP->ue_context.nas_pdu.buffer); @@ -1028,6 +1030,8 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( NULL, NULL, dedicatedNAS_MessageList, + ue_context_pP, + &rrc->carrier, NULL, cellGroupConfig); LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size,"[MSG] RRC Reconfiguration\n"); @@ -1137,6 +1141,8 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( NULL, dedicatedNAS_MessageList, NULL, + NULL, + NULL, NULL); ue_context_pP->ue_context.pdu_session_release_command_flag = 1; @@ -1706,6 +1712,8 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete( NULL, // MeasObj_list, NULL, NULL, + NULL, + NULL, NULL); LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, "[MSG] RRC Reconfiguration\n"); diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index 15caff0b4d..42a39a4fa8 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -266,6 +266,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ ue_context_p->ue_context.spCellConfig->spCellConfigDedicated, reconfig_ies, ue_context_p->ue_context.secondaryCellGroup, + ue_context_p->ue_context.UE_Capability_nr, carrier->pdsch_AntennaPorts, carrier->minRXTXTIME, carrier->do_CSIRS, @@ -276,6 +277,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ NULL, reconfig_ies, ue_context_p->ue_context.secondaryCellGroup, + ue_context_p->ue_context.UE_Capability_nr, carrier->pdsch_AntennaPorts, carrier->minRXTXTIME, carrier->do_CSIRS, diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index 1bde92568c..d35c5bf7a2 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -52,6 +52,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellconfigcommon, NR_ServingCellConfig_t *servingcellconfigdedicated, NR_CellGroupConfig_t *secondaryCellGroup, + NR_UE_NR_Capability_t *uecap, int scg_id, int servCellIndex, int dl_antenna_ports, @@ -1346,6 +1347,7 @@ void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon NR_ServingCellConfig_t *servingcellconfigdedicated, NR_RRCReconfiguration_IEs_t *reconfig, NR_CellGroupConfig_t *secondaryCellGroup, + NR_UE_NR_Capability_t *uecap, int dl_antenna_ports, int minRXTXTIME, int do_csirs, @@ -1360,6 +1362,7 @@ void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon fill_default_secondaryCellGroup(servingcellconfigcommon, servingcellconfigdedicated, secondaryCellGroup, + uecap, 1, 1, dl_antenna_ports, From dd6dac13928dc5c93ad4529854d5fd550a76c389 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 21 Jan 2022 16:16:02 +0100 Subject: [PATCH 027/267] function to configure pucch resource set 0 --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 24 ++-------------------- openair2/RRC/NR/nr_rrc_config.c | 29 +++++++++++++++++++++++++++ openair2/RRC/NR/nr_rrc_config.h | 2 +- openair2/RRC/NR/rrc_gNB_reconfig.c | 31 +++++++---------------------- 4 files changed, 39 insertions(+), 47 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 6c209381af..dce972ab3a 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -995,30 +995,10 @@ void fill_initial_SpCellConfig(int uid, initialUplinkBWP->pucch_Config->choice.setup=pucch_Config; pucch_Config->resourceSetToAddModList = calloc(1,sizeof(*pucch_Config->resourceSetToAddModList)); pucch_Config->resourceSetToReleaseList = NULL; - NR_PUCCH_ResourceSet_t *pucchresset0=calloc(1,sizeof(*pucchresset0)); - pucchresset0->pucch_ResourceSetId = 0; - NR_PUCCH_ResourceId_t *pucchresset0id0=calloc(1,sizeof(*pucchresset0id0)); - *pucchresset0id0=0; - ASN_SEQUENCE_ADD(&pucchresset0->resourceList.list,pucchresset0id0); - pucchresset0->maxPayloadSize=NULL; - ASN_SEQUENCE_ADD(&pucch_Config->resourceSetToAddModList->list,pucchresset0); - pucch_Config->resourceToAddModList = calloc(1,sizeof(*pucch_Config->resourceToAddModList)); pucch_Config->resourceToReleaseList = NULL; - // configure one single PUCCH0 opportunity for initial connection procedure - // one symbol (13) - NR_PUCCH_Resource_t *pucchres0=calloc(1,sizeof(*pucchres0)); - pucchres0->pucch_ResourceId=0; - pucchres0->startingPRB=(8+uid) % curr_bwp; - LOG_D(NR_RRC, "pucchres0->startPRB %ld uid %d curr_bwp %d\n", pucchres0->startingPRB, uid, curr_bwp); - pucchres0->intraSlotFrequencyHopping=NULL; - pucchres0->secondHopPRB=NULL; - pucchres0->format.present= NR_PUCCH_Resource__format_PR_format0; - pucchres0->format.choice.format0=calloc(1,sizeof(*pucchres0->format.choice.format0)); - pucchres0->format.choice.format0->initialCyclicShift=0; - pucchres0->format.choice.format0->nrofSymbols=1; - pucchres0->format.choice.format0->startingSymbolIndex=13; - ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres0); + config_pucch_resset0(pucch_Config, uid, curr_bwp, NULL); + initialUplinkBWP->pusch_Config = calloc(1,sizeof(*initialUplinkBWP->pusch_Config)); initialUplinkBWP->pusch_Config->present = NR_SetupRelease_PUSCH_Config_PR_setup; NR_PUSCH_Config_t *pusch_Config = calloc(1,sizeof(*pusch_Config)); diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 6b7f9a21b9..b8d6b6ee1b 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -102,6 +102,35 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay){ ASN_SEQUENCE_ADD(&scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list,pusch_timedomainresourceallocation_msg3); } } +} +// PUCCH resource set 0 for configuration with O_uci <= 2 bits and/or a positive or negative SR (section 9.2.1 of 38.213) +void config_pucch_resset0(NR_PUCCH_Config_t *pucch_Config, int uid, int curr_bwp, NR_UE_NR_Capability_t *uecap) { + + NR_PUCCH_ResourceSet_t *pucchresset = calloc(1,sizeof(*pucchresset)); + pucchresset->pucch_ResourceSetId = 0; + NR_PUCCH_ResourceId_t *pucchid=calloc(1,sizeof(*pucchid)); + *pucchid=0; + ASN_SEQUENCE_ADD(&pucchresset->resourceList.list,pucchid); + pucchresset->maxPayloadSize=NULL; + + if(uecap) { + long *pucch_F0_2WithoutFH = uecap->phy_Parameters.phy_ParametersFRX_Diff->pucch_F0_2WithoutFH; + AssertFatal(pucch_F0_2WithoutFH == NULL,"UE does not support PUCCH F0 without frequency hopping. Current configuration is without FH\n"); + } + + NR_PUCCH_Resource_t *pucchres0=calloc(1,sizeof(*pucchres0)); + pucchres0->pucch_ResourceId=*pucchid; + pucchres0->startingPRB= (8 + uid) % curr_bwp; + pucchres0->intraSlotFrequencyHopping=NULL; + pucchres0->secondHopPRB=NULL; + pucchres0->format.present= NR_PUCCH_Resource__format_PR_format0; + pucchres0->format.choice.format0=calloc(1,sizeof(*pucchres0->format.choice.format0)); + pucchres0->format.choice.format0->initialCyclicShift=0; + pucchres0->format.choice.format0->nrofSymbols=1; + pucchres0->format.choice.format0->startingSymbolIndex=13; + ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres0); + + ASN_SEQUENCE_ADD(&pucch_Config->resourceSetToAddModList->list,pucchresset); } diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index 192fee754e..af1fca4e0f 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -113,6 +113,6 @@ typedef struct physicalcellgroup_s{ void nr_rrc_config_dl_tda(NR_ServingCellConfigCommon_t *scc); void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay); - +void config_pucch_resset0(NR_PUCCH_Config_t *pucch_Config, int uid, int curr_bwp, NR_UE_NR_Capability_t *uecap); #endif diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index d35c5bf7a2..18c155f5b8 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -864,22 +864,20 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco if (!servingcellconfigdedicated) { ubwp->bwp_Dedicated = calloc(1,sizeof(*ubwp->bwp_Dedicated)); } + ubwp->bwp_Dedicated->pucch_Config = calloc(1,sizeof(*ubwp->bwp_Dedicated->pucch_Config)); ubwp->bwp_Dedicated->pucch_Config->present = NR_SetupRelease_PUCCH_Config_PR_setup; NR_PUCCH_Config_t *pucch_Config = calloc(1,sizeof(*pucch_Config)); ubwp->bwp_Dedicated->pucch_Config->choice.setup=pucch_Config; + pucch_Config->resourceSetToAddModList = calloc(1,sizeof(*pucch_Config->resourceSetToAddModList)); pucch_Config->resourceSetToReleaseList = NULL; - NR_PUCCH_ResourceSet_t *pucchresset0=calloc(1,sizeof(*pucchresset0)); + pucch_Config->resourceToAddModList = calloc(1,sizeof(*pucch_Config->resourceToAddModList)); + pucch_Config->resourceToReleaseList = NULL; + + config_pucch_resset0(pucch_Config, uid, curr_bwp, uecap); + NR_PUCCH_ResourceSet_t *pucchresset1=calloc(1,sizeof(*pucchresset1)); - pucchresset0->pucch_ResourceSetId = 0; - NR_PUCCH_ResourceId_t *pucchresset0id0=calloc(1,sizeof(*pucchresset0id0)); - *pucchresset0id0=1; - ASN_SEQUENCE_ADD(&pucchresset0->resourceList.list,pucchresset0id0); - pucchresset0->maxPayloadSize=NULL; - - ASN_SEQUENCE_ADD(&pucch_Config->resourceSetToAddModList->list,pucchresset0); - pucchresset1->pucch_ResourceSetId = 1; NR_PUCCH_ResourceId_t *pucchresset1id0=calloc(1,sizeof(*pucchresset1id0)); *pucchresset1id0=2; @@ -887,22 +885,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco pucchresset1->maxPayloadSize=NULL; ASN_SEQUENCE_ADD(&pucch_Config->resourceSetToAddModList->list,pucchresset1); - pucch_Config->resourceToAddModList = calloc(1,sizeof(*pucch_Config->resourceToAddModList)); - pucch_Config->resourceToReleaseList = NULL; - NR_PUCCH_Resource_t *pucchres0=calloc(1,sizeof(*pucchres0)); NR_PUCCH_Resource_t *pucchres2=calloc(1,sizeof(*pucchres2)); - - pucchres0->pucch_ResourceId=1; - pucchres0->startingPRB= (8 + uid) % curr_bwp; - pucchres0->intraSlotFrequencyHopping=NULL; - pucchres0->secondHopPRB=NULL; - pucchres0->format.present= NR_PUCCH_Resource__format_PR_format0; - pucchres0->format.choice.format0=calloc(1,sizeof(*pucchres0->format.choice.format0)); - pucchres0->format.choice.format0->initialCyclicShift=0; - pucchres0->format.choice.format0->nrofSymbols=1; - pucchres0->format.choice.format0->startingSymbolIndex=13; - ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres0); - pucchres2->pucch_ResourceId=2; pucchres2->startingPRB=0; pucchres2->intraSlotFrequencyHopping=NULL; From 975f7e868a2076905b4ae4686d528aa8c84973f8 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 21 Jan 2022 19:15:50 +0100 Subject: [PATCH 028/267] function to configure pucch resource set 1 (format2) --- cmake_targets/CMakeLists.txt | 1 + openair2/RRC/NR/MESSAGES/asn1_msg.c | 4 +++ openair2/RRC/NR/nr_rrc_config.c | 47 +++++++++++++++++++++++++++++ openair2/RRC/NR/nr_rrc_config.h | 1 + openair2/RRC/NR/rrc_gNB_reconfig.c | 37 ++--------------------- 5 files changed, 56 insertions(+), 34 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index bf3bb2b017..f0c84fbbe6 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -2029,6 +2029,7 @@ set(NR_L2_SRC_UE ${NR_SDAP_SRC} ${NR_UE_RRC_DIR}/L2_interface_ue.c ${NR_UE_RRC_DIR}/main_ue.c + ${NR_RRC_DIR}/nr_rrc_config.c ${NR_UE_RRC_DIR}/rrc_UE.c ${NR_UE_RRC_DIR}/rrc_nsa.c ) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index dce972ab3a..15dfa47f66 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1379,6 +1379,10 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, rrc_gNB_carrier_data_t *carrier, NR_UE_NR_Capability_t *uecap) { + NR_SpCellConfig_t *SpCellConfig = cellGroupConfig->spCellConfig; + NR_BWP_UplinkDedicated_t *initialUplinkBWP = SpCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; + NR_PUCCH_Config_t *pucch_Config = initialUplinkBWP->pucch_Config->choice.setup; + config_pucch_resset1(pucch_Config, uecap); } void fill_initial_cellGroupConfig(int uid, diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index b8d6b6ee1b..f4ab5fdd0f 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -134,3 +134,50 @@ void config_pucch_resset0(NR_PUCCH_Config_t *pucch_Config, int uid, int curr_bwp ASN_SEQUENCE_ADD(&pucch_Config->resourceSetToAddModList->list,pucchresset); } + +// PUCCH resource set 1 for configuration with O_uci > 2 bits (currently format2) +void config_pucch_resset1(NR_PUCCH_Config_t *pucch_Config, NR_UE_NR_Capability_t *uecap) { + + NR_PUCCH_ResourceSet_t *pucchresset=calloc(1,sizeof(*pucchresset)); + pucchresset->pucch_ResourceSetId = 1; + NR_PUCCH_ResourceId_t *pucchressetid=calloc(1,sizeof(*pucchressetid)); + *pucchressetid=2; + ASN_SEQUENCE_ADD(&pucchresset->resourceList.list,pucchressetid); + pucchresset->maxPayloadSize=NULL; + + if(uecap) { + long *pucch_F0_2WithoutFH = uecap->phy_Parameters.phy_ParametersFRX_Diff->pucch_F0_2WithoutFH; + AssertFatal(pucch_F0_2WithoutFH == NULL,"UE does not support PUCCH F2 without frequency hopping. Current configuration is without FH\n"); + } + + NR_PUCCH_Resource_t *pucchres2=calloc(1,sizeof(*pucchres2)); + pucchres2->pucch_ResourceId=*pucchressetid; + pucchres2->startingPRB=0; + pucchres2->intraSlotFrequencyHopping=NULL; + pucchres2->secondHopPRB=NULL; + pucchres2->format.present= NR_PUCCH_Resource__format_PR_format2; + pucchres2->format.choice.format2=calloc(1,sizeof(*pucchres2->format.choice.format2)); + pucchres2->format.choice.format2->nrofPRBs=8; + pucchres2->format.choice.format2->nrofSymbols=1; + pucchres2->format.choice.format2->startingSymbolIndex=13; + ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres2); + + ASN_SEQUENCE_ADD(&pucch_Config->resourceSetToAddModList->list,pucchresset); + + pucch_Config->format2=calloc(1,sizeof(*pucch_Config->format2)); + pucch_Config->format2->present=NR_SetupRelease_PUCCH_FormatConfig_PR_setup; + NR_PUCCH_FormatConfig_t *pucchfmt2 = calloc(1,sizeof(*pucchfmt2)); + pucch_Config->format2->choice.setup = pucchfmt2; + pucchfmt2->interslotFrequencyHopping=NULL; + pucchfmt2->additionalDMRS=NULL; + pucchfmt2->maxCodeRate=calloc(1,sizeof(*pucchfmt2->maxCodeRate)); + *pucchfmt2->maxCodeRate=NR_PUCCH_MaxCodeRate_zeroDot35; + pucchfmt2->nrofSlots=NULL; + pucchfmt2->pi2BPSK=NULL; + + // to check UE capabilities for that in principle + pucchfmt2->simultaneousHARQ_ACK_CSI=calloc(1,sizeof(*pucchfmt2->simultaneousHARQ_ACK_CSI)); + *pucchfmt2->simultaneousHARQ_ACK_CSI=NR_PUCCH_FormatConfig__simultaneousHARQ_ACK_CSI_true; + +} + diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index af1fca4e0f..78416f7ecf 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -114,5 +114,6 @@ typedef struct physicalcellgroup_s{ void nr_rrc_config_dl_tda(NR_ServingCellConfigCommon_t *scc); void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay); void config_pucch_resset0(NR_PUCCH_Config_t *pucch_Config, int uid, int curr_bwp, NR_UE_NR_Capability_t *uecap); +void config_pucch_resset1(NR_PUCCH_Config_t *pucch_Config, NR_UE_NR_Capability_t *uecap); #endif diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index 18c155f5b8..98dd8ee137 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -45,6 +45,7 @@ #include "SIMULATION/TOOLS/sim.h" #include "executables/softmodem-common.h" #include "LAYER2/nr_rlc/nr_rlc_oai_api.h" +#include "nr_rrc_config.h" #define false 0 #define true 1 @@ -875,40 +876,8 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco pucch_Config->resourceToAddModList = calloc(1,sizeof(*pucch_Config->resourceToAddModList)); pucch_Config->resourceToReleaseList = NULL; - config_pucch_resset0(pucch_Config, uid, curr_bwp, uecap); - - NR_PUCCH_ResourceSet_t *pucchresset1=calloc(1,sizeof(*pucchresset1)); - pucchresset1->pucch_ResourceSetId = 1; - NR_PUCCH_ResourceId_t *pucchresset1id0=calloc(1,sizeof(*pucchresset1id0)); - *pucchresset1id0=2; - ASN_SEQUENCE_ADD(&pucchresset1->resourceList.list,pucchresset1id0); - pucchresset1->maxPayloadSize=NULL; - ASN_SEQUENCE_ADD(&pucch_Config->resourceSetToAddModList->list,pucchresset1); - - NR_PUCCH_Resource_t *pucchres2=calloc(1,sizeof(*pucchres2)); - pucchres2->pucch_ResourceId=2; - pucchres2->startingPRB=0; - pucchres2->intraSlotFrequencyHopping=NULL; - pucchres2->secondHopPRB=NULL; - pucchres2->format.present= NR_PUCCH_Resource__format_PR_format2; - pucchres2->format.choice.format2=calloc(1,sizeof(*pucchres2->format.choice.format2)); - pucchres2->format.choice.format2->nrofPRBs=8; - pucchres2->format.choice.format2->nrofSymbols=1; - pucchres2->format.choice.format2->startingSymbolIndex=13; - ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres2); - - pucch_Config->format2=calloc(1,sizeof(*pucch_Config->format2)); - pucch_Config->format2->present=NR_SetupRelease_PUCCH_FormatConfig_PR_setup; - NR_PUCCH_FormatConfig_t *pucchfmt2 = calloc(1,sizeof(*pucchfmt2)); - pucch_Config->format2->choice.setup = pucchfmt2; - pucchfmt2->interslotFrequencyHopping=NULL; - pucchfmt2->additionalDMRS=NULL; - pucchfmt2->maxCodeRate=calloc(1,sizeof(*pucchfmt2->maxCodeRate)); - *pucchfmt2->maxCodeRate=NR_PUCCH_MaxCodeRate_zeroDot35; - pucchfmt2->nrofSlots=NULL; - pucchfmt2->pi2BPSK=NULL; - pucchfmt2->simultaneousHARQ_ACK_CSI=calloc(1,sizeof(*pucchfmt2->simultaneousHARQ_ACK_CSI)); - *pucchfmt2->simultaneousHARQ_ACK_CSI=NR_PUCCH_FormatConfig__simultaneousHARQ_ACK_CSI_true; + config_pucch_resset0(pucch_Config, uid, curr_bwp, uecap); // <= 2 bits + config_pucch_resset1(pucch_Config, uecap); // > 2 bits // for scheduling requestresource pucch_Config->schedulingRequestResourceToAddModList = calloc(1,sizeof(*pucch_Config->schedulingRequestResourceToAddModList)); From 9408c3c0b0647c2601f04c1f180d6a93bfb3ac56 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 26 Jan 2022 13:58:57 +0100 Subject: [PATCH 029/267] function to set dl_DataToUL_ACK --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 10 +--------- openair2/RRC/NR/nr_rrc_config.c | 11 +++++++++++ openair2/RRC/NR/nr_rrc_config.h | 1 + openair2/RRC/NR/rrc_gNB_reconfig.c | 10 +++------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 15dfa47f66..afb42e14e1 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1149,15 +1149,7 @@ void fill_initial_SpCellConfig(int uid, *schedulingRequestResourceConfig->resource = 0; ASN_SEQUENCE_ADD(&pucch_Config->schedulingRequestResourceToAddModList->list,schedulingRequestResourceConfig); - pucch_Config->dl_DataToUL_ACK = calloc(1,sizeof(*pucch_Config->dl_DataToUL_ACK)); - long *delay[8]; - for (int i=0;i<8;i++) { - delay[i] = calloc(1,sizeof(*delay[i])); - AssertFatal(carrier->minRXTXTIME >=2 && carrier->minRXTXTIME <7, - "check minRXTXTIME %d\n",carrier->minRXTXTIME); - *delay[i] = (i+carrier->minRXTXTIME); - ASN_SEQUENCE_ADD(&pucch_Config->dl_DataToUL_ACK->list,delay[i]); - } + set_dl_DataToUL_ACK(pucch_Config, carrier->minRXTXTIME); SpCellConfig->spCellConfigDedicated->initialDownlinkBWP = calloc(1,sizeof(*SpCellConfig->spCellConfigDedicated->initialDownlinkBWP)); NR_BWP_DownlinkDedicated_t *bwp_Dedicated = SpCellConfig->spCellConfigDedicated->initialDownlinkBWP; diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index f4ab5fdd0f..207b68e2d4 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -104,6 +104,17 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay){ } } +void set_dl_DataToUL_ACK(NR_PUCCH_Config_t *pucch_Config, int min_feedback_time) { + + pucch_Config->dl_DataToUL_ACK = calloc(1,sizeof(*pucch_Config->dl_DataToUL_ACK)); + long *delay[8]; + for (int i=0;i<8;i++) { + delay[i] = calloc(1,sizeof(*delay[i])); + *delay[i] = i+min_feedback_time; + ASN_SEQUENCE_ADD(&pucch_Config->dl_DataToUL_ACK->list,delay[i]); + } +} + // PUCCH resource set 0 for configuration with O_uci <= 2 bits and/or a positive or negative SR (section 9.2.1 of 38.213) void config_pucch_resset0(NR_PUCCH_Config_t *pucch_Config, int uid, int curr_bwp, NR_UE_NR_Capability_t *uecap) { diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index 78416f7ecf..62762ee7e4 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -115,5 +115,6 @@ void nr_rrc_config_dl_tda(NR_ServingCellConfigCommon_t *scc); void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay); void config_pucch_resset0(NR_PUCCH_Config_t *pucch_Config, int uid, int curr_bwp, NR_UE_NR_Capability_t *uecap); void config_pucch_resset1(NR_PUCCH_Config_t *pucch_Config, NR_UE_NR_Capability_t *uecap); +void set_dl_DataToUL_ACK(NR_PUCCH_Config_t *pucch_Config, int min_feedback_time); #endif diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index 98dd8ee137..b8b3485938 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -893,13 +893,9 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco pucch_Config->schedulingRequestResourceToReleaseList=NULL; pucch_Config->multi_CSI_PUCCH_ResourceList=NULL; - pucch_Config->dl_DataToUL_ACK = calloc(1,sizeof(*pucch_Config->dl_DataToUL_ACK)); - long *delay[8]; - for (int i=0;i<8;i++) { - delay[i] = calloc(1,sizeof(*delay[i])); - *delay[i] = i+minRXTXTIME; - ASN_SEQUENCE_ADD(&pucch_Config->dl_DataToUL_ACK->list,delay[i]); - } + + set_dl_DataToUL_ACK(pucch_Config, minRXTXTIME); + pucch_Config->spatialRelationInfoToAddModList = calloc(1,sizeof(*pucch_Config->spatialRelationInfoToAddModList)); NR_PUCCH_SpatialRelationInfo_t *pucchspatial = calloc(1,sizeof(*pucchspatial)); pucchspatial->pucch_SpatialRelationInfoId = 1; From d29b17a21151f97a11805f64eceea76e1a440dc7 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 26 Jan 2022 17:46:26 +0100 Subject: [PATCH 030/267] function to configure SR --- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 6 +- openair2/RRC/NR/MESSAGES/asn1_msg.c | 77 ++++++-------------- openair2/RRC/NR/MESSAGES/asn1_msg.h | 2 +- openair2/RRC/NR/nr_rrc_config.c | 27 +++++++ openair2/RRC/NR/nr_rrc_config.h | 2 + openair2/RRC/NR/rrc_gNB_reconfig.c | 21 +----- 6 files changed, 57 insertions(+), 78 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 85bb10290a..b452327c08 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2271,11 +2271,9 @@ int8_t nr_ue_get_SR(module_id_t module_idP, frame_t frameP, slot_t slot){ // start the sr-prohibittimer : rel 9 and above if (mac->scheduling_info.sr_ProhibitTimer > 0) { // timer configured mac->scheduling_info.sr_ProhibitTimer--; - mac->scheduling_info. - sr_ProhibitTimer_Running = 1; + mac->scheduling_info.sr_ProhibitTimer_Running = 1; } else { - mac->scheduling_info. - sr_ProhibitTimer_Running = 0; + mac->scheduling_info.sr_ProhibitTimer_Running = 0; } //mac->ul_active =1; return (1); //instruct phy to signal SR diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index afb42e14e1..bc03a74026 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -977,9 +977,11 @@ uint8_t do_RRCReject(uint8_t Mod_id, } void fill_initial_SpCellConfig(int uid, - NR_SpCellConfig_t *SpCellConfig, + NR_CellGroupConfig_t *cellGroupConfig, NR_ServingCellConfigCommon_t *scc, rrc_gNB_carrier_data_t *carrier) { + + NR_SpCellConfig_t *SpCellConfig = cellGroupConfig->spCellConfig; int curr_bwp = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth,MAX_BWP_SIZE); SpCellConfig->servCellIndex = NULL; SpCellConfig->reconfigurationWithSync = NULL; @@ -1127,27 +1129,7 @@ void fill_initial_SpCellConfig(int uid, srs_res0->spatialRelationInfo->referenceSignal.choice.csi_RS_Index=0; ASN_SEQUENCE_ADD(&srs_Config->srs_ResourceToAddModList->list,srs_res0); - // configure Scheduling request - // 40 slot period - pucch_Config->schedulingRequestResourceToAddModList = calloc(1,sizeof(*pucch_Config->schedulingRequestResourceToAddModList)); - NR_SchedulingRequestResourceConfig_t *schedulingRequestResourceConfig = calloc(1,sizeof(*schedulingRequestResourceConfig)); - schedulingRequestResourceConfig->schedulingRequestResourceId = 1; - schedulingRequestResourceConfig->schedulingRequestID= 0; - schedulingRequestResourceConfig->periodicityAndOffset = calloc(1,sizeof(*schedulingRequestResourceConfig->periodicityAndOffset)); - schedulingRequestResourceConfig->periodicityAndOffset->present = NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl40; - // note: make sure that there is no issue here. Later choose the RNTI accordingly. - // Here we would be limited to 3 UEs on this resource (1 1/2 Frames 30 kHz SCS, 5 ms TDD periodicity => slots 7,8,9). - // This should be a temporary resource until the first RRCReconfiguration gives new pucch resources. - // Check for above configuration and exit for now if it is not the case - AssertFatal(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.subcarrierSpacing==NR_SubcarrierSpacing_kHz30, - "SCS != 30kHz\n"); - AssertFatal(scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity==NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms5, - "TDD period != 5ms : %ld\n",scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity); - - schedulingRequestResourceConfig->periodicityAndOffset->choice.sl40 = 8; - schedulingRequestResourceConfig->resource = calloc(1,sizeof(*schedulingRequestResourceConfig->resource)); - *schedulingRequestResourceConfig->resource = 0; - ASN_SEQUENCE_ADD(&pucch_Config->schedulingRequestResourceToAddModList->list,schedulingRequestResourceConfig); + schedulingrequest_config(cellGroupConfig->mac_CellGroupConfig, pucch_Config); set_dl_DataToUL_ACK(pucch_Config, carrier->minRXTXTIME); @@ -1431,36 +1413,25 @@ void fill_initial_cellGroupConfig(int uid, cellGroupConfig->rlc_BearerToReleaseList = NULL; /* mac CellGroup Config */ - if (1) { - mac_CellGroupConfig = calloc(1, sizeof(*mac_CellGroupConfig)); - if (1) { - mac_CellGroupConfig->schedulingRequestConfig = calloc(1, sizeof(*mac_CellGroupConfig->schedulingRequestConfig)); - mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList = CALLOC(1,sizeof(*mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList)); - struct NR_SchedulingRequestToAddMod *schedulingrequestlist; - schedulingrequestlist = CALLOC(1,sizeof(*schedulingrequestlist)); - schedulingrequestlist->schedulingRequestId = 0; - schedulingrequestlist->sr_ProhibitTimer = CALLOC(1,sizeof(*schedulingrequestlist->sr_ProhibitTimer)); - *(schedulingrequestlist->sr_ProhibitTimer) = 0; - schedulingrequestlist->sr_TransMax = NR_SchedulingRequestToAddMod__sr_TransMax_n64; - ASN_SEQUENCE_ADD(&(mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList->list),schedulingrequestlist); - } - mac_CellGroupConfig->bsr_Config = calloc(1, sizeof(*mac_CellGroupConfig->bsr_Config)); - mac_CellGroupConfig->bsr_Config->periodicBSR_Timer = NR_BSR_Config__periodicBSR_Timer_sf10; - mac_CellGroupConfig->bsr_Config->retxBSR_Timer = NR_BSR_Config__retxBSR_Timer_sf80; - mac_CellGroupConfig->tag_Config = calloc(1, sizeof(*mac_CellGroupConfig->tag_Config)); - mac_CellGroupConfig->tag_Config->tag_ToReleaseList = NULL; - mac_CellGroupConfig->tag_Config->tag_ToAddModList = calloc(1,sizeof(*mac_CellGroupConfig->tag_Config->tag_ToAddModList)); - struct NR_TAG *tag=calloc(1,sizeof(*tag)); - tag->tag_Id = 0; - tag->timeAlignmentTimer = NR_TimeAlignmentTimer_infinity; - ASN_SEQUENCE_ADD(&mac_CellGroupConfig->tag_Config->tag_ToAddModList->list,tag); - mac_CellGroupConfig->phr_Config = calloc(1, sizeof(*mac_CellGroupConfig->phr_Config)); - mac_CellGroupConfig->phr_Config->present = NR_SetupRelease_PHR_Config_PR_setup; - mac_CellGroupConfig->phr_Config->choice.setup = calloc(1, sizeof(*mac_CellGroupConfig->phr_Config->choice.setup)); - mac_CellGroupConfig->phr_Config->choice.setup->phr_PeriodicTimer = NR_PHR_Config__phr_PeriodicTimer_sf10; - mac_CellGroupConfig->phr_Config->choice.setup->phr_ProhibitTimer = NR_PHR_Config__phr_ProhibitTimer_sf10; - mac_CellGroupConfig->phr_Config->choice.setup->phr_Tx_PowerFactorChange = NR_PHR_Config__phr_Tx_PowerFactorChange_dB1; - } + mac_CellGroupConfig = calloc(1, sizeof(*mac_CellGroupConfig)); + + mac_CellGroupConfig->bsr_Config = calloc(1, sizeof(*mac_CellGroupConfig->bsr_Config)); + mac_CellGroupConfig->bsr_Config->periodicBSR_Timer = NR_BSR_Config__periodicBSR_Timer_sf10; + mac_CellGroupConfig->bsr_Config->retxBSR_Timer = NR_BSR_Config__retxBSR_Timer_sf80; + mac_CellGroupConfig->tag_Config = calloc(1, sizeof(*mac_CellGroupConfig->tag_Config)); + mac_CellGroupConfig->tag_Config->tag_ToReleaseList = NULL; + mac_CellGroupConfig->tag_Config->tag_ToAddModList = calloc(1,sizeof(*mac_CellGroupConfig->tag_Config->tag_ToAddModList)); + struct NR_TAG *tag=calloc(1,sizeof(*tag)); + tag->tag_Id = 0; + tag->timeAlignmentTimer = NR_TimeAlignmentTimer_infinity; + ASN_SEQUENCE_ADD(&mac_CellGroupConfig->tag_Config->tag_ToAddModList->list,tag); + mac_CellGroupConfig->phr_Config = calloc(1, sizeof(*mac_CellGroupConfig->phr_Config)); + mac_CellGroupConfig->phr_Config->present = NR_SetupRelease_PHR_Config_PR_setup; + mac_CellGroupConfig->phr_Config->choice.setup = calloc(1, sizeof(*mac_CellGroupConfig->phr_Config->choice.setup)); + mac_CellGroupConfig->phr_Config->choice.setup->phr_PeriodicTimer = NR_PHR_Config__phr_PeriodicTimer_sf10; + mac_CellGroupConfig->phr_Config->choice.setup->phr_ProhibitTimer = NR_PHR_Config__phr_ProhibitTimer_sf10; + mac_CellGroupConfig->phr_Config->choice.setup->phr_Tx_PowerFactorChange = NR_PHR_Config__phr_Tx_PowerFactorChange_dB1; + cellGroupConfig->mac_CellGroupConfig = mac_CellGroupConfig; physicalCellGroupConfig = calloc(1,sizeof(*physicalCellGroupConfig)); @@ -1471,7 +1442,7 @@ void fill_initial_cellGroupConfig(int uid, cellGroupConfig->spCellConfig = calloc(1,sizeof(*cellGroupConfig->spCellConfig)); - fill_initial_SpCellConfig(uid,cellGroupConfig->spCellConfig,scc,carrier); + fill_initial_SpCellConfig(uid,cellGroupConfig,scc,carrier); cellGroupConfig->sCellToAddModList = NULL; cellGroupConfig->sCellToReleaseList = NULL; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 7fe08704c2..482bee16be 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -101,7 +101,7 @@ uint8_t do_RRCReject(uint8_t Mod_id, uint8_t *const buffer); void fill_initial_SpCellConfig(int uid, - NR_SpCellConfig_t *SpCellConfig, + NR_CellGroupConfig_t *cellGroupConfig, NR_ServingCellConfigCommon_t *scc, rrc_gNB_carrier_data_t *carrier); diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 207b68e2d4..fdd5fac30a 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -192,3 +192,30 @@ void config_pucch_resset1(NR_PUCCH_Config_t *pucch_Config, NR_UE_NR_Capability_t } +void schedulingrequest_config(NR_MAC_CellGroupConfig_t *mac_CellGroupConfig, + NR_PUCCH_Config_t *pucch_Config) { + + mac_CellGroupConfig->schedulingRequestConfig = calloc(1, sizeof(*mac_CellGroupConfig->schedulingRequestConfig)); + mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList = CALLOC(1,sizeof(*mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList)); + struct NR_SchedulingRequestToAddMod *schedulingrequestlist = CALLOC(1,sizeof(*schedulingrequestlist)); + schedulingrequestlist->schedulingRequestId = 0; + schedulingrequestlist->sr_ProhibitTimer = NULL; + schedulingrequestlist->sr_TransMax = NR_SchedulingRequestToAddMod__sr_TransMax_n64; + ASN_SEQUENCE_ADD(&(mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList->list),schedulingrequestlist); + + // format with <=2 bits in pucch resource set 0 + NR_PUCCH_ResourceSet_t *pucchresset = pucch_Config->resourceSetToAddModList->list.array[0]; + // assigning the 1st pucch resource in the set to scheduling request + NR_PUCCH_ResourceId_t *pucchressetid = pucchresset->resourceList.list.array[0]; + + pucch_Config->schedulingRequestResourceToAddModList = calloc(1,sizeof(*pucch_Config->schedulingRequestResourceToAddModList)); + NR_SchedulingRequestResourceConfig_t *schedulingRequestResourceConfig = calloc(1,sizeof(*schedulingRequestResourceConfig)); + schedulingRequestResourceConfig->schedulingRequestResourceId = 1; + schedulingRequestResourceConfig->schedulingRequestID = 0; + schedulingRequestResourceConfig->periodicityAndOffset = calloc(1,sizeof(*schedulingRequestResourceConfig->periodicityAndOffset)); + schedulingRequestResourceConfig->periodicityAndOffset->present = NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl10; + schedulingRequestResourceConfig->periodicityAndOffset->choice.sl10 = 7; + schedulingRequestResourceConfig->resource = calloc(1,sizeof(*schedulingRequestResourceConfig->resource)); + *schedulingRequestResourceConfig->resource = *pucchressetid; + ASN_SEQUENCE_ADD(&pucch_Config->schedulingRequestResourceToAddModList->list,schedulingRequestResourceConfig); +} diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index 62762ee7e4..cd418e21f4 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -116,5 +116,7 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay); void config_pucch_resset0(NR_PUCCH_Config_t *pucch_Config, int uid, int curr_bwp, NR_UE_NR_Capability_t *uecap); void config_pucch_resset1(NR_PUCCH_Config_t *pucch_Config, NR_UE_NR_Capability_t *uecap); void set_dl_DataToUL_ACK(NR_PUCCH_Config_t *pucch_Config, int min_feedback_time); +void schedulingrequest_config(NR_MAC_CellGroupConfig_t *mac_CellGroupConfig, + NR_PUCCH_Config_t *pucch_Config); #endif diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index b8b3485938..7bf2da09fb 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -96,15 +96,6 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco secondaryCellGroup->mac_CellGroupConfig=calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig)); secondaryCellGroup->mac_CellGroupConfig->drx_Config = NULL; - secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig = calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig)); - secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList = calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList)); - NR_SchedulingRequestToAddMod_t *SchedulingRequestConf = calloc(1,sizeof(*SchedulingRequestConf)); - SchedulingRequestConf->schedulingRequestId = 0; //Could be changed - SchedulingRequestConf->sr_ProhibitTimer = calloc(1,sizeof(*SchedulingRequestConf->sr_ProhibitTimer)); - *SchedulingRequestConf->sr_ProhibitTimer = NR_SchedulingRequestToAddMod__sr_ProhibitTimer_ms16; - SchedulingRequestConf->sr_TransMax = NR_SchedulingRequestToAddMod__sr_TransMax_n32; - ASN_SEQUENCE_ADD(&secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList->list,SchedulingRequestConf); - secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToReleaseList = NULL; secondaryCellGroup->mac_CellGroupConfig->bsr_Config=calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig->bsr_Config)); secondaryCellGroup->mac_CellGroupConfig->bsr_Config->periodicBSR_Timer = NR_BSR_Config__periodicBSR_Timer_sf10; @@ -879,17 +870,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco config_pucch_resset0(pucch_Config, uid, curr_bwp, uecap); // <= 2 bits config_pucch_resset1(pucch_Config, uecap); // > 2 bits - // for scheduling requestresource - pucch_Config->schedulingRequestResourceToAddModList = calloc(1,sizeof(*pucch_Config->schedulingRequestResourceToAddModList)); - NR_SchedulingRequestResourceConfig_t *schedulingRequestResourceConfig = calloc(1,sizeof(*schedulingRequestResourceConfig)); - schedulingRequestResourceConfig->schedulingRequestResourceId = 1; - schedulingRequestResourceConfig->schedulingRequestID = 0; - schedulingRequestResourceConfig->periodicityAndOffset = calloc(1,sizeof(*schedulingRequestResourceConfig->periodicityAndOffset)); - schedulingRequestResourceConfig->periodicityAndOffset->present = NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl10; - schedulingRequestResourceConfig->periodicityAndOffset->choice.sl10 = 7; - schedulingRequestResourceConfig->resource = calloc(1,sizeof(*schedulingRequestResourceConfig->resource)); - *schedulingRequestResourceConfig->resource = 1; - ASN_SEQUENCE_ADD(&pucch_Config->schedulingRequestResourceToAddModList->list,schedulingRequestResourceConfig); + schedulingrequest_config(secondaryCellGroup->mac_CellGroupConfig, pucch_Config); pucch_Config->schedulingRequestResourceToReleaseList=NULL; pucch_Config->multi_CSI_PUCCH_ResourceList=NULL; From 2e0823a7ae49680b781fff67636b3d47c84672db Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Tue, 1 Feb 2022 14:03:42 +0100 Subject: [PATCH 031/267] Change mapping between DRB id and channel id for interoperability with Accelleran CU -Some hardcodings also added to be removed later --- openair2/F1AP/f1ap_decoder.c | 2 +- openair2/F1AP/f1ap_du_task.c | 2 +- openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c | 16 +++++++++------- openair2/RRC/NR/MESSAGES/asn1_msg.c | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/openair2/F1AP/f1ap_decoder.c b/openair2/F1AP/f1ap_decoder.c index 60b3f94310..beecf70401 100644 --- a/openair2/F1AP/f1ap_decoder.c +++ b/openair2/F1AP/f1ap_decoder.c @@ -33,7 +33,7 @@ #include "f1ap_common.h" #include "f1ap_decoder.h" -int asn1_decoder_xer_print = 0; +int asn1_decoder_xer_print = 1; static int f1ap_decode_initiating_message(F1AP_F1AP_PDU_t *pdu) { //MessageDef *message_p; diff --git a/openair2/F1AP/f1ap_du_task.c b/openair2/F1AP/f1ap_du_task.c index 03d5810486..b8bf99ad89 100644 --- a/openair2/F1AP/f1ap_du_task.c +++ b/openair2/F1AP/f1ap_du_task.c @@ -127,7 +127,7 @@ void *F1AP_DU_task(void *arg) { LOG_I(F1AP, "DU Task Received F1AP_SETUP_REQ\n"); f1ap_setup_req_t *msgSetup=&F1AP_SETUP_REQ(msg); createF1inst(false, myInstance, msgSetup); - getCxt(DUtype, myInstance)->gtpInst=du_create_gtpu_instance_to_cu(msgSetup->CU_f1_ip_address.ipv4_address, + getCxt(DUtype, myInstance)->gtpInst=du_create_gtpu_instance_to_cu("192.168.18.91", //msgSetup->CU_f1_ip_address.ipv4_address, //"192.168.18.91" msgSetup->CUport, msgSetup->DU_f1_ip_address.ipv4_address, msgSetup->DUport); diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index 78e06d37e2..dad0c8052f 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -166,7 +166,7 @@ void mac_rlc_data_ind ( switch (channel_idP) { case 1 ... 3: rb = ue->srb[channel_idP - 1]; break; - case 4 ... 8: rb = ue->drb[channel_idP - 4]; break; + case 4 ... 8: rb = ue->drb[channel_idP - 1]; break; default: rb = NULL; break; } @@ -207,7 +207,7 @@ tbs_size_t mac_rlc_data_req( switch (channel_idP) { case 1 ... 3: rb = ue->srb[channel_idP - 1]; break; - case 4 ... 8: rb = ue->drb[channel_idP - 4]; break; + case 4 ... 8: rb = ue->drb[channel_idP - 1]; break; default: rb = NULL; LOG_E(RLC, "In %s:%d:%s: data request for unknown RB with LCID 0x%02x !\n", __FILE__, __LINE__, __FUNCTION__, channel_idP); @@ -215,10 +215,12 @@ tbs_size_t mac_rlc_data_req( } if (rb != NULL) { + LOG_D(RLC, "MAC PDU to get created for channel_idP:%d \n", channel_idP); rb->set_time(rb, nr_rlc_current_time); maxsize = tb_sizeP; ret = rb->generate_pdu(rb, buffer_pP, maxsize); } else { + LOG_D(RLC, "MAC PDU failed to get created for channel_idP:%d \n", channel_idP); ret = 0; } @@ -253,7 +255,7 @@ mac_rlc_status_resp_t mac_rlc_status_ind( switch (channel_idP) { case 1 ... 3: rb = ue->srb[channel_idP - 1]; break; - case 4 ... 8: rb = ue->drb[channel_idP - 4]; break; + case 4 ... 8: rb = ue->drb[channel_idP - 1]; break; default: rb = NULL; break; } @@ -316,7 +318,7 @@ rlc_buffer_occupancy_t mac_rlc_get_buffer_occupancy_ind( switch (channel_idP) { case 1 ... 3: rb = ue->srb[channel_idP - 1]; break; - case 4 ... 8: rb = ue->drb[channel_idP - 4]; break; + case 4 ... 8: rb = ue->drb[channel_idP - 1]; break; //4 default: rb = NULL; break; } @@ -751,7 +753,7 @@ static void add_drb_am(int rnti, struct NR_DRB_ToAddMod *s, NR_RLC_BearerConfig_ struct NR_RLC_Config *r = rlc_BearerConfig->rlc_Config; struct NR_LogicalChannelConfig *l = rlc_BearerConfig->mac_LogicalChannelConfig; int drb_id = s->drb_Identity; - int channel_id = rlc_BearerConfig->logicalChannelIdentity; + //int channel_id = rlc_BearerConfig->logicalChannelIdentity; int logical_channel_group; int t_status_prohibit; @@ -768,11 +770,11 @@ static void add_drb_am(int rnti, struct NR_DRB_ToAddMod *s, NR_RLC_BearerConfig_ exit(1); } - if (channel_id != drb_id + 3) { + /*if (channel_id != drb_id + 3) { LOG_E(RLC, "%s:%d:%s: todo, remove this limitation\n", __FILE__, __LINE__, __FUNCTION__); exit(1); - } + }*/ logical_channel_group = *l->ul_SpecificParameters->logicalChannelGroup; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index a2b2feb52c..46353110ca 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1647,7 +1647,7 @@ void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGr rlc_BearerConfig_drb->logicalChannelIdentity = 4; rlc_BearerConfig_drb->servedRadioBearer = calloc(1, sizeof(*rlc_BearerConfig_drb->servedRadioBearer)); rlc_BearerConfig_drb->servedRadioBearer->present = NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity; - rlc_BearerConfig_drb->servedRadioBearer->choice.drb_Identity = 1; + rlc_BearerConfig_drb->servedRadioBearer->choice.drb_Identity = 4; //1; rlc_BearerConfig_drb->reestablishRLC = NULL; rlc_Config_drb = calloc(1, sizeof(NR_RLC_Config_t)); rlc_Config_drb->present = NR_RLC_Config_PR_am; From 8d7df8d164005d27a9ad7b3e02fea4216eb6bbfb Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 7 Feb 2022 19:28:51 +0100 Subject: [PATCH 032/267] rrc configuration for pucch power control --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 1 + openair2/RRC/NR/nr_rrc_config.c | 47 +++++++++++++++++++++++++++++ openair2/RRC/NR/nr_rrc_config.h | 1 + openair2/RRC/NR/rrc_gNB_reconfig.c | 36 +--------------------- 4 files changed, 50 insertions(+), 35 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index bc03a74026..a36dd3e56b 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1357,6 +1357,7 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_BWP_UplinkDedicated_t *initialUplinkBWP = SpCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; NR_PUCCH_Config_t *pucch_Config = initialUplinkBWP->pucch_Config->choice.setup; config_pucch_resset1(pucch_Config, uecap); + set_pucch_power_config(pucch_Config, carrier->do_CSIRS); } void fill_initial_cellGroupConfig(int uid, diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index fdd5fac30a..8dc6a21c92 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -192,6 +192,53 @@ void config_pucch_resset1(NR_PUCCH_Config_t *pucch_Config, NR_UE_NR_Capability_t } +void set_pucch_power_config(NR_PUCCH_Config_t *pucch_Config, int do_csirs) { + + pucch_Config->pucch_PowerControl = calloc(1,sizeof(*pucch_Config->pucch_PowerControl)); + NR_P0_PUCCH_t *p00 = calloc(1,sizeof(*p00)); + p00->p0_PUCCH_Id = 1; + p00->p0_PUCCH_Value = 0; + pucch_Config->pucch_PowerControl->p0_Set = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->p0_Set)); + ASN_SEQUENCE_ADD(&pucch_Config->pucch_PowerControl->p0_Set->list,p00); + + pucch_Config->pucch_PowerControl->pathlossReferenceRSs = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->pathlossReferenceRSs)); + struct NR_PUCCH_PathlossReferenceRS *PL_ref_RS = calloc(1,sizeof(*PL_ref_RS)); + PL_ref_RS->pucch_PathlossReferenceRS_Id = 0; + if(do_csirs) { + PL_ref_RS->referenceSignal.present = NR_PUCCH_PathlossReferenceRS__referenceSignal_PR_csi_RS_Index; + PL_ref_RS->referenceSignal.choice.csi_RS_Index = 0; + } + else { + PL_ref_RS->referenceSignal.present = NR_PUCCH_PathlossReferenceRS__referenceSignal_PR_ssb_Index; + PL_ref_RS->referenceSignal.choice.ssb_Index = 0; + } + ASN_SEQUENCE_ADD(&pucch_Config->pucch_PowerControl->pathlossReferenceRSs->list,PL_ref_RS); + + pucch_Config->pucch_PowerControl->deltaF_PUCCH_f0 = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->deltaF_PUCCH_f0)); + *pucch_Config->pucch_PowerControl->deltaF_PUCCH_f0 = 0; + pucch_Config->pucch_PowerControl->deltaF_PUCCH_f2 = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->deltaF_PUCCH_f2)); + *pucch_Config->pucch_PowerControl->deltaF_PUCCH_f2 = 0; + + pucch_Config->spatialRelationInfoToAddModList = calloc(1,sizeof(*pucch_Config->spatialRelationInfoToAddModList)); + pucch_Config->spatialRelationInfoToReleaseList=NULL; + NR_PUCCH_SpatialRelationInfo_t *pucchspatial = calloc(1,sizeof(*pucchspatial)); + pucchspatial->pucch_SpatialRelationInfoId = 1; + pucchspatial->servingCellId = NULL; + if(do_csirs) { + pucchspatial->referenceSignal.present = NR_PUCCH_SpatialRelationInfo__referenceSignal_PR_csi_RS_Index; + pucchspatial->referenceSignal.choice.csi_RS_Index = 0; + } + else { + pucchspatial->referenceSignal.present = NR_PUCCH_SpatialRelationInfo__referenceSignal_PR_ssb_Index; + pucchspatial->referenceSignal.choice.ssb_Index = 0; + } + + pucchspatial->pucch_PathlossReferenceRS_Id = PL_ref_RS->pucch_PathlossReferenceRS_Id; + pucchspatial->p0_PUCCH_Id = p00->p0_PUCCH_Id; + pucchspatial->closedLoopIndex = NR_PUCCH_SpatialRelationInfo__closedLoopIndex_i0; + ASN_SEQUENCE_ADD(&pucch_Config->spatialRelationInfoToAddModList->list,pucchspatial); +} + void schedulingrequest_config(NR_MAC_CellGroupConfig_t *mac_CellGroupConfig, NR_PUCCH_Config_t *pucch_Config) { diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index cd418e21f4..f6df28cf9c 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -116,6 +116,7 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay); void config_pucch_resset0(NR_PUCCH_Config_t *pucch_Config, int uid, int curr_bwp, NR_UE_NR_Capability_t *uecap); void config_pucch_resset1(NR_PUCCH_Config_t *pucch_Config, NR_UE_NR_Capability_t *uecap); void set_dl_DataToUL_ACK(NR_PUCCH_Config_t *pucch_Config, int min_feedback_time); +void set_pucch_power_config(NR_PUCCH_Config_t *pucch_Config, int do_csirs); void schedulingrequest_config(NR_MAC_CellGroupConfig_t *mac_CellGroupConfig, NR_PUCCH_Config_t *pucch_Config); diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index 7bf2da09fb..aaf8159a03 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -876,41 +876,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco pucch_Config->multi_CSI_PUCCH_ResourceList=NULL; set_dl_DataToUL_ACK(pucch_Config, minRXTXTIME); - - pucch_Config->spatialRelationInfoToAddModList = calloc(1,sizeof(*pucch_Config->spatialRelationInfoToAddModList)); - NR_PUCCH_SpatialRelationInfo_t *pucchspatial = calloc(1,sizeof(*pucchspatial)); - pucchspatial->pucch_SpatialRelationInfoId = 1; - pucchspatial->servingCellId = NULL; - if(do_csirs) { - pucchspatial->referenceSignal.present = NR_PUCCH_SpatialRelationInfo__referenceSignal_PR_csi_RS_Index; - pucchspatial->referenceSignal.choice.csi_RS_Index = 0; - } - else { - pucchspatial->referenceSignal.present = NR_PUCCH_SpatialRelationInfo__referenceSignal_PR_ssb_Index; - pucchspatial->referenceSignal.choice.ssb_Index = 0; - } - pucchspatial->pucch_PathlossReferenceRS_Id = 0; - pucchspatial->p0_PUCCH_Id = 1; - pucchspatial->closedLoopIndex = NR_PUCCH_SpatialRelationInfo__closedLoopIndex_i0; - ASN_SEQUENCE_ADD(&pucch_Config->spatialRelationInfoToAddModList->list,pucchspatial); - pucch_Config->spatialRelationInfoToReleaseList=NULL; - pucch_Config->pucch_PowerControl=calloc(1,sizeof(*pucch_Config->pucch_PowerControl)); - pucch_Config->pucch_PowerControl->deltaF_PUCCH_f0 = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->deltaF_PUCCH_f0)); - *pucch_Config->pucch_PowerControl->deltaF_PUCCH_f0 = 0; - pucch_Config->pucch_PowerControl->deltaF_PUCCH_f1 = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->deltaF_PUCCH_f1)); - *pucch_Config->pucch_PowerControl->deltaF_PUCCH_f1 = 0; - pucch_Config->pucch_PowerControl->deltaF_PUCCH_f2 = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->deltaF_PUCCH_f2)); - *pucch_Config->pucch_PowerControl->deltaF_PUCCH_f2 = 0; - pucch_Config->pucch_PowerControl->deltaF_PUCCH_f3 = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->deltaF_PUCCH_f3)); - *pucch_Config->pucch_PowerControl->deltaF_PUCCH_f3 = 0; - pucch_Config->pucch_PowerControl->deltaF_PUCCH_f4 = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->deltaF_PUCCH_f4)); - *pucch_Config->pucch_PowerControl->deltaF_PUCCH_f4 = 0; - pucch_Config->pucch_PowerControl->p0_Set = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->p0_Set)); - NR_P0_PUCCH_t *p00 = calloc(1,sizeof(*p00)); - p00->p0_PUCCH_Id=1; - p00->p0_PUCCH_Value = 0; - ASN_SEQUENCE_ADD(&pucch_Config->pucch_PowerControl->p0_Set->list,p00); - pucch_Config->pucch_PowerControl->pathlossReferenceRSs = NULL; + set_pucch_power_config(pucch_Config, do_csirs); if (!servingcellconfigdedicated) { // copy pusch_Config from dedicated initialBWP From dccbd9279a9c2f41a6b552a02027ec91b1ff855e Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Wed, 9 Feb 2022 11:05:23 +0100 Subject: [PATCH 033/267] Some hardcoded values in F1AP for testing with Accelleran to be removed later --- openair2/F1AP/f1ap_du_interface_management.c | 2 +- openair2/F1AP/f1ap_du_task.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/F1AP/f1ap_du_interface_management.c b/openair2/F1AP/f1ap_du_interface_management.c index 0777db864c..2bca8f7e10 100644 --- a/openair2/F1AP/f1ap_du_interface_management.c +++ b/openair2/F1AP/f1ap_du_interface_management.c @@ -186,7 +186,7 @@ int DU_send_F1_SETUP_REQUEST(instance_t instance) { INT8_TO_OCTET_STRING(1,&SliceSupport_item->sNSSAI.sST); //OCTET_STRING_fromBuf(&SliceSupport_item->sNSSAI.sST, "1", 1); asn1cCalloc(SliceSupport_item->sNSSAI.sD, tmp); - INT24_TO_OCTET_STRING(1,tmp); + INT24_TO_OCTET_STRING(10203,tmp); //OCTET_STRING_fromBuf(tmp, "1",1); //} diff --git a/openair2/F1AP/f1ap_du_task.c b/openair2/F1AP/f1ap_du_task.c index b8bf99ad89..1a99e75d31 100644 --- a/openair2/F1AP/f1ap_du_task.c +++ b/openair2/F1AP/f1ap_du_task.c @@ -127,7 +127,7 @@ void *F1AP_DU_task(void *arg) { LOG_I(F1AP, "DU Task Received F1AP_SETUP_REQ\n"); f1ap_setup_req_t *msgSetup=&F1AP_SETUP_REQ(msg); createF1inst(false, myInstance, msgSetup); - getCxt(DUtype, myInstance)->gtpInst=du_create_gtpu_instance_to_cu("192.168.18.91", //msgSetup->CU_f1_ip_address.ipv4_address, //"192.168.18.91" + getCxt(DUtype, myInstance)->gtpInst=du_create_gtpu_instance_to_cu("172.21.10.9",//"172.21.9.5", //msgSetup->CU_f1_ip_address.ipv4_address, //"192.168.18.91" msgSetup->CUport, msgSetup->DU_f1_ip_address.ipv4_address, msgSetup->DUport); From e5c6ee599cb9e4087830a918b9ad83bdaf8cfaff Mon Sep 17 00:00:00 2001 From: matzakos Date: Mon, 28 Feb 2022 21:51:41 +0100 Subject: [PATCH 034/267] Merge with latest updates of develop and fixes for F1 -Problem when parsing UE_RAT_container_list at the DU through UE context setup request -Some debug logs added to be removed once this is fixed --- openair2/F1AP/f1ap_du_ue_context_management.c | 1 + openair2/RRC/NR/rrc_gNB.c | 18 ++++++++++++++---- openair2/RRC/NR_UE/rrc_UE.c | 4 ++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index 1a4fbe38a5..30dec1de08 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -140,6 +140,7 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList = (uint8_t *)calloc(1,ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList->size); memcpy(f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList->buf, ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList->size); f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length = ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList->size; + LOG_I(F1AP, "Size f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length: %d \n", f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length); } } diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index d61a7547da..48987b6a97 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2512,17 +2512,27 @@ rrc_gNB_decode_dcch( NR_UECapabilityInformation__criticalExtensions_PR_ueCapabilityInformation ) { struct NR_UE_CapabilityRAT_ContainerList *ue_CapabilityRAT_ContainerList = ul_dcch_msg->message.choice.c1->choice.ueCapabilityInformation->criticalExtensions.choice.ueCapabilityInformation->ue_CapabilityRAT_ContainerList; - + if(ul_dcch_msg->message.choice.c1->choice.ueCapabilityInformation->criticalExtensions.choice.ueCapabilityInformation->ue_CapabilityRAT_ContainerList!=NULL){ + LOG_I(NR_RRC, "ue_CapabilityRAT_ContainerList is present \n"); req->cu_to_du_rrc_information = calloc(1,sizeof(cu_to_du_rrc_information_t)); req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList = calloc(1,4096); asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_UE_CapabilityRAT_ContainerList, NULL, - (void *)ue_CapabilityRAT_ContainerList, + (void *)ul_dcch_msg->message.choice.c1->choice.ueCapabilityInformation->criticalExtensions.choice.ueCapabilityInformation->ue_CapabilityRAT_ContainerList,//ue_CapabilityRAT_ContainerList, req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, 4096); AssertFatal (enc_rval.encoded > 0, "ASN1 ue_CapabilityRAT_ContainerList encoding failed (%s, %jd)!\n", enc_rval.failed_type->name, enc_rval.encoded); req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length = (enc_rval.encoded+7)>>3; + LOG_I(NR_RRC, "Printing content of UE capabilityRANContainerList: \n"); + for(int i=0; icu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length; i++){ + printf("%x ", *(req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList+i)); + } + printf("\n"); + } + else{ + LOG_I(NR_RRC, "ue_CapabilityRAT_ContainerList is not present \n"); + } } itti_send_msg_to_task (TASK_CU_F1, ctxt_pP->module_id, message_p); } @@ -2994,7 +3004,7 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha if(req->cu_to_du_rrc_information!=NULL){ - if(req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList!=NULL){ + /*if(req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList!=NULL){ LOG_I(NR_RRC, "Length of ue_CapabilityRAT_ContainerList is: %d \n", (int) req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length); struct NR_UE_CapabilityRAT_ContainerList *ue_CapabilityRAT_ContainerList; asn_dec_rval_t dec_rval = uper_decode_complete( NULL, @@ -3078,7 +3088,7 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha //TODO } } - } + }*/ } NR_CellGroupConfig_t *cellGroupConfig; diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 2fa0583074..5da690920c 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -2719,9 +2719,9 @@ nr_rrc_ue_process_ueCapabilityEnquiry( AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n", enc_rval.failed_type->name, enc_rval.encoded); - if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { + //if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { xer_fprint(stdout, &asn_DEF_NR_UL_DCCH_Message, (void *)&ul_dcch_msg); - } + //} LOG_I(NR_RRC, "UECapabilityInformation Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); #ifdef ITTI_SIM From d4b566ceb83df42f08e43746c3d5017e80adc86b Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Thu, 3 Mar 2022 17:21:23 +0100 Subject: [PATCH 035/267] Update ori.h for AW2S RU --- targets/ARCH/AW2SORI/ori.h | 113 ++++++++++++++++++++++++++++++++++--- 1 file changed, 104 insertions(+), 9 deletions(-) diff --git a/targets/ARCH/AW2SORI/ori.h b/targets/ARCH/AW2SORI/ori.h index d4a4f2cbbf..3650d15ec6 100644 --- a/targets/ARCH/AW2SORI/ori.h +++ b/targets/ARCH/AW2SORI/ori.h @@ -2,8 +2,8 @@ * @file ori.h * @brief Open Radio Interface (ORI) C library header file. * @author AW2S (http://www.aw2s.com) -* @version 1.6 -* @date July 29, 2019 +* @version 1.8 +* @date January 18, 2022 * * This file is the AW2S REC ORI C library header, and contains all necessary * functions prototypes, enumerations, data structures and type definitions @@ -14,7 +14,7 @@ #define ORI_H_ #define ORILIB_VERSION_MAJOR 1 -#define ORILIB_VERSION_MINOR 6 +#define ORILIB_VERSION_MINOR 8 #include @@ -144,10 +144,14 @@ typedef enum ORI_ObjectType_TxEUtraFDD, /**< */ ORI_ObjectType_TxEUtraTDD, /**< */ ORI_ObjectType_TxGSM, /**< */ + ORI_ObjectType_TxNRFDD, /**< */ + ORI_ObjectType_TxNRTDD, /**< */ ORI_ObjectType_RxUtra, /**< */ ORI_ObjectType_RxEUtraFDD, /**< */ ORI_ObjectType_RxEUtraTDD, /**< */ ORI_ObjectType_RxGSM, /**< */ + ORI_ObjectType_RxNRFDD, /**< */ + ORI_ObjectType_RxNRTDD, /**< */ ORI_ObjectType_ORILink, /**< */ ORI_ObjectType_ExternalEventPort, /**< */ ORI_ObjectType_AISGPort, /**< */ @@ -223,6 +227,7 @@ typedef enum ORI_ObjectParam_SigPath_AWS_enableCompBitChange, /**< */ ORI_ObjectParam_SigPath_AWS_measuredPwr, /**< */ ORI_ObjectParam_SigPath_AWS_axcIncr, /**< */ + ORI_ObjectParam_SigPath_AWS_arfcn, /**< */ ORI_ObjectParam_TxSigPath_t2a, /**< */ ORI_ObjectParam_TxSigPath_maxTxPwr, /**< */ ORI_ObjectParam_TxSigPath_dlCalRE, /**< */ @@ -252,12 +257,12 @@ typedef enum ORI_ObjectParam_ORILink_AWS_localMAC, /**< */ ORI_ObjectParam_ORILink_AWS_remoteMAC, /**< */ ORI_ObjectParam_ORILink_AWS_t14, /**< */ + ORI_ObjectParam_ORILink_AWS_sfpTxPow, /**< */ + ORI_ObjectParam_ORILink_AWS_sfpRxPow, /**< */ ORI_ObjectParam_ORILink_AWS_remoteIP, /**< */ ORI_ObjectParam_ORILink_AWS_localIP, /**< */ ORI_ObjectParam_ORILink_AWS_remoteUdpPort, /**< */ ORI_ObjectParam_ORILink_AWS_localUdpPort, /**< */ - ORI_ObjectParam_ORILink_AWS_sfpTxPow, /**< */ - ORI_ObjectParam_ORILink_AWS_sfpRxPow, /**< */ ORI_ObjectParam_AISGPort_busPowerEnable, /**< */ ORI_ObjectParam_AISGALD_deviceType, /**< */ ORI_ObjectParam_AISGALD_UID, /**< */ @@ -1146,6 +1151,50 @@ typedef struct ORI_Boolean_e AWS_enPeakCancel; /**< RW-Locked. AW2S Vendor specific: Peak-Cancellation CFR enablement. */ } ORI_ObjectParams_TxSigPathGSM_s; +/** + * @struct ORI_ObjectParams_TxSigPathNRFDD_s + * @brief Structure containing the parameters of a TxSigPath NRFDD object. + */ +typedef struct +{ + uint16_t chanBW; /**< RW-Locked. Channel bandwith in MHz/10. */ + uint16_t dlCalREMax; /**< RO. Max possible buffer in RE for DL timing calibration in Tc/16.*/ + uint32_t t2a; /**< RO. RE time delay. */ + uint16_t dlCalRE; /**< RW-Locked. Time delay to enable DL timing calibration in Tc/16. */ + int16_t maxTxPwr; /**< RW. Max tx power for this path, unit is dBm/10 (e.g. 400 for 40 dBm). */ + uint8_t axcW; /**< RW-Locked. AxC W parameter. */ + uint8_t axcB; /**< RW-Locked. AxC B parameter. */ + ORI_Object_s * oriLink; /**< RW-Locked. ORI Link on which the AxC is mapped. */ + ORI_Object_s * antPort; /**< RW-Locked. Reference Antenna port for this signal. */ + ORI_Boolean_e AWS_enableCompRateChange; /**< RW-Locked. AW2S Vendor specific: Enable IQ data compression sample rate change. */ + int16_t AWS_measuredPwr; /**< RO. AW2S Vendor specific: Measured Tx power for this path, unit is dBm/10 (e.g. 400 for 40 dBm). */ + uint16_t AWS_axcIncr; /**< RW-Locked. AW2S Vendor specific: AxC increment for each sample, 0 means auto (= packed, no interleaving). */ + ORI_Boolean_e AWS_enPeakCancel; /**< RW-Locked. AW2S Vendor specific: Peak-Cancellation CFR enablement. */ + uint32_t AWS_arfcn; /**< RW-Locked. ARFCN of the NR carrier. */ +} ORI_ObjectParams_TxSigPathNRFDD_s; + +/** + * @struct ORI_ObjectParams_TxSigPathNRTDD_s + * @brief Structure containing the parameters of a TxSigPath NRTDD object. + */ +typedef struct +{ + uint16_t chanBW; /**< RW-Locked. Channel bandwith in MHz/10. */ + uint16_t dlCalREMax; /**< RO. Max possible buffer in RE for DL timing calibration in Tc/16.*/ + uint32_t t2a; /**< RO. RE time delay. */ + uint16_t dlCalRE; /**< RW-Locked. Time delay to enable DL timing calibration in Tc/16. */ + int16_t maxTxPwr; /**< RW. Max tx power for this path, unit is dBm/10 (e.g. 400 for 40 dBm). */ + uint8_t axcW; /**< RW-Locked. AxC W parameter. */ + uint8_t axcB; /**< RW-Locked. AxC B parameter. */ + ORI_Object_s * oriLink; /**< RW-Locked. ORI Link on which the AxC is mapped. */ + ORI_Object_s * antPort; /**< RW-Locked. Reference Antenna port for this signal. */ + ORI_Boolean_e AWS_enableCompRateChange; /**< RW-Locked. AW2S Vendor specific: Enable IQ data compression sample rate change. */ + int16_t AWS_measuredPwr; /**< RO. AW2S Vendor specific: Measured Tx power for this path, unit is dBm/10 (e.g. 400 for 40 dBm). */ + uint16_t AWS_axcIncr; /**< RW-Locked. AW2S Vendor specific: AxC increment for each sample, 0 means auto (= packed, no interleaving). */ + ORI_Boolean_e AWS_enPeakCancel; /**< RW-Locked. AW2S Vendor specific: Peak-Cancellation CFR enablement. */ + uint32_t AWS_arfcn; /**< RW-Locked. ARFCN of the NR carrier. */ +} ORI_ObjectParams_TxSigPathNRTDD_s; + /** * @struct ORI_ObjectParams_RxSigPathUtra_s * @brief Structure containing the parameters of a RxSigPath UTRAFDD object. @@ -1239,6 +1288,48 @@ typedef struct uint16_t AWS_axcIncr; /**< RW-Locked. AW2S Vendor specific: AxC increment for each sample, 0 means auto (= packed, no interleaving). */ } ORI_ObjectParams_RxSigPathGSM_s; +/** + * @struct ORI_ObjectParams_RxSigPathNRFDD_s + * @brief Structure containing the parameters of a RxSigPath NRFDD object. + * + */ +typedef struct +{ + uint16_t chanBW; /**< RW-Locked. Channel bandwith in MHz/10. */ + uint16_t ulCalREMax; /**< RO. Max possible buffer in RE for UL timing calibration in Tc/2.*/ + uint32_t ta3; /**< RO. RE time delay. */ + uint16_t ulCalRE; /**< RW-Locked. Time delay to enable UL timing calibration in Tc/2. */ + uint8_t axcW; /**< RW-Locked. AxC W parameter. */ + uint8_t axcB; /**< RW-Locked. AxC B parameter. */ + ORI_Object_s * oriLink; /**< RW-Locked. ORI Link on which the AxC is mapped. */ + ORI_Object_s * antPort; /**< RW-Locked. Reference Antenna port for this signal. */ + ORI_Boolean_e AWS_enableCompRateChange; /**< RW-Locked. AW2S Vendor specific: Enable IQ data compression sample rate change. */ + int16_t AWS_measuredPwr; /**< RO. AW2S Vendor specific: Measured Rx power for this path, unit is dBm/10 (e.g. -650 for -65 dBm). */ + uint16_t AWS_axcIncr; /**< RW-Locked. AW2S Vendor specific: AxC increment for each sample, 0 means auto (= packed, no interleaving). */ + uint32_t AWS_arfcn; /**< RW-Locked. ARFCN of the NR carrier. */ +} ORI_ObjectParams_RxSigPathNRFDD_s; + +/** + * @struct ORI_ObjectParams_RxSigPathNRTDD_s + * @brief Structure containing the parameters of a RxSigPath NRTDD object. + * + */ +typedef struct +{ + uint16_t chanBW; /**< RW-Locked. Channel bandwith in MHz/10. */ + uint16_t ulCalREMax; /**< RO. Max possible buffer in RE for UL timing calibration in Tc/2.*/ + uint32_t ta3; /**< RO. RE time delay. */ + uint16_t ulCalRE; /**< RW-Locked. Time delay to enable UL timing calibration in Tc/2. */ + uint8_t axcW; /**< RW-Locked. AxC W parameter. */ + uint8_t axcB; /**< RW-Locked. AxC B parameter. */ + ORI_Object_s * oriLink; /**< RW-Locked. ORI Link on which the AxC is mapped. */ + ORI_Object_s * antPort; /**< RW-Locked. Reference Antenna port for this signal. */ + ORI_Boolean_e AWS_enableCompRateChange; /**< RW-Locked. AW2S Vendor specific: Enable IQ data compression sample rate change. */ + int16_t AWS_measuredPwr; /**< RO. AW2S Vendor specific: Measured Rx power for this path, unit is dBm/10 (e.g. -650 for -65 dBm). */ + uint16_t AWS_axcIncr; /**< RW-Locked. AW2S Vendor specific: AxC increment for each sample, 0 means auto (= packed, no interleaving). */ + uint32_t AWS_arfcn; /**< RW-Locked. ARFCN of the NR carrier. */ +} ORI_ObjectParams_RxSigPathNRTDD_s; + /** * @struct ORI_ObjectParams_ORILink_s * @brief Structure containing the parameters of an ORI Link object. @@ -1258,12 +1349,12 @@ typedef struct uint8_t AWS_localMAC[6]; /**< R0. AW2S Vendor specific: Local MAC address of the ORI link. */ uint8_t AWS_remoteMAC[6]; /**< RW. AW2S Vendor specific: Remote MAC address of the ORI link. */ uint32_t AWS_t14; /**< RO. AW2S Vendor specific: CPRI time delay component. */ - uint8_t AWS_remoteIP[4]; /**< RW. AW2S Vendor specific: REC IP for ECPRI Ethernet frame */ - uint8_t AWS_localIP[4]; /**< R0. AW2S Vendor specific: RE IP for ECPRI Ethernet frame */ - uint16_t AWS_remoteUdpPort; /**< RW. AW2S Vendor specific: REC Udp Port for ECPRI Ethernet frame */ - uint16_t AWS_localUdpPort; /**< R0. AW2S Vendor specific: RE Udp Port for ECPRI Ethernet frame */ uint32_t AWS_sfpTxPow; /**< RO. AW2S Vendor specific: SFP Tx power. */ uint32_t AWS_sfpRxPow; /**< RO. AW2S Vendor specific: SFP Rx power. */ + uint8_t AWS_remoteIP[4]; /**< RW. AW2S Vendor specific: IP of REC for ECPRI Ethernet frame */ + uint8_t AWS_localIP[4]; /**< RW. AW2S Vendor specific: IP of RE for ECPRI Ethernet frame */ + uint16_t AWS_remoteUdpPort; /**< RW. AW2S Vendor specific: UDP port of REC for ECPRI Ethernet frame */ + uint16_t AWS_localUdpPort; /**< RO. AW2S Vendor specific: UDP port of RE for ECPRI Ethernet frame */ } ORI_ObjectParams_ORILink_s; /** @@ -1393,10 +1484,14 @@ typedef union ORI_ObjectParams_TxSigPathEUtraFDD_s TxEUtraFDD; /**< Parameters for ::ORI_ObjectType_TxEUtraFDD. */ ORI_ObjectParams_TxSigPathEUtraTDD_s TxEUtraTDD; /**< Parameters for ::ORI_ObjectType_TxEUtraTDD. */ ORI_ObjectParams_TxSigPathGSM_s TxGSM; /**< Parameters for ::ORI_ObjectType_TxGSM. */ + ORI_ObjectParams_TxSigPathNRFDD_s TxNRFDD; /**< Parameters for ::ORI_ObjectType_TxNRFDD. */ + ORI_ObjectParams_TxSigPathNRTDD_s TxNRTDD; /**< Parameters for ::ORI_ObjectType_TxNRTDD. */ ORI_ObjectParams_RxSigPathUtra_s RxUtra; /**< Parameters for ::ORI_ObjectType_RxUtra. */ ORI_ObjectParams_RxSigPathEUtraFDD_s RxEUtraFDD; /**< Parameters for ::ORI_ObjectType_RxEUtraFDD. */ ORI_ObjectParams_RxSigPathEUtraTDD_s RxEUtraTDD; /**< Parameters for ::ORI_ObjectType_RxEUtraTDD. */ ORI_ObjectParams_RxSigPathGSM_s RxGSM; /**< Parameters for ::ORI_ObjectType_RxGSM. */ + ORI_ObjectParams_RxSigPathNRFDD_s RxNRFDD; /**< Parameters for ::ORI_ObjectType_RxNRFDD. */ + ORI_ObjectParams_RxSigPathNRTDD_s RxNRTDD; /**< Parameters for ::ORI_ObjectType_RxNRTDD. */ ORI_ObjectParams_ORILink_s ORILink; /**< Parameters for ::ORI_ObjectType_ORILink. */ ORI_ObjectParams_ExternalEventPort_s ExternalEventPort; /**< Parameters for ::ORI_ObjectType_ExternalEventPort. */ ORI_ObjectParams_AISGPort_s AISGPort; /**< Parameters for ::ORI_ObjectType_AISGPort. */ From 2776ec78b05c0f5b57e13c0911660d4b9decfc2d Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Thu, 3 Mar 2022 17:21:59 +0100 Subject: [PATCH 036/267] Add initial support for DL Data Delivery status reporting over NR-User plane protocol in gtp-u --- openair3/ocp-gtpu/gtp_itf.cpp | 124 ++++++++++++++++++++++++++++++---- openair3/ocp-gtpu/gtp_itf.h | 5 ++ 2 files changed, 114 insertions(+), 15 deletions(-) diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index 421aa24cc0..36cd9c7df1 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -34,6 +34,22 @@ typedef struct Gtpv1uMsgHeader { teid_t teid; } __attribute__((packed)) Gtpv1uMsgHeaderT; +//TS 38.425, Figure 5.5.2.2-1 +typedef struct DlDataDeliveryStatus_flags { + uint8_t LPR:1; //Lost packet report + uint8_t FFI:1; //Final Frame Ind + uint8_t deliveredPdcpSn:1; //Highest Delivered NR PDCP SN Ind + uint8_t transmittedPdcpSn:1; //Highest Transmitted NR PDCP SN Ind + uint8_t pduType:4; //PDU type + uint8_t CR:1; //Cause Report + uint8_t deliveredReTxPdcpSn:1; //Delivered retransmitted NR PDCP SN Ind + uint8_t reTxPdcpSn:1; //Retransmitted NR PDCP SN Ind + uint8_t DRI:1; //Data Rate Indication + uint8_t deliveredPdcpSnRange:1; //Delivered NR PDCP SN Range Ind + uint8_t spare:3; + uint32_t drbBufferSize; //Desired buffer size for the data radio bearer +} __attribute__((packed)) DlDataDeliveryStatus_flagsT; + #pragma pack() // TS 29.060, table 7.1 defines the possible message types @@ -59,12 +75,14 @@ typedef struct ocp_gtpv1u_bearer_s { typedef struct { map bearers; + teid_t outgoing_teid; } teidData_t; typedef struct { rnti_t rnti; ebi_t incoming_rb_id; gtpCallback callBack; + teid_t outgoing_teid; } rntiData_t; class gtpEndPoint { @@ -109,14 +127,16 @@ instance_t legacyInstanceMapping=0; static int gtpv1uCreateAndSendMsg(int h, uint32_t peerIp, uint16_t peerPort, int msgType, teid_t teid, uint8_t *Msg,int msgLen, - bool seqNumFlag, bool npduNumFlag, bool extHdrFlag, int seqNum, int npduNum, int extHdrType) { - AssertFatal(extHdrFlag==false,"Not developped"); + bool seqNumFlag, bool npduNumFlag, bool extHdrFlag, int seqNum, int npduNum, int extHdrType, + uint8_t *extensionHeader_buffer, uint8_t extensionHeader_length) { + LOG_D(GTPU, "Peer IP:%u peer port:%u outgoing teid:%u \n", peerIp, peerPort, teid); + //AssertFatal(extHdrFlag==false,"Not developped"); int headerAdditional=0; if ( seqNumFlag || npduNumFlag || extHdrFlag) headerAdditional=4; - int fullSize=GTPV1U_HEADER_SIZE+headerAdditional+msgLen; + int fullSize=GTPV1U_HEADER_SIZE+headerAdditional+msgLen+extensionHeader_length; uint8_t buffer[fullSize]; Gtpv1uMsgHeaderT *msgHdr = (Gtpv1uMsgHeaderT *)buffer ; // N should be 0 for us (it was used only in 2G and 3G) @@ -128,20 +148,42 @@ instance_t legacyInstanceMapping=0; msgHdr->PT=1; msgHdr->version=1; msgHdr->msgType=msgType; - msgHdr->msgLength=htons(msgLen); + msgHdr->msgLength=htons(msgLen+extensionHeader_length); if ( seqNumFlag || extHdrFlag || npduNumFlag) - msgHdr->msgLength+=4; + msgHdr->msgLength+=htons(4); msgHdr->teid=htonl(teid); if(seqNumFlag || extHdrFlag || npduNumFlag) { - *((uint16_t *) (buffer+8)) = seqNumFlag ? htons(seqNum) : 0x0000; - *((uint8_t *) (buffer+10)) = npduNumFlag ? htons(npduNum) : 0x00; - *((uint8_t *) (buffer+11)) = extHdrFlag ? htons(extHdrType) : 0x00; + *((uint16_t *) (buffer+8)) = seqNumFlag ? seqNum : 0x0000; + *((uint8_t *) (buffer+10)) = npduNumFlag ? npduNum : 0x00; + *((uint8_t *) (buffer+11)) = extHdrFlag ? extHdrType : 0x00; + + /**(buffer+8) = seqNumFlag ? htons(seqNum) : 0x0000; + *(buffer+10) = npduNumFlag ? htons(npduNum) : 0x00; + *(buffer+11) = extHdrFlag ? htons(extHdrType) : 0x00; + *(buffer+11) = extHdrType;*/ + } + + if(extHdrFlag){ + while (extHdrType){ + if (extensionHeader_length > 0 && extHdrType == 0x84){ + memcpy(buffer+GTPV1U_HEADER_SIZE+headerAdditional, extensionHeader_buffer, extensionHeader_length); + LOG_D(GTPU, "Extension Header for DDD added. The length is: %d, extension header type is: %x \n", extensionHeader_length, *((uint8_t *) (buffer+11))); + extHdrType = extensionHeader_buffer[extensionHeader_length -1]; + LOG_D(GTPU, "Next extension header type is: %x \n", *((uint8_t *) (buffer+11))); + } + else { + LOG_W(GTPU, "Extension header type not supported, returning... \n"); + return GTPNOK; + } + } + } + if (Msg!= NULL){ + memcpy(buffer+GTPV1U_HEADER_SIZE+headerAdditional+extensionHeader_length, Msg, msgLen); } - memcpy(buffer+GTPV1U_HEADER_SIZE+headerAdditional, Msg, msgLen); // Fix me: add IPv6 support, using flag ipVersion static struct sockaddr_in to= {0}; to.sin_family = AF_INET; @@ -196,9 +238,9 @@ static void gtpv1uSend(instance_t instance, gtpv1u_enb_tunnel_data_req_t *req, b gtpv1uCreateAndSendMsg(compatInst(instance), tmp.outgoing_ip_addr, tmp.outgoing_port, - GTP_GPDU, + GTP_GPDU, tmp.teid_outgoing, - buffer, length, seqNumFlag, npduNumFlag, false, tmp.seqNum, tmp.npduNum, 0) ; + buffer, length, seqNumFlag, npduNumFlag, false, tmp.seqNum, tmp.npduNum, 0, NULL, 0) ; } static void gtpv1uSend2(instance_t instance, gtpv1u_gnb_tunnel_data_req_t *req, bool seqNumFlag, bool npduNumFlag) { @@ -239,9 +281,9 @@ static void gtpv1uSend2(instance_t instance, gtpv1u_gnb_tunnel_data_req_t *req, gtpv1uCreateAndSendMsg(compatInst(instance), tmp.outgoing_ip_addr, tmp.outgoing_port, - GTP_GPDU, + GTP_GPDU, tmp.teid_outgoing, - buffer, length, seqNumFlag, npduNumFlag, false, tmp.seqNum, tmp.npduNum, 0) ; + buffer, length, seqNumFlag, npduNumFlag, false, tmp.seqNum, tmp.npduNum, 0, NULL, 0) ; } static void gtpv1uEndTunnel(instance_t instance, gtpv1u_enb_tunnel_data_req_t *req) { @@ -445,6 +487,8 @@ teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer inst->te2ue_mapping[incoming_teid].incoming_rb_id= incoming_bearer_id; + inst->te2ue_mapping[incoming_teid].outgoing_teid= outgoing_teid; + inst->te2ue_mapping[incoming_teid].callBack=callBack; ocp_gtpv1u_bearer_t *tmp=&inst->ue2te_mapping[rnti].bearers[outgoing_bearer_id]; @@ -664,7 +708,7 @@ static int Gtpv1uHandleEchoReq(int h, return gtpv1uCreateAndSendMsg(h, peerIp, peerPort, GTP_ECHO_RSP, ntohl(msgHdr->teid), recovery, sizeof recovery, - 1, 0, 0, seq, 0, 0); + 1, 0, 0, seq, 0, 0, NULL, 0); } @@ -787,9 +831,24 @@ static int Gtpv1uHandleGpdu(int h, if( msgHdr->E || msgHdr->S ||msgHdr->PN) offset+=4; + uint32_t NR_PDCP_PDU_SN = 0; //Consider the length of 1 or more extension headers that can be present in the GTP-U PDU if(msgHdr->E) { - while (msgBuf[offset]!=0) { + while (msgBuf[offset]!=0){ + if(msgBuf[offset-1] == 0x84){ //Extension header corresponding to NR-RAN container type + uint8_t PDU_type = (msgBuf[offset+1]>>4) & 0x0f; + if (PDU_type == 0){ //DL USER Data Format + if((msgBuf[offset+2]>>2)& 0x3){ //"Report delivered" and "User data existence flags" enabled (TS 38.425, 5.4) + /*Store the NR PDCP PDU SN for which a delivery status report shall be generated once the + *PDU gets forwarded to the lower layers*/ + NR_PDCP_PDU_SN = msgBuf[offset+3] << 16 | msgBuf[offset+4] << 8 | msgBuf[offset+5]; + LOG_D(GTPU, " NR_PDCP_PDU_SN: %u \n", NR_PDCP_PDU_SN); + } + } + else{ + LOG_W(GTPU, "NR-RAN container type: %d not supported \n", PDU_type); + } + } LOG_D(GTPU, "Extension header length in multiple of 4 bytes is: %d \n", msgBuf[offset]); offset+=msgBuf[offset]*4 -1; } @@ -830,6 +889,41 @@ static int Gtpv1uHandleGpdu(int h, &sourceL2Id, &destinationL2Id) ) LOG_E(GTPU,"[%d] down layer refused incoming packet\n", h); + if(NR_PDCP_PDU_SN > 0 && NR_PDCP_PDU_SN %5 ==0){ + LOG_D (GTPU, "Create and send DL DATA Delivery status for the previously received PDU, NR_PDCP_PDU_SN: %u \n", NR_PDCP_PDU_SN); + /*Total size of DDD_status PDU = 1 octet to report extension header length + * size of mandatory part + 3 octets for highest transmitted/delivered PDCP SN + * 1 octet for padding + 1 octet for next extension header type, + * according to TS 38.425: Fig. 5.5.2.2-1 and section 5.5.3.24*/ + extensionHeader_t *extensionHeader; + extensionHeader = (extensionHeader_t *) calloc(1, sizeof(extensionHeader_t)) ; + extensionHeader->buffer[0] = (1+sizeof(DlDataDeliveryStatus_flagsT)+3+1+1)/4; + DlDataDeliveryStatus_flagsT DlDataDeliveryStatus; + DlDataDeliveryStatus.deliveredPdcpSn = 0; + DlDataDeliveryStatus.transmittedPdcpSn= 1; + DlDataDeliveryStatus.pduType = 1; + DlDataDeliveryStatus.drbBufferSize = htonl(1000000); //hardcoded for now but normally we should extract it from RLC + memcpy(extensionHeader->buffer+1, &DlDataDeliveryStatus, sizeof(DlDataDeliveryStatus_flagsT)); + uint8_t offset = sizeof(DlDataDeliveryStatus_flagsT)+1; + + extensionHeader->buffer[offset] = (NR_PDCP_PDU_SN >> 16) & 0xff; + extensionHeader->buffer[offset+1] = (NR_PDCP_PDU_SN >> 8) & 0xff; + extensionHeader->buffer[offset+2] = NR_PDCP_PDU_SN & 0xff; + LOG_D(GTPU, "Octets reporting NR_PDCP_PDU_SN, extensionHeader->buffer[offset]: %u, extensionHeader->buffer[offset+1]:%u, extensionHeader->buffer[offset+2]:%u \n", extensionHeader->buffer[offset], extensionHeader->buffer[offset+1],extensionHeader->buffer[offset+2]); + extensionHeader->buffer[offset+3] = 0x00; //Padding octet + extensionHeader->buffer[offset+4] = 0x00; //No more extension headers + /*Total size of DDD_status PDU = size of mandatory part + + * 3 octets for highest transmitted/delivered PDCP SN + + * 1 octet for padding + 1 octet for next extension header type, + * according to TS 38.425: Fig. 5.5.2.2-1 and section 5.5.3.24*/ + extensionHeader->length = 1+sizeof(DlDataDeliveryStatus_flagsT)+3+1+1; + gtpv1uCreateAndSendMsg(h, + peerIp, + peerPort, + GTP_GPDU, + inst->te2ue_mapping[ntohl(msgHdr->teid)].outgoing_teid, + NULL, 0, false, false, true, 0, 0, 0x84, extensionHeader->buffer, extensionHeader->length) ; + } LOG_D(GTPU,"[%d] Received a %d bytes packet for: teid:%x\n", h, msgBufLen-offset, diff --git a/openair3/ocp-gtpu/gtp_itf.h b/openair3/ocp-gtpu/gtp_itf.h index 3893acf40f..940e3415bf 100644 --- a/openair3/ocp-gtpu/gtp_itf.h +++ b/openair3/ocp-gtpu/gtp_itf.h @@ -41,6 +41,11 @@ typedef struct openAddr_s { instance_t originInstance; } openAddr_t; +typedef struct extensionHeader_s{ + uint8_t buffer[500]; + uint8_t length; +}extensionHeader_t; + // the init function create a gtp instance and return the gtp instance id // the parameter originInstance will be sent back in each message from gtp to the creator void ocp_gtpv1uReceiver(int h); From 14ec3e505d036d5bad87b16135412379637d2bda Mon Sep 17 00:00:00 2001 From: matzakos Date: Wed, 9 Mar 2022 19:08:15 +0100 Subject: [PATCH 037/267] Fix decoding of UE-capabilities-RAT-container-list at the DU after receiving it from the CU --- openair2/RRC/NR/rrc_gNB.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 48987b6a97..97aed1ebee 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -3004,9 +3004,9 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha if(req->cu_to_du_rrc_information!=NULL){ - /*if(req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList!=NULL){ + if(req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList!=NULL){ LOG_I(NR_RRC, "Length of ue_CapabilityRAT_ContainerList is: %d \n", (int) req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length); - struct NR_UE_CapabilityRAT_ContainerList *ue_CapabilityRAT_ContainerList; + struct NR_UE_CapabilityRAT_ContainerList *ue_CapabilityRAT_ContainerList = NULL; asn_dec_rval_t dec_rval = uper_decode_complete( NULL, &asn_DEF_NR_UE_CapabilityRAT_ContainerList, (void **)&ue_CapabilityRAT_ContainerList, @@ -3088,7 +3088,7 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha //TODO } } - }*/ + } } NR_CellGroupConfig_t *cellGroupConfig; From a88a8dae8e12bf9ed2b55d8243e58ebe21304c69 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 11 Mar 2022 12:27:00 +0100 Subject: [PATCH 038/267] config of pucch2 in rrcsetup --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 09baf9d824..ac092957d1 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1034,6 +1034,8 @@ void fill_initial_SpCellConfig(int uid, pucch_Config->resourceToAddModList = calloc(1,sizeof(*pucch_Config->resourceToAddModList)); pucch_Config->resourceToReleaseList = NULL; config_pucch_resset0(pucch_Config, uid, curr_bwp, NULL); + config_pucch_resset1(pucch_Config, NULL); + set_pucch_power_config(pucch_Config, carrier->do_CSIRS); initialUplinkBWP->pusch_Config = calloc(1,sizeof(*initialUplinkBWP->pusch_Config)); initialUplinkBWP->pusch_Config->present = NR_SetupRelease_PUSCH_Config_PR_setup; @@ -1410,11 +1412,6 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, if (SpCellConfig == NULL) return; - NR_BWP_UplinkDedicated_t *initialUplinkBWP = SpCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; - NR_PUCCH_Config_t *pucch_Config = initialUplinkBWP->pucch_Config->choice.setup; - config_pucch_resset1(pucch_Config, uecap); - set_pucch_power_config(pucch_Config, carrier->do_CSIRS); - NR_ServingCellConfigCommon_t *scc = carrier->servingcellconfigcommon; NR_BWP_DownlinkDedicated_t *bwp_Dedicated = SpCellConfig->spCellConfigDedicated->initialDownlinkBWP; From 03617b916545d08a862653b31c29c615469b324c Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 14 Mar 2022 10:43:59 +0100 Subject: [PATCH 039/267] more general SR config for period and offset --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 2 +- openair2/RRC/NR/nr_rrc_config.c | 53 ++++++++++++++++++++++++++--- openair2/RRC/NR/nr_rrc_config.h | 3 +- openair2/RRC/NR/rrc_gNB_reconfig.c | 2 +- 4 files changed, 53 insertions(+), 7 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index ac092957d1..2d09506c69 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1184,7 +1184,7 @@ void fill_initial_SpCellConfig(int uid, srs_res0->spatialRelationInfo->referenceSignal.choice.csi_RS_Index=0; ASN_SEQUENCE_ADD(&srs_Config->srs_ResourceToAddModList->list,srs_res0); - schedulingrequest_config(cellGroupConfig->mac_CellGroupConfig, pucch_Config); + schedulingrequest_config(scc, cellGroupConfig->mac_CellGroupConfig, pucch_Config); set_dl_DataToUL_ACK(pucch_Config, carrier->minRXTXTIME); diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 99786f660b..835348095e 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -286,7 +286,52 @@ void set_pucch_power_config(NR_PUCCH_Config_t *pucch_Config, int do_csirs) { ASN_SEQUENCE_ADD(&pucch_Config->spatialRelationInfoToAddModList->list,pucchspatial); } -void schedulingrequest_config(NR_MAC_CellGroupConfig_t *mac_CellGroupConfig, +void set_SR_periodandoffset(NR_SchedulingRequestResourceConfig_t *schedulingRequestResourceConfig, + NR_ServingCellConfigCommon_t *scc) { + + const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; + int sr_slot = 0; + if(tdd) + sr_slot = tdd->nrofDownlinkSlots; // SR in the first uplink slot + + schedulingRequestResourceConfig->periodicityAndOffset = calloc(1,sizeof(*schedulingRequestResourceConfig->periodicityAndOffset)); + + if(sr_slot<10){ + schedulingRequestResourceConfig->periodicityAndOffset->present = NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl10; + schedulingRequestResourceConfig->periodicityAndOffset->choice.sl10 = sr_slot; + return; + } + if(sr_slot<20){ + schedulingRequestResourceConfig->periodicityAndOffset->present = NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl20; + schedulingRequestResourceConfig->periodicityAndOffset->choice.sl20 = sr_slot; + return; + } + if(sr_slot<40){ + schedulingRequestResourceConfig->periodicityAndOffset->present = NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl40; + schedulingRequestResourceConfig->periodicityAndOffset->choice.sl40 = sr_slot; + return; + } + if(sr_slot<80){ + schedulingRequestResourceConfig->periodicityAndOffset->present = NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl80; + schedulingRequestResourceConfig->periodicityAndOffset->choice.sl80 = sr_slot; + return; + } + if(sr_slot<160){ + schedulingRequestResourceConfig->periodicityAndOffset->present = NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl160; + schedulingRequestResourceConfig->periodicityAndOffset->choice.sl160 = sr_slot; + return; + } + if(sr_slot<320){ + schedulingRequestResourceConfig->periodicityAndOffset->present = NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl320; + schedulingRequestResourceConfig->periodicityAndOffset->choice.sl320 = sr_slot; + return; + } + schedulingRequestResourceConfig->periodicityAndOffset->present = NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl640; + schedulingRequestResourceConfig->periodicityAndOffset->choice.sl640 = sr_slot; +} + +void schedulingrequest_config(NR_ServingCellConfigCommon_t *scc, + NR_MAC_CellGroupConfig_t *mac_CellGroupConfig, NR_PUCCH_Config_t *pucch_Config) { mac_CellGroupConfig->schedulingRequestConfig = calloc(1, sizeof(*mac_CellGroupConfig->schedulingRequestConfig)); @@ -306,9 +351,9 @@ void schedulingrequest_config(NR_MAC_CellGroupConfig_t *mac_CellGroupConfig, NR_SchedulingRequestResourceConfig_t *schedulingRequestResourceConfig = calloc(1,sizeof(*schedulingRequestResourceConfig)); schedulingRequestResourceConfig->schedulingRequestResourceId = 1; schedulingRequestResourceConfig->schedulingRequestID = 0; - schedulingRequestResourceConfig->periodicityAndOffset = calloc(1,sizeof(*schedulingRequestResourceConfig->periodicityAndOffset)); - schedulingRequestResourceConfig->periodicityAndOffset->present = NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl10; - schedulingRequestResourceConfig->periodicityAndOffset->choice.sl10 = 7; + + set_SR_periodandoffset(schedulingRequestResourceConfig, scc); + schedulingRequestResourceConfig->resource = calloc(1,sizeof(*schedulingRequestResourceConfig->resource)); *schedulingRequestResourceConfig->resource = *pucchressetid; ASN_SEQUENCE_ADD(&pucch_Config->schedulingRequestResourceToAddModList->list,schedulingRequestResourceConfig); diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index 1080d58d40..813549b621 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -117,7 +117,8 @@ void config_pucch_resset0(NR_PUCCH_Config_t *pucch_Config, int uid, int curr_bwp void config_pucch_resset1(NR_PUCCH_Config_t *pucch_Config, NR_UE_NR_Capability_t *uecap); void set_dl_DataToUL_ACK(NR_PUCCH_Config_t *pucch_Config, int min_feedback_time); void set_pucch_power_config(NR_PUCCH_Config_t *pucch_Config, int do_csirs); -void schedulingrequest_config(NR_MAC_CellGroupConfig_t *mac_CellGroupConfig, +void schedulingrequest_config(NR_ServingCellConfigCommon_t *scc, + NR_MAC_CellGroupConfig_t *mac_CellGroupConfig, NR_PUCCH_Config_t *pucch_Config); void set_dl_mcs_table(int scs, NR_UE_NR_Capability_t *cap, NR_BWP_DownlinkDedicated_t *bwp_Dedicated, diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index 46e6b46016..a9c0f523c5 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -859,7 +859,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco config_pucch_resset0(pucch_Config, uid, curr_bwp, uecap); // <= 2 bits config_pucch_resset1(pucch_Config, uecap); // > 2 bits - schedulingrequest_config(secondaryCellGroup->mac_CellGroupConfig, pucch_Config); + schedulingrequest_config(servingcellconfigcommon, secondaryCellGroup->mac_CellGroupConfig, pucch_Config); pucch_Config->schedulingRequestResourceToReleaseList=NULL; pucch_Config->multi_CSI_PUCCH_ResourceList=NULL; From 8edcd41a8d26ccb779a09c41ed05097ba6c951e6 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 14 Mar 2022 17:35:04 +0100 Subject: [PATCH 040/267] fix for pucch0 that straddles DC carrier --- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index b85dbd1454..eab48fa24a 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -282,23 +282,35 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, } int n2; + int nb_re_pucch = 12*pucch_pdu->prb_size; // prb size is 1 + int32_t rp[frame_parms->nb_antennas_rx][2][nb_re_pucch],*tmp_rp; + for (int l=0; lnr_of_symbols; l++) { l2 = l+pucch_pdu->start_symbol_index; + re_offset[l] = (12*prb_offset[l]) + frame_parms->first_carrier_offset; if (re_offset[l]>= frame_parms->ofdm_symbol_size) re_offset[l]-=frame_parms->ofdm_symbol_size; - - AssertFatal(re_offset[l]+12 < frame_parms->ofdm_symbol_size,"pucch straddles DC carrier, handle this!\n"); - int16_t *r; + for (int aa=0;aanb_antennas_rx;aa++) { - r=(int16_t*)&rxdataF[aa][soffset+(l2*frame_parms->ofdm_symbol_size)+re_offset[l]]; + tmp_rp = &rxdataF[aa][soffset + l2*frame_parms->ofdm_symbol_size]; + if(re_offset[l] + nb_re_pucch > frame_parms->ofdm_symbol_size) { + int neg_length = frame_parms->ofdm_symbol_size-re_offset[l]; + int pos_length = nb_re_pucch-neg_length; + memcpy1((void*)rp[aa][l],(void*)&tmp_rp[re_offset[l]],neg_length*sizeof(int32_t)); + memcpy1((void*)&rp[aa][l][neg_length],(void*)tmp_rp,pos_length*sizeof(int32_t)); + } + else + memcpy1((void*)rp[aa][l],(void*)&tmp_rp[re_offset[l]],nb_re_pucch*sizeof(int32_t)); + + int16_t *r = (int16_t*)&rp[aa][l]; n2=0; for (n=0;n<12;n++,n2+=2) { xr[aa][l][n2] +=(int16_t)(((int32_t)x_re[l][n]*r[n2]+(int32_t)x_im[l][n]*r[n2+1])>>15); xr[aa][l][n2+1]+=(int16_t)(((int32_t)x_re[l][n]*r[n2+1]-(int32_t)x_im[l][n]*r[n2])>>15); #ifdef DEBUG_NR_PUCCH_RX printf("x (%d,%d), r%d.%d (%d,%d), xr (%d,%d)\n", - x_re[l][n],x_im[l][n],l2,re_offset[l],r[n2],r[n2+1],xr[aa][l][n2],xr[aa][l][n2+1]); + x_re[l][n],x_im[l][n],l2,re_offset[l],r[n2],r[n2+1],xr[aa][l][n2],xr[aa][l][n2+1]); #endif } } @@ -395,9 +407,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, int max_n0 = uci_stats->pucch0_n00>uci_stats->pucch0_n01 ? uci_stats->pucch0_n00:uci_stats->pucch0_n01; int SNRtimes10,sigenergy=0; for (int aa=0;aanb_antennas_rx;aa++) - sigenergy += signal_energy_nodc(&rxdataF[aa][soffset+ - (pucch_pdu->start_symbol_index*frame_parms->ofdm_symbol_size)+ - re_offset[0]],12); + sigenergy += signal_energy_nodc(rp[aa][0],12); SNRtimes10 = xrtmag_dBtimes10-(10*max_n0); int cqi; if (SNRtimes10 < -640) cqi=0; From f40b579a78bd1ccd886c10ee0ad147138855d10c Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 16 Mar 2022 15:13:50 +0100 Subject: [PATCH 041/267] fix for phy-simulator issues --- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 4 ++-- openair1/SIMULATION/NR_PHY/pucchsim.c | 1 + openair2/RRC/NR/nr_rrc_config.c | 8 ++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index eab48fa24a..083dbb328c 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -283,7 +283,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, int n2; int nb_re_pucch = 12*pucch_pdu->prb_size; // prb size is 1 - int32_t rp[frame_parms->nb_antennas_rx][2][nb_re_pucch],*tmp_rp; + int32_t rp[frame_parms->nb_antennas_rx][pucch_pdu->nr_of_symbols][nb_re_pucch],*tmp_rp; for (int l=0; lnr_of_symbols; l++) { l2 = l+pucch_pdu->start_symbol_index; @@ -305,7 +305,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, int16_t *r = (int16_t*)&rp[aa][l]; n2=0; - for (n=0;n<12;n++,n2+=2) { + for (n=0;n>15); xr[aa][l][n2+1]+=(int16_t)(((int32_t)x_re[l][n]*r[n2+1]-(int32_t)x_im[l][n]*r[n2])>>15); #ifdef DEBUG_NR_PUCCH_RX diff --git a/openair1/SIMULATION/NR_PHY/pucchsim.c b/openair1/SIMULATION/NR_PHY/pucchsim.c index 151d51d726..5d85135677 100644 --- a/openair1/SIMULATION/NR_PHY/pucchsim.c +++ b/openair1/SIMULATION/NR_PHY/pucchsim.c @@ -640,6 +640,7 @@ int main(int argc, char **argv) pucch_pdu.initial_cyclic_shift = 0; pucch_pdu.start_symbol_index = startingSymbolIndex; pucch_pdu.prb_start = startingPRB; + pucch_pdu.prb_size = 1; pucch_pdu.bwp_start = 0; pucch_pdu.bwp_size = N_RB_DL; if (nrofSymbols>1) { diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 835348095e..98004f9add 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -37,6 +37,7 @@ void prepare_sim_uecap(NR_UE_NR_Capability_t *cap, int rbsize, int mcs_table) { + NR_Phy_Parameters_t *phy_Parameters = &cap->phy_Parameters; int band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; NR_BandNR_t *nr_bandnr = CALLOC(1,sizeof(NR_BandNR_t)); nr_bandnr->bandNR = band; @@ -50,8 +51,8 @@ void prepare_sim_uecap(NR_UE_NR_Capability_t *cap, *bandNRinfo->pdsch_256QAM_FR2 = NR_BandNR__pdsch_256QAM_FR2_supported; } else{ - cap->phy_Parameters.phy_ParametersFR1 = CALLOC(1,sizeof(*cap->phy_Parameters.phy_ParametersFR1)); - NR_Phy_ParametersFR1_t *phy_fr1 = cap->phy_Parameters.phy_ParametersFR1; + phy_Parameters->phy_ParametersFR1 = CALLOC(1,sizeof(*phy_Parameters->phy_ParametersFR1)); + NR_Phy_ParametersFR1_t *phy_fr1 = phy_Parameters->phy_ParametersFR1; phy_fr1->pdsch_256QAM_FR1 = CALLOC(1,sizeof(*phy_fr1->pdsch_256QAM_FR1)); *phy_fr1->pdsch_256QAM_FR1 = NR_Phy_ParametersFR1__pdsch_256QAM_FR1_supported; } @@ -73,6 +74,9 @@ void prepare_sim_uecap(NR_UE_NR_Capability_t *cap, ASN_SEQUENCE_ADD(&fs->featureSetsDownlinkPerCC->list, fs_cc); } + + phy_Parameters->phy_ParametersFRX_Diff = CALLOC(1,sizeof(*phy_Parameters->phy_ParametersFRX_Diff)); + phy_Parameters->phy_ParametersFRX_Diff->pucch_F0_2WithoutFH = NULL; } void nr_rrc_config_dl_tda(NR_ServingCellConfigCommon_t *scc){ From aba5098e30587309f8e5af9c66a8bdaba7e3cdb6 Mon Sep 17 00:00:00 2001 From: matzakos Date: Thu, 17 Mar 2022 17:01:01 +0100 Subject: [PATCH 042/267] Remove hardcoding of port numbers in handling of F1 UE context modification request --- openair2/F1AP/f1ap_du_ue_context_management.c | 4 +++- openair2/RRC/NR/rrc_gNB.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index 30dec1de08..ca0ddcc82d 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -1154,6 +1154,8 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, F1AP_GTPTunnel_t *ul_up_tnl0 = ul_up_tnl_info_p->uLUPTNLInformation.choice.gTPTunnel; BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&ul_up_tnl0->transportLayerAddress, drb_p->up_ul_tnl[0].tl_address); OCTET_STRING_TO_INT32(&ul_up_tnl0->gTP_TEID, drb_p->up_ul_tnl[0].teid); + // 3GPP assumes GTP-U is on port 2152, but OAI is configurable + drb_p->up_ul_tnl[0].port=getCxt(false,instance)->setupReq.CUport; switch (drbs_tobesetupmod_item_p->rLCMode) { case F1AP_RLCMode_rlc_am: @@ -1174,7 +1176,7 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, drb_p->drb_id, drb_p->up_ul_tnl[0].teid, addr, - 2152, + drb_p->up_ul_tnl[0].port, lteDURecvCb); drb_p->up_dl_tnl_length++; } diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 28ccfb1181..bded0a619d 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -3465,7 +3465,7 @@ static void rrc_DU_process_ue_context_modification_request(MessageDef *msg_p, co drb_p.drb_id, drb_p.up_ul_tnl[0].teid, addr, - 2152, + drb_p.up_ul_tnl[0].port, DURecvCb); } } From 4e73ef0c3bb6a949e9498e8b03e9a8a33c4f93aa Mon Sep 17 00:00:00 2001 From: matzakos Date: Thu, 17 Mar 2022 17:01:50 +0100 Subject: [PATCH 043/267] Avoid exiting in case of PDPC receiving UL user-plane traffic before the DRB is established -Happened occasionally in the CU/DU split scenario --- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 1f66400af1..8afba9d315 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -274,9 +274,10 @@ static void do_pdcp_data_ind( if (rb != NULL) { rb->recv_pdu(rb, (char *)sdu_buffer->data, sdu_buffer_size); } else { - LOG_E(PDCP, "%s:%d:%s: fatal: no RB found (rb_id %ld, srb_flag %d)\n", + LOG_E(PDCP, "%s:%d:%s: no RB found (rb_id %ld, srb_flag %d)\n", __FILE__, __LINE__, __FUNCTION__, rb_id, srb_flagP); - exit(1); + return; + } nr_pdcp_manager_unlock(nr_pdcp_ue_manager); From 184e151fde961300bf7179b6123a728dee7ee0a3 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Tue, 22 Mar 2022 17:40:06 +0000 Subject: [PATCH 044/267] Fix build after merge --- openair1/PHY/INIT/nr_init_ue.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 45cb2849dd..f1dd418dbf 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -337,6 +337,9 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) csirs_vars[gNB_id]->active = false; srs_vars[gNB_id]->active = false; + // ceil((NB_RB*8(max allocation per RB)*2(QPSK))/32) + int csi_dmrs_init_length = ((fp->N_RB_DL<<4)>>5)+1; + ue->nr_csi_rs_info = (nr_csi_rs_info_t *)malloc16_clear(sizeof(nr_csi_rs_info_t)); ue->nr_csi_rs_info->nr_gold_csi_rs = (uint32_t ***)malloc16(fp->slots_per_frame*sizeof(uint32_t **)); AssertFatal(ue->nr_csi_rs_info->nr_gold_csi_rs!=NULL, "NR init: csi reference signal malloc failed\n"); @@ -344,7 +347,7 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) ue->nr_csi_rs_info->nr_gold_csi_rs[slot] = (uint32_t **)malloc16(fp->symbols_per_slot*sizeof(uint32_t *)); AssertFatal(ue->nr_csi_rs_info->nr_gold_csi_rs[slot]!=NULL, "NR init: csi reference signal for slot %d - malloc failed\n", slot); for (int symb=0; symbsymbols_per_slot; symb++) { - ue->nr_csi_rs_info->nr_gold_csi_rs[slot][symb] = (uint32_t *)malloc16(NR_MAX_CSI_RS_INIT_LENGTH_DWORD*sizeof(uint32_t)); + ue->nr_csi_rs_info->nr_gold_csi_rs[slot][symb] = (uint32_t *)malloc16(csi_dmrs_init_length*sizeof(uint32_t)); AssertFatal(ue->nr_csi_rs_info->nr_gold_csi_rs[slot][symb]!=NULL, "NR init: csi reference signal for slot %d symbol %d - malloc failed\n", slot, symb); } } From 17504695f833173413593e2f8c56970689d0cb44 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Tue, 22 Mar 2022 18:02:12 +0000 Subject: [PATCH 045/267] Fix updated configurations that was reverted in merge --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 319aa535e7..5f1b43c998 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1137,7 +1137,7 @@ void fill_default_csi_MeasConfig(int uid, csirep1->reportConfigType.present = NR_CSI_ReportConfig__reportConfigType_PR_periodic; csirep1->reportConfigType.choice.periodic = calloc(1,sizeof(*csirep1->reportConfigType.choice.periodic)); csirep1->reportConfigType.choice.periodic->reportSlotConfig.present=NR_CSI_ReportPeriodicityAndOffset_PR_slots320; - csirep1->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320 = 9 + (20 * uid) % 320; + csirep1->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320 = (8 + (20 * uid)) % 320; ASN_SEQUENCE_ADD(&csirep1->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list,pucchcsires1); csirep1->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI; csirep1->reportQuantity.choice.cri_RI_PMI_CQI=(NULL_t)0; @@ -1196,7 +1196,7 @@ void fill_default_csi_MeasConfig(int uid, csirep2->reportConfigType.present = NR_CSI_ReportConfig__reportConfigType_PR_periodic; csirep2->reportConfigType.choice.periodic = calloc(1,sizeof(*csirep2->reportConfigType.choice.periodic)); csirep2->reportConfigType.choice.periodic->reportSlotConfig.present=NR_CSI_ReportPeriodicityAndOffset_PR_slots320; - csirep2->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320 = 29 + (20 * uid) % 320; + csirep2->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320 = (28 + (20 * uid)) % 320; ASN_SEQUENCE_ADD(&csirep2->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list,pucchcsires1); csirep2->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP; csirep2->reportQuantity.choice.cri_RSRP=(NULL_t)0; From e834acfaf2396b7a56088d85ccb92a9090213621 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Tue, 22 Mar 2022 18:25:29 +0000 Subject: [PATCH 046/267] Temporary commit to test CSI-RS without core --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 44 +++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 5f1b43c998..f90bdaa597 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1307,8 +1307,13 @@ void fill_initial_SpCellConfig(int uid, NR_PUCCH_SpatialRelationInfo_t *pucchspatial = calloc(1,sizeof(*pucchspatial)); pucchspatial->pucch_SpatialRelationInfoId = 1; pucchspatial->servingCellId = NULL; - pucchspatial->referenceSignal.present = NR_PUCCH_SpatialRelationInfo__referenceSignal_PR_ssb_Index; - pucchspatial->referenceSignal.choice.ssb_Index = 0; + + // TODO: Remove this if + if(!carrier->do_CSIRS) { + pucchspatial->referenceSignal.present = NR_PUCCH_SpatialRelationInfo__referenceSignal_PR_ssb_Index; + pucchspatial->referenceSignal.choice.ssb_Index = 0; + } + pucchspatial->pucch_PathlossReferenceRS_Id = 0; pucchspatial->p0_PUCCH_Id = 1; pucchspatial->closedLoopIndex = NR_PUCCH_SpatialRelationInfo__closedLoopIndex_i0; @@ -1575,13 +1580,13 @@ void fill_initial_SpCellConfig(int uid, bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->maxLength=NULL; bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition)); - *bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = NR_DMRS_DownlinkConfig__dmrs_AdditionalPosition_pos1; - bwp_Dedicated->pdsch_Config->choice.setup->resourceAllocation = NR_PDSCH_Config__resourceAllocation_resourceAllocationType1; - bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.present = NR_PDSCH_Config__prb_BundlingType_PR_staticBundling; - bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling = calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling)); - bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize = - calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize)); - *bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize = NR_PDSCH_Config__prb_BundlingType__staticBundling__bundleSize_wideband; + *bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = NR_DMRS_DownlinkConfig__dmrs_AdditionalPosition_pos1; + bwp_Dedicated->pdsch_Config->choice.setup->resourceAllocation = NR_PDSCH_Config__resourceAllocation_resourceAllocationType1; + bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.present = NR_PDSCH_Config__prb_BundlingType_PR_staticBundling; + bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling = calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling)); + bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize = + calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize)); + *bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize = NR_PDSCH_Config__prb_BundlingType__staticBundling__bundleSize_wideband; bwp_Dedicated->pdsch_Config->choice.setup->tci_StatesToAddModList=calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->tci_StatesToAddModList)); NR_TCI_State_t *tcic; @@ -1602,6 +1607,25 @@ void fill_initial_SpCellConfig(int uid, SpCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->present = NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup; SpCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup = pdsch_servingcellconfig; + // TODO: Delete this code and calls in update_cellGroupConfig() + if (carrier->do_CSIRS) { + struct NR_PUCCH_Config__spatialRelationInfoToAddModList *spatialRelationInfoToAddModList = calloc(1,sizeof(*spatialRelationInfoToAddModList)); + NR_PUCCH_SpatialRelationInfo_t *pucchspatial = calloc(1,sizeof(*pucchspatial)); + pucchspatial->pucch_SpatialRelationInfoId = 1; + pucchspatial->servingCellId = NULL; + pucchspatial->referenceSignal.present = NR_PUCCH_SpatialRelationInfo__referenceSignal_PR_csi_RS_Index; + pucchspatial->referenceSignal.choice.csi_RS_Index = 0; + pucchspatial->pucch_PathlossReferenceRS_Id = 0; + pucchspatial->p0_PUCCH_Id = 1; + pucchspatial->closedLoopIndex = NR_PUCCH_SpatialRelationInfo__closedLoopIndex_i0; + ASN_SEQUENCE_ADD(&spatialRelationInfoToAddModList->list,pucchspatial); + SpCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pucch_Config->choice.setup->spatialRelationInfoToAddModList = spatialRelationInfoToAddModList; + if(!SpCellConfig->spCellConfigDedicated->csi_MeasConfig) { + SpCellConfig->spCellConfigDedicated->csi_MeasConfig=calloc(1,sizeof(*SpCellConfig->spCellConfigDedicated->csi_MeasConfig)); + } + fill_default_csi_MeasConfig(uid, SpCellConfig->spCellConfigDedicated->csi_MeasConfig, scc, carrier); + } + pdsch_servingcellconfig->codeBlockGroupTransmission = NULL; pdsch_servingcellconfig->xOverhead = NULL; pdsch_servingcellconfig->nrofHARQ_ProcessesForPDSCH = calloc(1, sizeof(*pdsch_servingcellconfig->nrofHARQ_ProcessesForPDSCH)); @@ -1709,6 +1733,7 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_ServingCellConfigCommon_t *scc = carrier->servingcellconfigcommon; // Config CSI-RS + /* if (carrier->do_CSIRS) { struct NR_PUCCH_Config__spatialRelationInfoToAddModList *spatialRelationInfoToAddModList = calloc(1,sizeof(*spatialRelationInfoToAddModList)); NR_PUCCH_SpatialRelationInfo_t *pucchspatial = calloc(1,sizeof(*pucchspatial)); @@ -1726,6 +1751,7 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, } fill_default_csi_MeasConfig(uid, SpCellConfig->spCellConfigDedicated->csi_MeasConfig, scc, carrier); } + */ // Set DL MCS table NR_BWP_DownlinkDedicated_t *bwp_Dedicated = SpCellConfig->spCellConfigDedicated->initialDownlinkBWP; From 3e664b5eb7e5b26396e147a5b0786c4df7adc59a Mon Sep 17 00:00:00 2001 From: rmagueta Date: Tue, 22 Mar 2022 18:28:49 +0000 Subject: [PATCH 047/267] Fix warning --- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 1a37e8c6d9..8a5535c1a7 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -225,7 +225,7 @@ void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req) { } } - int dumpsig=0; + //int dumpsig=0; // if all segments are done if (rdata->nbSegments == ulsch_harq->processedSegments) { if (decodeSuccess) { From a77c1d32026f4f4b8a9c0a54d8a7a0f87cf4ef84 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Tue, 29 Mar 2022 12:17:37 +0200 Subject: [PATCH 048/267] Trigger first DL Data Delivery status from DU to report the buffer availability to the CU -After that no DL traffic is getting blocked at the Accelleran CU for low values of throughput -Remaining to remove the hardcoded value of buffer availability and report the actual value from the DU. --- openair2/COMMON/gtpv1_u_messages_def.h | 3 +- openair2/COMMON/gtpv1_u_messages_types.h | 8 +++ openair2/RRC/NR/rrc_gNB.c | 15 +++++ openair3/ocp-gtpu/gtp_itf.cpp | 74 ++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 1 deletion(-) diff --git a/openair2/COMMON/gtpv1_u_messages_def.h b/openair2/COMMON/gtpv1_u_messages_def.h index 44e9d4fbdf..e0e5db5b7f 100644 --- a/openair2/COMMON/gtpv1_u_messages_def.h +++ b/openair2/COMMON/gtpv1_u_messages_def.h @@ -27,4 +27,5 @@ MESSAGE_DEF(GTPV1U_ENB_END_MARKER_REQ, MESSAGE_PRIORITY_MED, gtpv1u_enb_end MESSAGE_DEF(GTPV1U_ENB_END_MARKER_IND, MESSAGE_PRIORITY_MED, gtpv1u_enb_end_marker_ind_t, Gtpv1uEndMarkerInd) MESSAGE_DEF(GTPV1U_REQ, MESSAGE_PRIORITY_MED, Gtpv1uReq, gtpv1uReq) -MESSAGE_DEF(GTPV1U_GNB_TUNNEL_DATA_REQ, MESSAGE_PRIORITY_MED, gtpv1u_gnb_tunnel_data_req_t, NRGtpv1uTunnelDataReq) +MESSAGE_DEF(GTPV1U_GNB_TUNNEL_DATA_REQ, MESSAGE_PRIORITY_MED, gtpv1u_gnb_tunnel_data_req_t, NRGtpv1uTunnelDataReq) +MESSAGE_DEF(GTPV1U_DU_BUFFER_REPORT_REQ, MESSAGE_PRIORITY_MED, gtpv1u_DU_buffer_report_req_t, NRGtpv1uBufferReportReq) diff --git a/openair2/COMMON/gtpv1_u_messages_types.h b/openair2/COMMON/gtpv1_u_messages_types.h index 096f0f4697..4111b00024 100644 --- a/openair2/COMMON/gtpv1_u_messages_types.h +++ b/openair2/COMMON/gtpv1_u_messages_types.h @@ -39,6 +39,8 @@ #define GTPV1U_GNB_TUNNEL_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.NRGtpv1uTunnelDataReq +#define GTPV1U_DU_BUFFER_REPORT_REQ(mSGpTR) (mSGpTR)->ittiMsg.NRGtpv1uBufferReportReq + #define GTPV1U_ALL_TUNNELS_TEID (teid_t)0xFFFFFFFF typedef struct gtpv1u_enb_create_x2u_tunnel_req_s { @@ -213,4 +215,10 @@ typedef struct gtpv1u_gnb_tunnel_data_req_s { pdusessionid_t pdusession_id; } gtpv1u_gnb_tunnel_data_req_t; +typedef struct gtpv1u_DU_buffer_report_req_s { + uint32_t buffer_availability; + rnti_t rnti; + pdusessionid_t pdusession_id; +} gtpv1u_DU_buffer_report_req_t; + #endif /* GTPV1_U_MESSAGES_TYPES_H_ */ diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index f7a53c59a4..d7ff9492a5 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -3487,6 +3487,21 @@ static void rrc_DU_process_ue_context_modification_request(MessageDef *msg_p, co } else if(req->ReconfigComplOutcome == RRCreconf_success){ LOG_I(NR_RRC, "CU reporting RRC Reconfiguration success \n"); + if(ue_context_p->ue_context.DRB_configList!=NULL){ + LOG_I(NR_RRC, "Send first DDD buffer status reporting towards the CU through an ITTI message to gtp-u \n"); + uint8_t drb_id = ue_context_p->ue_context.DRB_configList->list.array[0]->drb_Identity; + rnti_t rnti = ue_context_p->ue_context.rnti; + LOG_I(NR_RRC, "Reported in DDD drb_id:%d, rnti:%d\n", drb_id, rnti); + MessageDef *msg = itti_alloc_new_message_sized(TASK_RRC_GNB, 0, GTPV1U_DU_BUFFER_REPORT_REQ, + sizeof(gtpv1u_gnb_tunnel_data_req_t)); + gtpv1u_DU_buffer_report_req_t *req=>PV1U_DU_BUFFER_REPORT_REQ(msg); + req->pdusession_id = drb_id; + req->rnti = rnti; + req->buffer_availability = 1000000; //Hardcoding to be removed and read the actual RLC buffer availability instead + extern instance_t DUuniqInstance; + itti_send_msg_to_task(TASK_GTPV1_U, DUuniqInstance, msg); + + } } /* Fill the UE context setup response ITTI message to send to F1AP */ diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index c79f7ecce2..20db486561 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -286,6 +286,74 @@ static void gtpv1uSend2(instance_t instance, gtpv1u_gnb_tunnel_data_req_t *req, buffer, length, seqNumFlag, npduNumFlag, false, tmp.seqNum, tmp.npduNum, 0, NULL, 0) ; } +static void fillDlDeliveryStatusReport(extensionHeader_t *extensionHeader, uint32_t RLC_buffer_availability, uint32_t NR_PDCP_PDU_SN){ + + extensionHeader->buffer[0] = (1+sizeof(DlDataDeliveryStatus_flagsT)+(NR_PDCP_PDU_SN>0?3:0)+(NR_PDCP_PDU_SN>0?1:0)+1)/4; + DlDataDeliveryStatus_flagsT DlDataDeliveryStatus; + DlDataDeliveryStatus.deliveredPdcpSn = 0; + DlDataDeliveryStatus.transmittedPdcpSn= NR_PDCP_PDU_SN>0?1:0; + DlDataDeliveryStatus.pduType = 1; + DlDataDeliveryStatus.drbBufferSize = htonl(RLC_buffer_availability); + memcpy(extensionHeader->buffer+1, &DlDataDeliveryStatus, sizeof(DlDataDeliveryStatus_flagsT)); + uint8_t offset = sizeof(DlDataDeliveryStatus_flagsT)+1; + + if(NR_PDCP_PDU_SN>0){ + extensionHeader->buffer[offset] = (NR_PDCP_PDU_SN >> 16) & 0xff; + extensionHeader->buffer[offset+1] = (NR_PDCP_PDU_SN >> 8) & 0xff; + extensionHeader->buffer[offset+2] = NR_PDCP_PDU_SN & 0xff; + LOG_D(GTPU, "Octets reporting NR_PDCP_PDU_SN, extensionHeader->buffer[offset]: %u, extensionHeader->buffer[offset+1]:%u, extensionHeader->buffer[offset+2]:%u \n", extensionHeader->buffer[offset], extensionHeader->buffer[offset+1],extensionHeader->buffer[offset+2]); + extensionHeader->buffer[offset+3] = 0x00; //Padding octet + offset = offset+3; + } + extensionHeader->buffer[offset] = 0x00; //No more extension headers + /*Total size of DDD_status PDU = size of mandatory part + + * 3 octets for highest transmitted/delivered PDCP SN + + * 1 octet for padding + 1 octet for next extension header type, + * according to TS 38.425: Fig. 5.5.2.2-1 and section 5.5.3.24*/ + extensionHeader->length = 1+sizeof(DlDataDeliveryStatus_flagsT)+ + (NR_PDCP_PDU_SN>0?3:0)+ + (NR_PDCP_PDU_SN>0?1:0)+1; +} + +static void gtpv1uSendDlDeliveryStatus(instance_t instance, gtpv1u_DU_buffer_report_req_t *req){ + rnti_t rnti=req->rnti; + int rab_id=req->pdusession_id; + pthread_mutex_lock(&globGtp.gtp_lock); + auto inst=&globGtp.instances[compatInst(instance)]; + auto ptrRnti=inst->ue2te_mapping.find(rnti); + + if ( ptrRnti==inst->ue2te_mapping.end() ) { + LOG_E(GTPU, "[%ld] GTP-U gtpv1uSend failed: while getting ue rnti %x in hashtable ue_mapping\n", instance, rnti); + pthread_mutex_unlock(&globGtp.gtp_lock); + return; + } + + map::iterator ptr2=ptrRnti->second.bearers.find(rab_id); + + if ( ptr2 == ptrRnti->second.bearers.end() ) { + LOG_D(GTPU,"GTP-U instance: %ld sending a packet to a non existant RNTI:RAB: %x/%x\n", instance, rnti, rab_id); + pthread_mutex_unlock(&globGtp.gtp_lock); + return; + } + + extensionHeader_t *extensionHeader; + extensionHeader = (extensionHeader_t *) calloc(1, sizeof(extensionHeader_t)); + fillDlDeliveryStatusReport(extensionHeader, req->buffer_availability,0); + + LOG_I(GTPU,"[%ld] GTP-U sending DL Data Delivery status to RNTI:RAB:teid %x/%x/%x, oldseq %d, oldnum %d\n", + instance, rnti, rab_id,ptr2->second.teid_outgoing, ptr2->second.seqNum,ptr2->second.npduNum ); + // copy to release the mutex + gtpv1u_bearer_t tmp=ptr2->second; + pthread_mutex_unlock(&globGtp.gtp_lock); + gtpv1uCreateAndSendMsg(compatInst(instance), + tmp.outgoing_ip_addr, + tmp.outgoing_port, + GTP_GPDU, + tmp.teid_outgoing, + NULL, 0, false, false, true, 0, 0, 0x84, extensionHeader->buffer, extensionHeader->length) ; + +} + static void gtpv1uEndTunnel(instance_t instance, gtpv1u_enb_tunnel_data_req_t *req) { rnti_t rnti=req->rnti; int rab_id=req->rab_id; @@ -1049,6 +1117,12 @@ void *gtpv1uTask(void *args) { } break; + case GTPV1U_DU_BUFFER_REPORT_REQ:{ + gtpv1uSendDlDeliveryStatus(compatInst(ITTI_MSG_DESTINATION_INSTANCE(message_p)), + >PV1U_DU_BUFFER_REPORT_REQ(message_p)); + } + break; + case TERMINATE_MESSAGE: break; From c7a54269de4dd75bf94765b2fe9f71fe48cd9ae2 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Wed, 30 Mar 2022 16:16:58 +0100 Subject: [PATCH 049/267] First version of rank indicator computation at UE --- openair1/PHY/INIT/nr_init_ue.c | 2 + openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 123 ++++++++++++++++++++++++++ openair1/PHY/defs_nr_common.h | 7 ++ 3 files changed, 132 insertions(+) diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 6d2655cb93..033ea2eec6 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -351,6 +351,7 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) } } ue->nr_csi_rs_info->noise_power = (uint32_t*)malloc16_clear(sizeof(uint32_t)); + ue->nr_csi_rs_info->rank_indicator = (uint8_t*)malloc16_clear(sizeof(uint8_t)); ue->nr_csi_rs_info->csi_rs_generated_signal = (int32_t **)malloc16(NR_MAX_NB_PORTS * sizeof(int32_t *) ); for (i=0; inr_csi_rs_info->csi_rs_generated_signal[i] = (int32_t *) malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t)); @@ -642,6 +643,7 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) free_and_zero(ue->nr_csi_rs_info->nr_gold_csi_rs[slot]); } free_and_zero(ue->nr_csi_rs_info->noise_power); + free_and_zero(ue->nr_csi_rs_info->rank_indicator); free_and_zero(ue->nr_csi_rs_info->nr_gold_csi_rs); free_and_zero(ue->nr_csi_rs_info->csi_rs_generated_signal); free_and_zero(ue->nr_csi_rs_info->csi_rs_received_signal); diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index fd33398f5c..138d5ff7ca 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -355,6 +355,114 @@ int nr_csi_rs_channel_estimation(PHY_VARS_NR_UE *ue, return 0; } +int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, + UE_nr_rxtx_proc_t *proc, + fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, + nr_csi_rs_info_t *nr_csi_rs_info, + int32_t ***csi_rs_estimated_channel_freq, + uint8_t *rank_indicator) { + + NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + int16_t cond_dB_threshold = 0; + int count=0; + *rank_indicator = 0; + + /* Example 2x2: Hh x H = + * | conjch00 conjch10 | x | ch00 ch01 | = | conjch00*ch00+conjch10*ch10 conjch00*ch01+conjch10*ch11 | + * | conjch01 conjch11 | | ch10 ch11 | | conjch01*ch00+conjch11*ch10 conjch01*ch01+conjch11*ch11 | + */ + + for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) { + + if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) { + continue; + } + uint16_t k = (frame_parms->first_carrier_offset + rb*NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size; + + // conjch x ch computation + for (int ant_rx_conjch = 0; ant_rx_conjch < frame_parms->nb_antennas_rx; ant_rx_conjch++) { + for(uint16_t port_tx_conjch = 0; port_tx_conjch < nr_csi_rs_info->N_ports; port_tx_conjch++) { + for (int ant_rx_ch = 0; ant_rx_ch < frame_parms->nb_antennas_rx; ant_rx_ch++) { + for(uint16_t port_tx_ch = 0; port_tx_ch < nr_csi_rs_info->N_ports; port_tx_ch++) { + nr_conjch0_mult_ch1(&csi_rs_estimated_channel_freq[ant_rx_conjch][port_tx_conjch][k], + &csi_rs_estimated_channel_freq[ant_rx_ch][port_tx_ch][k], + &nr_csi_rs_info->csi_rs_estimated_conjch_ch[ant_rx_conjch][port_tx_conjch][ant_rx_ch][port_tx_ch][k], + 1, + 0); + } + } + } + } + + // construct Hh x H elements + nr_construct_HhH_elements(0 < frame_parms->nb_antennas_rx && 0 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[0][0][0][0][k] : NULL, + 0 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[0][1][0][1][k] : NULL, + 1 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[1][1][1][1][k] : NULL, + 1 < frame_parms->nb_antennas_rx && 0 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[1][0][1][0][k] : NULL, + 2 < frame_parms->nb_antennas_rx && 0 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[2][0][2][0][k] : NULL, + 2 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[2][1][2][1][k] : NULL, + 3 < frame_parms->nb_antennas_rx && 0 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[3][0][3][0][k] : NULL, + 3 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[3][1][3][1][k] : NULL, + 0 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[0][0][0][1][k] : NULL, + 0 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[0][1][0][0][k] : NULL, + 1 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[1][0][1][1][k] : NULL, + 1 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[1][1][1][0][k] : NULL, + 2 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[2][0][2][1][k] : NULL, + 2 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[2][1][2][0][k] : NULL, + 3 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[3][0][3][1][k] : NULL, + 3 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[3][1][3][0][k] : NULL, + &nr_csi_rs_info->csi_rs_estimated_A_MF[0][0][k], + &nr_csi_rs_info->csi_rs_estimated_A_MF[0][1][k], + &nr_csi_rs_info->csi_rs_estimated_A_MF[1][0][k], + &nr_csi_rs_info->csi_rs_estimated_A_MF[1][1][k], + 1, + 0); + + // compute the determinant of A_MF (denominator) + nr_det_HhH(&nr_csi_rs_info->csi_rs_estimated_A_MF[0][0][k], + &nr_csi_rs_info->csi_rs_estimated_A_MF[0][1][k], + &nr_csi_rs_info->csi_rs_estimated_A_MF[1][0][k], + &nr_csi_rs_info->csi_rs_estimated_A_MF[1][1][k], + &nr_csi_rs_info->csi_rs_estimated_determ_fin[k], + 1, + 0, + 0); + + // compute the square of A_MF (numerator) + squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[0][0][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][0][k], 1); + squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[0][1][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][1][k], 1); + squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[1][0][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][0][k], 1); + squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[1][1][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][1][k], 1); + numer(&nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][0][k], + &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][1][k], + &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][0][k], + &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][1][k], + &nr_csi_rs_info->csi_rs_estimated_numer_fin[k], + 1); + + // compute the conditional number + for (int sc_idx=0; sc_idx < NR_NB_SC_PER_RB; sc_idx++) { + int8_t csi_rs_estimated_denum_db = dB_fixed(nr_csi_rs_info->csi_rs_estimated_determ_fin[k + sc_idx]); + int8_t csi_rs_estimated_numer_db = dB_fixed(nr_csi_rs_info->csi_rs_estimated_numer_fin[k + k]); + int8_t cond_db = csi_rs_estimated_numer_db - csi_rs_estimated_denum_db; + if (cond_db < cond_dB_threshold) { + count++; + } else { + count--; + } + } + } + + // conditional number is lower than cond_dB_threshold in half on more REs + if (count > 0) { + *rank_indicator = 1; + } + + LOG_I(NR_PHY, "count %i, RI = %i\n", *rank_indicator + 1); + + return 0; +} + int nr_ue_csi_im_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t gNB_id) { return 0; } @@ -406,5 +514,20 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t ue->nr_csi_rs_info->csi_rs_received_signal, ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, ue->nr_csi_rs_info->noise_power); + + if(ue->frame_parms.nb_antennas_rx == 1 || ue->nr_csi_rs_info->N_ports == 1) { + *ue->nr_csi_rs_info->rank_indicator = 0; + } else if(ue->frame_parms.nb_antennas_rx == 2 && ue->nr_csi_rs_info->N_ports == 2) { + nr_csi_rs_ri_estimation(ue, + proc, + csirs_config_pdu, + ue->nr_csi_rs_info, + ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, + ue->nr_csi_rs_info->rank_indicator); + } else { + LOG_D(NR_PHY, "Rank indicator computation is not implemented for %i x %i system\n", + ue->frame_parms.nb_antennas_rx, ue->nr_csi_rs_info->N_ports); + } + return 0; } diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 87eed8c4fc..1ed5eee07c 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -43,6 +43,7 @@ #define nr_slot_t lte_subframe_t #define MAX_NUM_SUBCARRIER_SPACING 5 +#define NR_MAX_OFDM_SYMBOL_SIZE 4096 #define NR_NB_SC_PER_RB 12 #define NR_NB_REG_PER_CCE 6 @@ -260,7 +261,13 @@ typedef struct { int32_t **csi_rs_received_signal; int32_t ***csi_rs_ls_estimated_channel; int32_t ***csi_rs_estimated_channel_freq; + int32_t csi_rs_estimated_conjch_ch[4][4][4][4][NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32))); + int32_t csi_rs_estimated_A_MF[2][2][NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32))); + int32_t csi_rs_estimated_A_MF_sq[2][2][NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32))); + int32_t csi_rs_estimated_determ_fin[NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32))); + int32_t csi_rs_estimated_numer_fin[NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32))); uint32_t *noise_power; + uint8_t *rank_indicator; } nr_csi_rs_info_t; typedef struct NR_DL_FRAME_PARMS NR_DL_FRAME_PARMS; From 38d0dca0bf2df12799db7adcd101d2fa7a4400d4 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Wed, 30 Mar 2022 17:00:25 +0100 Subject: [PATCH 050/267] Minor fixes --- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 138d5ff7ca..5465e22874 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -443,7 +443,7 @@ int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, // compute the conditional number for (int sc_idx=0; sc_idx < NR_NB_SC_PER_RB; sc_idx++) { int8_t csi_rs_estimated_denum_db = dB_fixed(nr_csi_rs_info->csi_rs_estimated_determ_fin[k + sc_idx]); - int8_t csi_rs_estimated_numer_db = dB_fixed(nr_csi_rs_info->csi_rs_estimated_numer_fin[k + k]); + int8_t csi_rs_estimated_numer_db = dB_fixed(nr_csi_rs_info->csi_rs_estimated_numer_fin[k + sc_idx]); int8_t cond_db = csi_rs_estimated_numer_db - csi_rs_estimated_denum_db; if (cond_db < cond_dB_threshold) { count++; @@ -458,7 +458,7 @@ int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, *rank_indicator = 1; } - LOG_I(NR_PHY, "count %i, RI = %i\n", *rank_indicator + 1); + LOG_I(NR_PHY, "RI = %i\n", *rank_indicator + 1); return 0; } From fba2df755796101683383f7e26ef51fae385075e Mon Sep 17 00:00:00 2001 From: rmagueta Date: Wed, 30 Mar 2022 19:27:24 +0100 Subject: [PATCH 051/267] Fix config files after merge --- targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf | 2 +- .../GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf | 2 +- .../GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf | 2 +- .../GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf | 2 +- .../GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.24PRB.usrpb210.conf | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf index c07a0db649..29acadb708 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf @@ -45,7 +45,7 @@ gNBs = remote_s_portc = 500; remote_s_portd = 2152; ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts = 1; + pdsch_AntennaPorts_N1 = 1; pusch_AntennaPorts = 1; min_rxtxtime = 6; sib1_tda = 0; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf index b5fe03c89b..e1c970aa62 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf @@ -33,7 +33,7 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts = 1; + pdsch_AntennaPorts_N1 = 1; pusch_AntennaPorts = 1; min_rxtxtime = 2; sib1_tda = 0; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf index cab801525b..4b3d886cdf 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf @@ -33,7 +33,7 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts = 1; + pdsch_AntennaPorts_N1 = 1; pusch_AntennaPorts = 1; min_rxtxtime = 6; sib1_tda = 0; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf index 1fe6b30bf2..69bd4f7a7c 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf @@ -33,7 +33,7 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts = 1; + pdsch_AntennaPorts_N1 = 1; pusch_AntennaPorts = 1; min_rxtxtime = 2; sib1_tda = 0; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.24PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.24PRB.usrpb210.conf index bd3076a014..1259951422 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.24PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.24PRB.usrpb210.conf @@ -33,7 +33,7 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts = 1; + pdsch_AntennaPorts_N1 = 1; pusch_AntennaPorts = 1; sib1_tda = 15; min_rxtxtime = 6; From da1e542a31669ef10d9fbc64d00c721384682617 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Wed, 30 Mar 2022 20:14:57 +0100 Subject: [PATCH 052/267] Fix dl_antenna_ports after merge --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index f90bdaa597..ba785f8cf2 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1008,12 +1008,13 @@ void fill_default_csi_MeasConfig(int uid, rrc_gNB_carrier_data_t *carrier) { int curr_bwp = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth,MAX_BWP_SIZE); + int dl_antenna_ports = carrier->pdsch_AntennaPorts.N1 * carrier->pdsch_AntennaPorts.N2 * carrier->pdsch_AntennaPorts.XP; setupRelease_csi_MeasConfig->present = NR_SetupRelease_CSI_MeasConfig_PR_setup; NR_CSI_MeasConfig_t *csi_MeasConfig = calloc(1,sizeof(*csi_MeasConfig)); setupRelease_csi_MeasConfig->choice.setup = csi_MeasConfig; - if (carrier->pdsch_AntennaPorts > 1) { + if (dl_antenna_ports > 1) { csi_MeasConfig->csi_IM_ResourceToAddModList = calloc(1,sizeof(*csi_MeasConfig->csi_IM_ResourceToAddModList)); NR_CSI_IM_Resource_t *imres0 = calloc(1,sizeof(*imres0)); imres0->csi_IM_ResourceId = 0; @@ -1044,7 +1045,7 @@ void fill_default_csi_MeasConfig(int uid, csi_MeasConfig->nzp_CSI_RS_ResourceSetToReleaseList = NULL; - config_csirs(scc, csi_MeasConfig, uid, carrier->pdsch_AntennaPorts, curr_bwp, carrier->do_CSIRS); + config_csirs(scc, csi_MeasConfig, uid, dl_antenna_ports, curr_bwp, carrier->do_CSIRS); csi_MeasConfig->csi_SSB_ResourceSetToAddModList = calloc(1,sizeof(*csi_MeasConfig->csi_SSB_ResourceSetToAddModList)); csi_MeasConfig->csi_SSB_ResourceSetToReleaseList = NULL; @@ -1107,7 +1108,7 @@ void fill_default_csi_MeasConfig(int uid, csires1->resourceType = NR_CSI_ResourceConfig__resourceType_periodic; ASN_SEQUENCE_ADD(&csi_MeasConfig->csi_ResourceConfigToAddModList->list,csires1); - if (carrier->pdsch_AntennaPorts > 1) { + if (dl_antenna_ports > 1) { NR_CSI_ResourceConfig_t *csires2 = calloc(1,sizeof(*csires2)); csires2->csi_ResourceConfigId=2; csires2->csi_RS_ResourceSetList.present = NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_csi_IM_ResourceSetList; @@ -1125,7 +1126,7 @@ void fill_default_csi_MeasConfig(int uid, pucchcsires1->pucch_Resource=1; csi_MeasConfig->csi_ReportConfigToAddModList = calloc(1,sizeof(*csi_MeasConfig->csi_ReportConfigToAddModList)); csi_MeasConfig->csi_ReportConfigToReleaseList = NULL; - if (carrier->pdsch_AntennaPorts > 1) { + if (dl_antenna_ports > 1) { LOG_I(NR_RRC,"Filling CSI Report Config for RI_PMI_CQI\n"); NR_CSI_ReportConfig_t *csirep1 = calloc(1,sizeof(*csirep1)); csirep1->reportConfigId=0; From bc2ea375c846f36410177f042b379f00b5503d9f Mon Sep 17 00:00:00 2001 From: rmagueta Date: Thu, 31 Mar 2022 20:30:00 +0100 Subject: [PATCH 053/267] Replace nr_construct_HhH_elements by nr_a_sum_b function in nr_csi_rs_ri_estimation --- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 74 +++++++---------- .../NR_UE_TRANSPORT/nr_dlsch_demodulation.c | 83 +++++++++++++++++++ .../NR_UE_TRANSPORT/nr_transport_proto_ue.h | 42 ++++++---- 3 files changed, 140 insertions(+), 59 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 5465e22874..6b7c045061 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -372,6 +372,12 @@ int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, * | conjch01 conjch11 | | ch10 ch11 | | conjch01*ch00+conjch11*ch10 conjch01*ch01+conjch11*ch11 | */ + for(uint16_t port_tx_conjch = 0; port_tx_conjch < nr_csi_rs_info->N_ports; port_tx_conjch++) { + for(uint16_t port_tx_ch = 0; port_tx_ch < nr_csi_rs_info->N_ports; port_tx_ch++) { + memset(nr_csi_rs_info->csi_rs_estimated_A_MF[port_tx_conjch][port_tx_ch],0,NR_MAX_OFDM_SYMBOL_SIZE*sizeof(int32_t)); + } + } + for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) { if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) { @@ -379,66 +385,48 @@ int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, } uint16_t k = (frame_parms->first_carrier_offset + rb*NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size; - // conjch x ch computation for (int ant_rx_conjch = 0; ant_rx_conjch < frame_parms->nb_antennas_rx; ant_rx_conjch++) { for(uint16_t port_tx_conjch = 0; port_tx_conjch < nr_csi_rs_info->N_ports; port_tx_conjch++) { for (int ant_rx_ch = 0; ant_rx_ch < frame_parms->nb_antennas_rx; ant_rx_ch++) { for(uint16_t port_tx_ch = 0; port_tx_ch < nr_csi_rs_info->N_ports; port_tx_ch++) { + + // conjch x ch computation nr_conjch0_mult_ch1(&csi_rs_estimated_channel_freq[ant_rx_conjch][port_tx_conjch][k], &csi_rs_estimated_channel_freq[ant_rx_ch][port_tx_ch][k], &nr_csi_rs_info->csi_rs_estimated_conjch_ch[ant_rx_conjch][port_tx_conjch][ant_rx_ch][port_tx_ch][k], 1, 0); + + // construct Hh x H elements + if(ant_rx_conjch == ant_rx_ch) { + nr_a_sum_b((__m128i *)&nr_csi_rs_info->csi_rs_estimated_A_MF[port_tx_conjch][port_tx_ch][k], + (__m128i *)&nr_csi_rs_info->csi_rs_estimated_conjch_ch[ant_rx_conjch][port_tx_conjch][ant_rx_ch][port_tx_ch][k], + 1); + } } } } } - // construct Hh x H elements - nr_construct_HhH_elements(0 < frame_parms->nb_antennas_rx && 0 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[0][0][0][0][k] : NULL, - 0 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[0][1][0][1][k] : NULL, - 1 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[1][1][1][1][k] : NULL, - 1 < frame_parms->nb_antennas_rx && 0 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[1][0][1][0][k] : NULL, - 2 < frame_parms->nb_antennas_rx && 0 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[2][0][2][0][k] : NULL, - 2 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[2][1][2][1][k] : NULL, - 3 < frame_parms->nb_antennas_rx && 0 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[3][0][3][0][k] : NULL, - 3 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[3][1][3][1][k] : NULL, - 0 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[0][0][0][1][k] : NULL, - 0 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[0][1][0][0][k] : NULL, - 1 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[1][0][1][1][k] : NULL, - 1 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[1][1][1][0][k] : NULL, - 2 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[2][0][2][1][k] : NULL, - 2 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[2][1][2][0][k] : NULL, - 3 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[3][0][3][1][k] : NULL, - 3 < frame_parms->nb_antennas_rx && 1 < nr_csi_rs_info->N_ports ? &nr_csi_rs_info->csi_rs_estimated_conjch_ch[3][1][3][0][k] : NULL, - &nr_csi_rs_info->csi_rs_estimated_A_MF[0][0][k], - &nr_csi_rs_info->csi_rs_estimated_A_MF[0][1][k], - &nr_csi_rs_info->csi_rs_estimated_A_MF[1][0][k], - &nr_csi_rs_info->csi_rs_estimated_A_MF[1][1][k], - 1, - 0); - // compute the determinant of A_MF (denominator) - nr_det_HhH(&nr_csi_rs_info->csi_rs_estimated_A_MF[0][0][k], - &nr_csi_rs_info->csi_rs_estimated_A_MF[0][1][k], - &nr_csi_rs_info->csi_rs_estimated_A_MF[1][0][k], - &nr_csi_rs_info->csi_rs_estimated_A_MF[1][1][k], - &nr_csi_rs_info->csi_rs_estimated_determ_fin[k], - 1, - 0, - 0); + nr_det_A_MF_2x2(&nr_csi_rs_info->csi_rs_estimated_A_MF[0][0][k], + &nr_csi_rs_info->csi_rs_estimated_A_MF[0][1][k], + &nr_csi_rs_info->csi_rs_estimated_A_MF[1][0][k], + &nr_csi_rs_info->csi_rs_estimated_A_MF[1][1][k], + &nr_csi_rs_info->csi_rs_estimated_determ_fin[k], + 1); // compute the square of A_MF (numerator) - squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[0][0][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][0][k], 1); - squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[0][1][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][1][k], 1); - squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[1][0][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][0][k], 1); - squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[1][1][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][1][k], 1); - numer(&nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][0][k], - &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][1][k], - &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][0][k], - &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][1][k], - &nr_csi_rs_info->csi_rs_estimated_numer_fin[k], - 1); + nr_squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[0][0][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][0][k], 1); + nr_squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[0][1][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][1][k], 1); + nr_squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[1][0][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][0][k], 1); + nr_squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[1][1][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][1][k], 1); + nr_numer_2x2(&nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][0][k], + &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][1][k], + &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][0][k], + &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][1][k], + &nr_csi_rs_info->csi_rs_estimated_numer_fin[k], + 1); // compute the conditional number for (int sc_idx=0; sc_idx < NR_NB_SC_PER_RB; sc_idx++) { diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index 69eccaf02e..07e7e5c3bb 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -1869,6 +1869,89 @@ void nr_dlsch_detection_mrc(int **rxdataF_comp, #endif } +void nr_det_A_MF_2x2(int32_t *a_mf_00, + int32_t *a_mf_01, + int32_t *a_mf_10, + int32_t *a_mf_11, + int32_t *det_fin, + unsigned short nb_rb) { + + int16_t nr_conjug2[8]__attribute__((aligned(16))) = {1,-1,1,-1,1,-1,1,-1} ; + + __m128i ad_re_128, bc_re_128, det_re_128; + + __m128i *a_mf_00_128 = (__m128i *)a_mf_00; + __m128i *a_mf_01_128 = (__m128i *)a_mf_01; + __m128i *a_mf_10_128 = (__m128i *)a_mf_10; + __m128i *a_mf_11_128 = (__m128i *)a_mf_11; + __m128i *det_fin_128 = (__m128i *)det_fin; + + for (int rb = 0; rb<3*nb_rb; rb++) { + + //complex multiplication (I_a+jQ_a)(I_d+jQ_d) = (I_aI_d - Q_aQ_d) + j(Q_aI_d + I_aQ_d) + //The imag part is often zero, we compute only the real part + ad_re_128 = _mm_sign_epi16(a_mf_00_128[0],*(__m128i*)&nr_conjug2[0]); + ad_re_128 = _mm_madd_epi16(ad_re_128,a_mf_11_128[0]); //Re: I_a0*I_d0 - Q_a1*Q_d1 + + //complex multiplication (I_b+jQ_b)(I_c+jQ_c) = (I_bI_c - Q_bQ_c) + j(Q_bI_c + I_bQ_c) + //The imag part is often zero, we compute only the real part + bc_re_128 = _mm_sign_epi16(a_mf_01_128[0],*(__m128i*)&nr_conjug2[0]); + bc_re_128 = _mm_madd_epi16(bc_re_128,a_mf_10_128[0]); //Re: I_b0*I_c0 - Q_b1*Q_c1 + + det_re_128 = _mm_sub_epi32(ad_re_128, bc_re_128); + + //det in Q30 format + det_fin_128[0] = _mm_abs_epi32(det_re_128); + + det_fin_128+=1; + a_mf_00_128+=1; + a_mf_01_128+=1; + a_mf_10_128+=1; + a_mf_11_128+=1; + } + _mm_empty(); + _m_empty(); +} + +void nr_squared_matrix_element(int32_t *a, + int32_t *a_sq, + unsigned short nb_rb) { + __m128i *a_128 = (__m128i *)a; + __m128i *a_sq_128 = (__m128i *)a_sq; + for (int rb=0; rb<3*nb_rb; rb++) { + a_sq_128[0] = _mm_madd_epi16(a_128[0], a_128[0]); + a_sq_128+=1; + a_128+=1; + } + _mm_empty(); + _m_empty(); +} + +void nr_numer_2x2(int32_t *a_00_sq, + int32_t *a_01_sq, + int32_t *a_10_sq, + int32_t *a_11_sq, + int32_t *num_fin, + unsigned short nb_rb) { + __m128i *a_00_sq_128 = (__m128i *)a_00_sq; + __m128i *a_01_sq_128 = (__m128i *)a_01_sq; + __m128i *a_10_sq_128 = (__m128i *)a_10_sq; + __m128i *a_11_sq_128 = (__m128i *)a_11_sq; + __m128i *num_fin_128 = (__m128i *)num_fin; + for (int rb=0; rb<3*nb_rb; rb++) { + __m128i sq_a_plus_sq_d_128 = _mm_add_epi32(a_00_sq_128[0], a_11_sq_128[0]); + __m128i sq_b_plus_sq_c_128 = _mm_add_epi32(a_01_sq_128[0], a_10_sq_128[0]); + num_fin_128[0] = _mm_add_epi32(sq_a_plus_sq_d_128, sq_b_plus_sq_c_128); + num_fin_128+=1; + a_00_sq_128+=1; + a_01_sq_128+=1; + a_10_sq_128+=1; + a_11_sq_128+=1; + } + _mm_empty(); + _m_empty(); +} + /* Zero Forcing Rx function: nr_a_sum_b() * Compute the complex addition x=x+y * diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index e1df279abf..c2bf41c923 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -851,10 +851,6 @@ void construct_HhH_elements(int *ch0conj_ch0, int32_t *after_mf_11, unsigned short nb_rb); -void squared_matrix_element(int32_t *Hh_h_00, - int32_t *Hh_h_00_sq, - unsigned short nb_rb); - void dlsch_channel_level_TM34_meas(int *ch00, int *ch01, int *ch10, @@ -881,19 +877,33 @@ void nr_dlsch_detection_mrc(int **rxdataF_comp, unsigned short nb_rb, int length); -void det_HhH(int32_t *after_mf_00, - int32_t *after_mf_01, - int32_t *after_mf_10, - int32_t *after_mf_11, - int32_t *det_fin_128, - unsigned short nb_rb); +void nr_conjch0_mult_ch1(int *ch0, + int *ch1, + int32_t *ch0conj_ch1, + unsigned short nb_rb, + unsigned char output_shift0); -void numer(int32_t *Hh_h_00_sq, - int32_t *Hh_h_01_sq, - int32_t *Hh_h_10_sq, - int32_t *Hh_h_11_sq, - int32_t *num_fin, - unsigned short nb_rb); +void nr_a_sum_b(__m128i *input_x, + __m128i *input_y, + unsigned short nb_rb); + +void nr_det_A_MF_2x2(int32_t *a_mf_00, + int32_t *a_mf_01, + int32_t *a_mf_10, + int32_t *a_mf_11, + int32_t *det_fin, + unsigned short nb_rb); + +void nr_squared_matrix_element(int32_t *a, + int32_t *a_sq, + unsigned short nb_rb); + +void nr_numer_2x2(int32_t *a_00_sq, + int32_t *a_01_sq, + int32_t *a_10_sq, + int32_t *a_11_sq, + int32_t *num_fin, + unsigned short nb_rb); uint8_t rank_estimation_tm3_tm4(int *dl_ch_estimates_00, int *dl_ch_estimates_01, From e628c8c2c41a8296f16f0af2090db3570aafc3c0 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Fri, 1 Apr 2022 20:13:06 +0100 Subject: [PATCH 054/267] Fix build after merge --- openair2/GNB_APP/gnb_paramdef.h | 2 +- openair2/RRC/NR/MESSAGES/asn1_msg.c | 10 +++++----- openair2/RRC/NR/nr_rrc_config.c | 3 ++- openair2/RRC/NR/nr_rrc_config.h | 3 ++- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index 1503342f0f..3458be4f45 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -160,7 +160,7 @@ typedef enum { {GNB_CONFIG_STRING_NRCELLID, NULL, 0, u64ptr:NULL, defint64val:1, TYPE_UINT64, 0}, \ {GNB_CONFIG_STRING_MINRXTXTIME, NULL, 0, iptr:NULL, defintval:2, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_ULPRBBLACKLIST, NULL, 0, strptr:NULL, defstrval:"", TYPE_STRING, 0}, \ -{GNB_CONFIG_STRING_UMONDEFAULTDRB, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0} \ +{GNB_CONFIG_STRING_UMONDEFAULTDRB, NULL, 0, uptr:NULL, defuintval:0, TYPE_UINT, 0}, \ {GNB_CONFIG_STRING_FORCE256QAMOFF, GNB_CONFIG_HLP_FORCE256QAMOFF, PARAMFLAG_BOOL, iptr:NULL, defintval:0, TYPE_INT, 0} \ } diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index c3a1a49084..562eaad64d 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1310,7 +1310,7 @@ void fill_initial_SpCellConfig(int uid, pucchspatial->servingCellId = NULL; // TODO: Remove this if - if(!carrier->do_CSIRS) { + if(!configuration->do_CSIRS) { pucchspatial->referenceSignal.present = NR_PUCCH_SpatialRelationInfo__referenceSignal_PR_ssb_Index; pucchspatial->referenceSignal.choice.ssb_Index = 0; } @@ -1609,7 +1609,7 @@ void fill_initial_SpCellConfig(int uid, SpCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup = pdsch_servingcellconfig; // TODO: Delete this code and calls in update_cellGroupConfig() - if (carrier->do_CSIRS) { + if (configuration->do_CSIRS) { struct NR_PUCCH_Config__spatialRelationInfoToAddModList *spatialRelationInfoToAddModList = calloc(1,sizeof(*spatialRelationInfoToAddModList)); NR_PUCCH_SpatialRelationInfo_t *pucchspatial = calloc(1,sizeof(*pucchspatial)); pucchspatial->pucch_SpatialRelationInfoId = 1; @@ -1624,7 +1624,7 @@ void fill_initial_SpCellConfig(int uid, if(!SpCellConfig->spCellConfigDedicated->csi_MeasConfig) { SpCellConfig->spCellConfigDedicated->csi_MeasConfig=calloc(1,sizeof(*SpCellConfig->spCellConfigDedicated->csi_MeasConfig)); } - fill_default_csi_MeasConfig(uid, SpCellConfig->spCellConfigDedicated->csi_MeasConfig, scc, carrier); + fill_default_csi_MeasConfig(uid, SpCellConfig->spCellConfigDedicated->csi_MeasConfig, scc, configuration); } pdsch_servingcellconfig->codeBlockGroupTransmission = NULL; @@ -1758,14 +1758,14 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, // Set DL MCS table NR_BWP_DownlinkDedicated_t *bwp_Dedicated = SpCellConfig->spCellConfigDedicated->initialDownlinkBWP; set_dl_mcs_table(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.subcarrierSpacing, - configuration->force_256qam_off ? NULL : uecap, bwp_Dedicated, scc); + configuration->force_256qam_off ? NULL : uecap, SpCellConfig, bwp_Dedicated, scc); struct NR_ServingCellConfig__downlinkBWP_ToAddModList *DL_BWP_list = SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList; if (DL_BWP_list) { for (int i=0; ilist.count; i++){ NR_BWP_Downlink_t *bwp = DL_BWP_list->list.array[i]; int scs = bwp->bwp_Common->genericParameters.subcarrierSpacing; - set_dl_mcs_table(scs, configuration->force_256qam_off ? NULL : uecap, bwp->bwp_Dedicated, carrier->servingcellconfigcommon); + set_dl_mcs_table(scs, configuration->force_256qam_off ? NULL : uecap, SpCellConfig, bwp->bwp_Dedicated, carrier->servingcellconfigcommon); } } } diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 6025105350..4e373900bd 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -304,7 +304,8 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay){ } } -void set_dl_mcs_table(int scs, NR_UE_NR_Capability_t *cap, +void set_dl_mcs_table(int scs, + NR_UE_NR_Capability_t *cap, NR_SpCellConfig_t *SpCellConfig, NR_BWP_DownlinkDedicated_t *bwp_Dedicated, NR_ServingCellConfigCommon_t *scc) { diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index 63df31d1a7..cce03ed02a 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -119,7 +119,8 @@ void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, int num_dl_antenna_ports, int curr_bwp, int do_csirs); -void set_dl_mcs_table(int scs, NR_UE_NR_Capability_t *cap, +void set_dl_mcs_table(int scs, + NR_UE_NR_Capability_t *cap, NR_SpCellConfig_t *SpCellConfig, NR_BWP_DownlinkDedicated_t *bwp_Dedicated, NR_ServingCellConfigCommon_t *scc); From 4c17c9c62a834ae6795ad5c013ff9dee654153cb Mon Sep 17 00:00:00 2001 From: francescomani Date: Sun, 3 Apr 2022 18:15:17 +0200 Subject: [PATCH 055/267] change SR slot in FDD to avoid assertion --- openair2/RRC/NR/nr_rrc_config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 98004f9add..9ee9d2a5bc 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -294,7 +294,7 @@ void set_SR_periodandoffset(NR_SchedulingRequestResourceConfig_t *schedulingRequ NR_ServingCellConfigCommon_t *scc) { const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; - int sr_slot = 0; + int sr_slot = 1; // in FDD SR in slot 1 if(tdd) sr_slot = tdd->nrofDownlinkSlots; // SR in the first uplink slot From c37e0af9b0aa8878fc8a9efb9bd2f1614ea28958 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Mon, 4 Apr 2022 14:42:37 +0100 Subject: [PATCH 056/267] Change LOG levels --- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 30 ++++++++++++++------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 6b7c045061..6e84f80894 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -364,9 +364,18 @@ int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; int16_t cond_dB_threshold = 0; - int count=0; + int count = 0; *rank_indicator = 0; + if (ue->frame_parms.nb_antennas_rx == 1 || ue->nr_csi_rs_info->N_ports == 1) { + LOG_I(NR_PHY, "RI = %i\n", *rank_indicator + 1); + return 0; + } else if( !(ue->frame_parms.nb_antennas_rx == 2 && ue->nr_csi_rs_info->N_ports == 2) ) { + LOG_W(NR_PHY, "Rank indicator computation is not implemented for %i x %i system\n", + ue->frame_parms.nb_antennas_rx, ue->nr_csi_rs_info->N_ports); + return -1; + } + /* Example 2x2: Hh x H = * | conjch00 conjch10 | x | ch00 ch01 | = | conjch00*ch00+conjch10*ch10 conjch00*ch01+conjch10*ch11 | * | conjch01 conjch11 | | ch10 ch11 | | conjch01*ch00+conjch11*ch10 conjch01*ch01+conjch11*ch11 | @@ -503,19 +512,12 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, ue->nr_csi_rs_info->noise_power); - if(ue->frame_parms.nb_antennas_rx == 1 || ue->nr_csi_rs_info->N_ports == 1) { - *ue->nr_csi_rs_info->rank_indicator = 0; - } else if(ue->frame_parms.nb_antennas_rx == 2 && ue->nr_csi_rs_info->N_ports == 2) { - nr_csi_rs_ri_estimation(ue, - proc, - csirs_config_pdu, - ue->nr_csi_rs_info, - ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, - ue->nr_csi_rs_info->rank_indicator); - } else { - LOG_D(NR_PHY, "Rank indicator computation is not implemented for %i x %i system\n", - ue->frame_parms.nb_antennas_rx, ue->nr_csi_rs_info->N_ports); - } + nr_csi_rs_ri_estimation(ue, + proc, + csirs_config_pdu, + ue->nr_csi_rs_info, + ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, + ue->nr_csi_rs_info->rank_indicator); return 0; } From 03f7bd34686cb72d7299938a89750fae20859c6b Mon Sep 17 00:00:00 2001 From: rmagueta Date: Mon, 4 Apr 2022 14:44:22 +0100 Subject: [PATCH 057/267] Remove unused input in nr_csi_rs_ri_estimation --- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 6e84f80894..215f6d3d6a 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -356,7 +356,6 @@ int nr_csi_rs_channel_estimation(PHY_VARS_NR_UE *ue, } int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, - UE_nr_rxtx_proc_t *proc, fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, nr_csi_rs_info_t *nr_csi_rs_info, int32_t ***csi_rs_estimated_channel_freq, @@ -513,7 +512,6 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t ue->nr_csi_rs_info->noise_power); nr_csi_rs_ri_estimation(ue, - proc, csirs_config_pdu, ue->nr_csi_rs_info, ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, From f12c6ea65b8aa43d21dc8506f2c564a98af8cb74 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Mon, 4 Apr 2022 15:55:16 +0100 Subject: [PATCH 058/267] Add log2_maxh for nr_conjch0_mult_ch1 in nr_csi_rs_ri_estimation --- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 5 ++++- openair1/PHY/defs_nr_common.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 215f6d3d6a..4d34cf7d8c 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -205,6 +205,7 @@ int nr_csi_rs_channel_estimation(PHY_VARS_NR_UE *ue, NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; int dataF_offset = proc->nr_slot_rx*ue->frame_parms.samples_per_slot_wCP; *noise_power = 0; + int maxh = 0; for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) { @@ -318,6 +319,7 @@ int nr_csi_rs_channel_estimation(PHY_VARS_NR_UE *ue, int16_t *csi_rs_estimated_channel16 = (int16_t *)&csi_rs_estimated_channel_freq[ant_rx][port_tx][k]; noise_real[ant_rx][port_tx][rb-csirs_config_pdu->start_rb] = abs(csi_rs_ls_estimated_channel[0]-csi_rs_estimated_channel16[0]); noise_imag[ant_rx][port_tx][rb-csirs_config_pdu->start_rb] = abs(csi_rs_ls_estimated_channel[1]-csi_rs_estimated_channel16[1]); + maxh = cmax3(maxh, abs(csi_rs_estimated_channel16[0]), abs(csi_rs_estimated_channel16[1])); } } for(uint16_t port_tx = 0; port_txN_ports; port_tx++) { @@ -347,6 +349,7 @@ int nr_csi_rs_channel_estimation(PHY_VARS_NR_UE *ue, } *noise_power /= (frame_parms->nb_antennas_rx*nr_csi_rs_info->N_ports); + nr_csi_rs_info->log2_maxh = log2_approx(maxh-1); #ifdef NR_CSIRS_DEBUG LOG_I(NR_PHY, "Noise power estimation based on CSI-RS: %i\n", *noise_power); @@ -403,7 +406,7 @@ int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, &csi_rs_estimated_channel_freq[ant_rx_ch][port_tx_ch][k], &nr_csi_rs_info->csi_rs_estimated_conjch_ch[ant_rx_conjch][port_tx_conjch][ant_rx_ch][port_tx_ch][k], 1, - 0); + nr_csi_rs_info->log2_maxh); // construct Hh x H elements if(ant_rx_conjch == ant_rx_ch) { diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 658a3e20cf..7d4557e340 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -261,6 +261,7 @@ typedef struct { int32_t **csi_rs_received_signal; int32_t ***csi_rs_ls_estimated_channel; int32_t ***csi_rs_estimated_channel_freq; + int16_t log2_maxh; int32_t csi_rs_estimated_conjch_ch[4][4][4][4][NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32))); int32_t csi_rs_estimated_A_MF[2][2][NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32))); int32_t csi_rs_estimated_A_MF_sq[2][2][NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32))); From 4254d59a960e9db5e07de60b62076de94bd8159b Mon Sep 17 00:00:00 2001 From: rmagueta Date: Mon, 4 Apr 2022 20:13:33 +0100 Subject: [PATCH 059/267] Create nr_csi_rs_pmi_estimation function for PMI computation (still almost empty) --- openair1/PHY/INIT/nr_init_ue.c | 1 + openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 36 +++++++++++++++++++++++++++ openair1/PHY/defs_nr_common.h | 1 + 3 files changed, 38 insertions(+) diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 59c526b818..07988f9665 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -347,6 +347,7 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) } ue->nr_csi_rs_info->noise_power = (uint32_t*)malloc16_clear(sizeof(uint32_t)); ue->nr_csi_rs_info->rank_indicator = (uint8_t*)malloc16_clear(sizeof(uint8_t)); + ue->nr_csi_rs_info->pmi = (uint8_t*)malloc16_clear(sizeof(uint8_t)); ue->nr_csi_rs_info->csi_rs_generated_signal = (int32_t **)malloc16(NR_MAX_NB_PORTS * sizeof(int32_t *) ); for (i=0; inr_csi_rs_info->csi_rs_generated_signal[i] = (int32_t *) malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t)); diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 4d34cf7d8c..f5ecc874eb 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -462,6 +462,35 @@ int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, return 0; } +int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, + fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, + nr_csi_rs_info_t *nr_csi_rs_info, + int32_t ***csi_rs_estimated_channel_freq, + uint8_t rank_indicator, + uint8_t *pmi) { + + // TS 38.214: For 2 antenna ports {3000, 3001} and the UE configured with higher layer parameter codebookType set to + // 'typeISinglePanel' each PMI value corresponds to a codebook index given in Table 5.2.2.2.1-1. + // The first column is applicable if the UE is reporting a Rank = 1, whereas the second column is applicable if the + // UE is reporting a Rank = 2. + + *pmi = 0; + + if(ue->nr_csi_rs_info->N_ports == 1) { + return 0; + } + + if(rank_indicator == 0) { + + } else if(rank_indicator == 1) { + + } else { + LOG_W(NR_PHY, "PMI computation is not implemented for rank indicator %i\n", rank_indicator); + } + + return 0; +} + int nr_ue_csi_im_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t gNB_id) { return 0; } @@ -520,5 +549,12 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, ue->nr_csi_rs_info->rank_indicator); + nr_csi_rs_pmi_estimation(ue, + csirs_config_pdu, + ue->nr_csi_rs_info, + ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, + *ue->nr_csi_rs_info->rank_indicator, + ue->nr_csi_rs_info->pmi); + return 0; } diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 7d4557e340..6ae2608a16 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -269,6 +269,7 @@ typedef struct { int32_t csi_rs_estimated_numer_fin[NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32))); uint32_t *noise_power; uint8_t *rank_indicator; + uint8_t *pmi; } nr_csi_rs_info_t; typedef struct NR_DL_FRAME_PARMS NR_DL_FRAME_PARMS; From 886b580fac06f7e3630f9f7dfcbf16a7de336720 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Tue, 5 Apr 2022 19:56:13 +0100 Subject: [PATCH 060/267] PMI computation for rank=1 case --- openair1/PHY/INIT/nr_init_ue.c | 3 +- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 59 ++++++++++++++++++++++++--- openair1/PHY/defs_nr_common.h | 3 +- 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 07988f9665..e5402c1c04 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -347,7 +347,8 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) } ue->nr_csi_rs_info->noise_power = (uint32_t*)malloc16_clear(sizeof(uint32_t)); ue->nr_csi_rs_info->rank_indicator = (uint8_t*)malloc16_clear(sizeof(uint8_t)); - ue->nr_csi_rs_info->pmi = (uint8_t*)malloc16_clear(sizeof(uint8_t)); + ue->nr_csi_rs_info->i1 = (uint8_t*)malloc16_clear(3*sizeof(uint8_t)); + ue->nr_csi_rs_info->i2 = (uint8_t*)malloc16_clear(sizeof(uint8_t)); ue->nr_csi_rs_info->csi_rs_generated_signal = (int32_t **)malloc16(NR_MAX_NB_PORTS * sizeof(int32_t *) ); for (i=0; inr_csi_rs_info->csi_rs_generated_signal[i] = (int32_t *) malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t)); diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index f5ecc874eb..09b32f1a33 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -457,8 +457,6 @@ int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, *rank_indicator = 1; } - LOG_I(NR_PHY, "RI = %i\n", *rank_indicator + 1); - return 0; } @@ -467,21 +465,64 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, nr_csi_rs_info_t *nr_csi_rs_info, int32_t ***csi_rs_estimated_channel_freq, uint8_t rank_indicator, - uint8_t *pmi) { + uint8_t *i1, + uint8_t *i2) { + + NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + i1[0] = 1; + i1[1] = 1; + i1[2] = 1; + *i2 = 0; // TS 38.214: For 2 antenna ports {3000, 3001} and the UE configured with higher layer parameter codebookType set to // 'typeISinglePanel' each PMI value corresponds to a codebook index given in Table 5.2.2.2.1-1. // The first column is applicable if the UE is reporting a Rank = 1, whereas the second column is applicable if the // UE is reporting a Rank = 2. - *pmi = 0; - if(ue->nr_csi_rs_info->N_ports == 1) { return 0; } if(rank_indicator == 0) { + uint32_t metric[4] = {0}; + uint16_t shift = nr_csi_rs_info->log2_maxh + log2_approx(frame_parms->nb_antennas_rx) + log2_approx(csirs_config_pdu->nr_of_rbs) - 1; + + for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) { + + if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) { + continue; + } + uint16_t k = (frame_parms->first_carrier_offset + rb * NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size; + + for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) { + int16_t *csi_rs_estimated_channel_p0 = (int16_t *) &csi_rs_estimated_channel_freq[ant_rx][0][k]; + int16_t *csi_rs_estimated_channel_p1 = (int16_t *) &csi_rs_estimated_channel_freq[ant_rx][1][k]; + + // H_p0 + 1*H_p1 = (H_p0_re + H_p1_re) + 1j*(H_p0_im + H_p1_im) + metric[0] += ((csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[0]) + + (csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[1]))>>shift; + + // H_p0 + 1j*H_p1 = (H_p0_re - H_p1_im) + 1j*(H_p0_im + H_p1_re) + metric[1] += ((csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[1]) + + (csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[0]))>>shift; + + // H_p0 - 1*H_p1 = (H_p0_re - H_p1_re) + 1j*(H_p0_im - H_p1_im) + metric[2] += ((csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[0]) + + (csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[1]))>>shift; + + // H_p0 - 1j*H_p1 = (H_p0_re + H_p1_im) + 1j*(H_p0_im - H_p1_re) + metric[3] += ((csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[1]) + + (csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[0]))>>shift; + } + } + + for(int tested_i2 = 0; tested_i2 < 4; tested_i2++) { + if(metric[tested_i2] > metric[*i2]) { + *i2 = tested_i2; + } + } + } else if(rank_indicator == 1) { } else { @@ -554,7 +595,13 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t ue->nr_csi_rs_info, ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, *ue->nr_csi_rs_info->rank_indicator, - ue->nr_csi_rs_info->pmi); + ue->nr_csi_rs_info->i1, + ue->nr_csi_rs_info->i2); + + LOG_I(NR_PHY, "RI = %i, i1 = [%i %i %i], i2 = %i\n", + *ue->nr_csi_rs_info->rank_indicator + 1, + ue->nr_csi_rs_info->i1[0], ue->nr_csi_rs_info->i1[1], ue->nr_csi_rs_info->i1[2], + *ue->nr_csi_rs_info->i2); return 0; } diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 6ae2608a16..c1157e452f 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -269,7 +269,8 @@ typedef struct { int32_t csi_rs_estimated_numer_fin[NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32))); uint32_t *noise_power; uint8_t *rank_indicator; - uint8_t *pmi; + uint8_t *i1; + uint8_t *i2; } nr_csi_rs_info_t; typedef struct NR_DL_FRAME_PARMS NR_DL_FRAME_PARMS; From 0eb2acb00bea1f3be14b3cc0f4696b66ac36c504 Mon Sep 17 00:00:00 2001 From: matzakos Date: Wed, 6 Apr 2022 10:43:09 +0200 Subject: [PATCH 061/267] F1 code cleanup before merge -Remove commented out code, debug logs, some hardcodings, fix indentation --- openair2/COMMON/f1ap_messages_types.h | 38 +- openair2/F1AP/f1ap_cu_ue_context_management.c | 571 +++++++++--------- openair2/F1AP/f1ap_du_interface_management.c | 28 +- openair2/F1AP/f1ap_du_ue_context_management.c | 129 ++-- openair2/GNB_APP/gnb_config.c | 7 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 4 - openair2/RRC/NR/rrc_gNB.c | 89 +-- openair2/RRC/NR/rrc_gNB_NGAP.c | 47 +- openair2/RRC/NR_UE/rrc_UE.c | 4 +- openair3/ocp-gtpu/gtp_itf.cpp | 6 - 10 files changed, 416 insertions(+), 507 deletions(-) diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index 409e4a912e..4a0d3eb411 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -352,6 +352,15 @@ typedef struct cu_to_du_rrc_information_s { uint8_t measConfig_length; }cu_to_du_rrc_information_t; +typedef struct du_to_du_rrc_information_s { + uint8_t * cellGroupConfig; + uint8_t cellGroupConfig_length; + uint8_t * measGapConfig; + uint8_t measGapConfig_length; + uint8_t * requestedP_MaxFR1; + uint8_t requestedP_MaxFR1_length; +}du_to_cu_rrc_information_t; + typedef enum QoS_information_e { NG_RAN_QoS = 0, EUTRAN_QoS = 1, @@ -377,10 +386,13 @@ typedef struct f1ap_ue_context_setup_s { uint32_t servCellId; cu_to_du_rrc_information_t *cu_to_du_rrc_information; uint8_t cu_to_du_rrc_information_length; - uint8_t *du_to_cu_rrc_information; - uint8_t du_to_cu_rrc_information_length; - f1ap_drb_to_be_setup_t *drbs_to_be_setup; // BK: need to replace by s1ap_initial_context_setup_req - uint8_t drbs_to_be_setup_length; // BK: need to replace by s1ap_initial_context_setup_req + //uint8_t *du_to_cu_rrc_information; + du_to_cu_rrc_information_t *du_to_cu_rrc_information; + uint32_t du_to_cu_rrc_information_length; + f1ap_drb_to_be_setup_t *drbs_to_be_setup; + uint8_t drbs_to_be_setup_length; + f1ap_drb_to_be_setup_t *drbs_to_be_modified; + uint8_t drbs_to_be_modified_length; QoS_information_t QoS_information_type; uint8_t drbs_failed_to_be_setup_length; f1ap_rb_failed_to_be_setup_t *drbs_failed_to_be_setup; @@ -388,29 +400,11 @@ typedef struct f1ap_ue_context_setup_s { uint8_t srbs_to_be_setup_length; uint8_t srbs_failed_to_be_setup_length; f1ap_rb_failed_to_be_setup_t *srbs_failed_to_be_setup; - s1ap_initial_context_setup_req_t *s1ap_initial_context_setup_req; ReconfigurationCompl_t ReconfigComplOutcome; - // coniatner for the rrc_eNB_generate_SecurityModeCommand message uint8_t *rrc_container; int rrc_container_length; } f1ap_ue_context_setup_t; -typedef struct f1ap_ue_context_setup_resp_s { - uint32_t gNB_CU_ue_id; // BK: need to replace by use from rnti - uint32_t gNB_DU_ue_id; - uint16_t rnti; - uint8_t du_to_cu_rrc_information[1024 /*Arbitrarily big enough*/]; - uint32_t du_to_cu_rrc_information_length; - f1ap_drb_to_be_setup_t *drbs_setup; // BK: need to replace by s1ap_initial_context_setup_req - uint8_t drbs_setup_length; // BK: need to replace by s1ap_initial_context_setup_req - f1ap_srb_to_be_setup_t *srbs_setup; - uint8_t srbs_setup_length; - uint8_t srbs_failed_to_be_setup_length; - f1ap_rb_failed_to_be_setup_t *srbs_failed_to_be_setup; - uint8_t drbs_failed_to_be_setup_length; - f1ap_rb_failed_to_be_setup_t *drbs_failed_to_be_setup; -} f1ap_ue_context_setup_resp_t; - typedef enum F1ap_Cause_e { F1AP_CAUSE_NOTHING, /* No components present */ F1AP_CAUSE_RADIO_NETWORK, diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index 037be0c8d4..08d0ff042e 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -135,23 +135,23 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(instance_t instance, /* optional */ /* 6.1 cG_ConfigInfo */ if(f1ap_ue_context_setup_req->cu_to_du_rrc_information->cG_ConfigInfo!=NULL){ - const char cG_ConfigInfoStr[]="asdsa1d32sa1d31asd31as"; asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.cG_ConfigInfo, cG_ConfigInfo); - OCTET_STRING_fromBuf(cG_ConfigInfo, cG_ConfigInfoStr, strlen(cG_ConfigInfoStr)) ; + OCTET_STRING_fromBuf(cG_ConfigInfo, (const char *)f1ap_ue_context_setup_req->cu_to_du_rrc_information->cG_ConfigInfo, + f1ap_ue_context_setup_req->cu_to_du_rrc_information->cG_ConfigInfo_length); } /* optional */ /* 6.2 uE_CapabilityRAT_ContainerList */ if(f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList!=NULL){ asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList, uE_CapabilityRAT_ContainerList ); OCTET_STRING_fromBuf(uE_CapabilityRAT_ContainerList, (const char *)f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, - f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length); + f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length); } /* optional */ /* 6.3 measConfig */ if(f1ap_ue_context_setup_req->cu_to_du_rrc_information->measConfig!=NULL){ - const char measConfigStr[]="asdsa1d32sa1d31asd31as"; asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.measConfig, measConfig); - OCTET_STRING_fromBuf(measConfig, measConfigStr, strlen(measConfigStr)) ; + OCTET_STRING_fromBuf(measConfig, (const char*)f1ap_ue_context_setup_req->cu_to_du_rrc_information->measConfig, + f1ap_ue_context_setup_req->cu_to_du_rrc_information->measConfig_length); } } @@ -248,201 +248,95 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(instance_t instance, /* mandatory */ /* c11. SRBs_ToBeSetup_List */ if(f1ap_ue_context_setup_req->srbs_to_be_setup_length > 0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie11); - ie11->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetup_List; - ie11->criticality = F1AP_Criticality_reject; // ? - ie11->value.present = F1AP_UEContextSetupRequestIEs__value_PR_SRBs_ToBeSetup_List; + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie11); + ie11->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetup_List; + ie11->criticality = F1AP_Criticality_reject; // ? + ie11->value.present = F1AP_UEContextSetupRequestIEs__value_PR_SRBs_ToBeSetup_List; - for (int i=0; isrbs_to_be_setup_length; i++) { - // - asn1cSequenceAdd(ie11->value.choice.SRBs_ToBeSetup_List.list, F1AP_SRBs_ToBeSetup_ItemIEs_t, srbs_toBeSetup_item_ies); - srbs_toBeSetup_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetup_Item; // 73 - srbs_toBeSetup_item_ies->criticality = F1AP_Criticality_ignore; - srbs_toBeSetup_item_ies->value.present = F1AP_SRBs_ToBeSetup_ItemIEs__value_PR_SRBs_ToBeSetup_Item; - /* 11.1 SRBs_ToBeSetup_Item */ - F1AP_SRBs_ToBeSetup_Item_t *srbs_toBeSetup_item=&srbs_toBeSetup_item_ies->value.choice.SRBs_ToBeSetup_Item; - /* 11.1.1 sRBID */ - srbs_toBeSetup_item->sRBID = f1ap_ue_context_setup_req->srbs_to_be_setup[i].srb_id; - /* OPTIONAL */ - /* 11.1.2 duplicationIndication */ - //if (0) { - asn1cCallocOne(srbs_toBeSetup_item->duplicationIndication, + for (int i=0; isrbs_to_be_setup_length; i++) { + asn1cSequenceAdd(ie11->value.choice.SRBs_ToBeSetup_List.list, F1AP_SRBs_ToBeSetup_ItemIEs_t, srbs_toBeSetup_item_ies); + srbs_toBeSetup_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetup_Item; // 73 + srbs_toBeSetup_item_ies->criticality = F1AP_Criticality_ignore; + srbs_toBeSetup_item_ies->value.present = F1AP_SRBs_ToBeSetup_ItemIEs__value_PR_SRBs_ToBeSetup_Item; + /* 11.1 SRBs_ToBeSetup_Item */ + F1AP_SRBs_ToBeSetup_Item_t *srbs_toBeSetup_item=&srbs_toBeSetup_item_ies->value.choice.SRBs_ToBeSetup_Item; + /* 11.1.1 sRBID */ + srbs_toBeSetup_item->sRBID = f1ap_ue_context_setup_req->srbs_to_be_setup[i].srb_id; + /* OPTIONAL */ + /* 11.1.2 duplicationIndication */ + asn1cCallocOne(srbs_toBeSetup_item->duplicationIndication, F1AP_DuplicationIndication_true); // enum - //} - } + } } /* mandatory */ /* c12. DRBs_ToBeSetup_List */ if(f1ap_ue_context_setup_req->drbs_to_be_setup_length){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie12); - ie12->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_List; - ie12->criticality = F1AP_Criticality_reject; - ie12->value.present = F1AP_UEContextSetupRequestIEs__value_PR_DRBs_ToBeSetup_List; - LOG_I(F1AP, "Length of drbs_to_be_setup: %d \n", f1ap_ue_context_setup_req->drbs_to_be_setup_length); + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie12); + ie12->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_List; + ie12->criticality = F1AP_Criticality_reject; + ie12->value.present = F1AP_UEContextSetupRequestIEs__value_PR_DRBs_ToBeSetup_List; + LOG_I(F1AP, "Length of drbs_to_be_setup: %d \n", f1ap_ue_context_setup_req->drbs_to_be_setup_length); - for (int i = 0; i < f1ap_ue_context_setup_req->drbs_to_be_setup_length; i++) { - // - asn1cSequenceAdd(ie12->value.choice.DRBs_ToBeSetup_List.list, F1AP_DRBs_ToBeSetup_ItemIEs_t, drbs_toBeSetup_item_ies); - drbs_toBeSetup_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_Item; - drbs_toBeSetup_item_ies->criticality = F1AP_Criticality_reject; - drbs_toBeSetup_item_ies->value.present = F1AP_DRBs_ToBeSetup_ItemIEs__value_PR_DRBs_ToBeSetup_Item; - /* 12.1 DRBs_ToBeSetup_Item */ - F1AP_DRBs_ToBeSetup_Item_t *drbs_toBeSetup_item=&drbs_toBeSetup_item_ies->value.choice.DRBs_ToBeSetup_Item; - /* 12.1.1 dRBID */ - drbs_toBeSetup_item->dRBID = f1ap_ue_context_setup_req->drbs_to_be_setup[i].drb_id; // 9 - /* 12.1.2 qoSInformation */ - int some_decide_qos = 0; // BK: Need Check + for (int i = 0; i < f1ap_ue_context_setup_req->drbs_to_be_setup_length; i++) { + // + asn1cSequenceAdd(ie12->value.choice.DRBs_ToBeSetup_List.list, F1AP_DRBs_ToBeSetup_ItemIEs_t, drbs_toBeSetup_item_ies); + drbs_toBeSetup_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_Item; + drbs_toBeSetup_item_ies->criticality = F1AP_Criticality_reject; + drbs_toBeSetup_item_ies->value.present = F1AP_DRBs_ToBeSetup_ItemIEs__value_PR_DRBs_ToBeSetup_Item; + /* 12.1 DRBs_ToBeSetup_Item */ + F1AP_DRBs_ToBeSetup_Item_t *drbs_toBeSetup_item=&drbs_toBeSetup_item_ies->value.choice.DRBs_ToBeSetup_Item; + /* 12.1.1 dRBID */ + drbs_toBeSetup_item->dRBID = f1ap_ue_context_setup_req->drbs_to_be_setup[i].drb_id; // 9 + /* 12.1.2 qoSInformation */ + int some_decide_qos = 0; // BK: Need Check - if (some_decide_qos) { - drbs_toBeSetup_item->qoSInformation.present = F1AP_QoSInformation_PR_eUTRANQoS; - /* 12.1.2.1 eUTRANQoS */ - asn1cCalloc(drbs_toBeSetup_item->qoSInformation.choice.eUTRANQoS, eUTRANQoS); - /* 12.1.2.1.1 qCI */ - eUTRANQoS->qCI = 254L; - /* 12.1.2.1.2 allocationAndRetentionPriority */ - { - /* 12.1.2.1.2.1 priorityLevel */ - eUTRANQoS->allocationAndRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum - /* 12.1.2.1.2.2 pre_emptionCapability */ - eUTRANQoS->allocationAndRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_may_trigger_pre_emption; // enum - /* 12.1.2.1.2.2 pre_emptionVulnerability */ - eUTRANQoS->allocationAndRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum - } - - /* OPTIONAL */ - /* 12.1.2.1.3 gbrQosInformation */ - if (0) { - eUTRANQoS->gbrQosInformation = (F1AP_GBR_QosInformation_t *)calloc(1, sizeof(F1AP_GBR_QosInformation_t)); - asn_long2INTEGER(&eUTRANQoS->gbrQosInformation->e_RAB_MaximumBitrateDL, 1L); - asn_long2INTEGER(&eUTRANQoS->gbrQosInformation->e_RAB_MaximumBitrateUL, 1L); - asn_long2INTEGER(&eUTRANQoS->gbrQosInformation->e_RAB_GuaranteedBitrateDL, 1L); - asn_long2INTEGER(&eUTRANQoS->gbrQosInformation->e_RAB_GuaranteedBitrateUL, 1L); - } - } else { - /* 12.1.2 DRB_Information */ - drbs_toBeSetup_item->qoSInformation.present = F1AP_QoSInformation_PR_choice_extension; - F1AP_QoSInformation_ExtIEs_t *ie = (F1AP_QoSInformation_ExtIEs_t *)calloc(1, sizeof(*ie)); - ie->id = F1AP_ProtocolIE_ID_id_DRB_Information; - ie->criticality = F1AP_Criticality_reject; - ie->value.present = F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information; - F1AP_DRB_Information_t *DRB_Information = &ie->value.choice.DRB_Information; - drbs_toBeSetup_item->qoSInformation.choice.choice_extension = (struct F1AP_ProtocolIE_SingleContainer *)ie; - /* 12.1.2.1 dRB_QoS */ - { - /* qoS_Characteristics */ + if (some_decide_qos) { + drbs_toBeSetup_item->qoSInformation.present = F1AP_QoSInformation_PR_eUTRANQoS; + /* 12.1.2.1 eUTRANQoS */ + asn1cCalloc(drbs_toBeSetup_item->qoSInformation.choice.eUTRANQoS, eUTRANQoS); + /* 12.1.2.1.1 qCI */ + eUTRANQoS->qCI = 254L; + /* 12.1.2.1.2 allocationAndRetentionPriority */ { - int some_decide_qoS_characteristics = 0; // BK: Need Check - - if (some_decide_qoS_characteristics) { - DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI; - setQos(DRB_Information->dRB_QoS.qoS_Characteristics.choice.non_Dynamic_5QI); - } else { - DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_dynamic_5QI; - asn1cCalloc(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI, tmp); - /* qoSPriorityLevel */ - tmp->qoSPriorityLevel = 1L; - /* packetDelayBudget */ - tmp->packetDelayBudget = 1L; - /* packetErrorRate */ - tmp->packetErrorRate.pER_Scalar = 1L; - tmp->packetErrorRate.pER_Exponent = 6L; - - /* OPTIONAL */ - /* delayCritical */ - if (0) { - asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->delayCritical, 1L); - } - - /* OPTIONAL */ - /* averagingWindow */ - if (0) { - asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->averagingWindow, 1L); - } - - /* OPTIONAL */ - /* maxDataBurstVolume */ - if (0) { - asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->maxDataBurstVolume, 1L); - } - } // if some_decide_qoS_characteristics - } // qoS_Characteristics - /* nGRANallocationRetentionPriority */ - { - DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum - DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_shall_not_trigger_pre_emption; // enum - DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum - } // nGRANallocationRetentionPriority - - /* OPTIONAL */ - /* gBR_QoS_Flow_Information */ - if (0) { - asn1cCalloc(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information, tmp); - asn_long2INTEGER(&tmp->maxFlowBitRateDownlink, 1L); - asn_long2INTEGER(&tmp->maxFlowBitRateUplink, 1L); - asn_long2INTEGER(&tmp->guaranteedFlowBitRateDownlink, 1L); - asn_long2INTEGER(&tmp->guaranteedFlowBitRateUplink, 1L); - - /* OPTIONAL */ - /* maxPacketLossRateDownlink */ - if (0) { - asn1cCallocOne(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information->maxPacketLossRateDownlink, 1L); - } - - /* OPTIONAL */ - /* maxPacketLossRateUplink */ - if (0) { - asn1cCallocOne(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information->maxPacketLossRateUplink, 1L); - } + /* 12.1.2.1.2.1 priorityLevel */ + eUTRANQoS->allocationAndRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum + /* 12.1.2.1.2.2 pre_emptionCapability */ + eUTRANQoS->allocationAndRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_may_trigger_pre_emption; // enum + /* 12.1.2.1.2.2 pre_emptionVulnerability */ + eUTRANQoS->allocationAndRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum } /* OPTIONAL */ - /* reflective_QoS_Attribute */ + /* 12.1.2.1.3 gbrQosInformation */ if (0) { - asn1cCallocOne(DRB_Information->dRB_QoS.reflective_QoS_Attribute, 1L); + eUTRANQoS->gbrQosInformation = (F1AP_GBR_QosInformation_t *)calloc(1, sizeof(F1AP_GBR_QosInformation_t)); + asn_long2INTEGER(&eUTRANQoS->gbrQosInformation->e_RAB_MaximumBitrateDL, 1L); + asn_long2INTEGER(&eUTRANQoS->gbrQosInformation->e_RAB_MaximumBitrateUL, 1L); + asn_long2INTEGER(&eUTRANQoS->gbrQosInformation->e_RAB_GuaranteedBitrateDL, 1L); + asn_long2INTEGER(&eUTRANQoS->gbrQosInformation->e_RAB_GuaranteedBitrateUL, 1L); } - } // dRB_QoS - /* 12.1.2.2 sNSSAI */ - { - /* sST */ - OCTET_STRING_fromBuf(&DRB_Information->sNSSAI.sST, "1", 1); - - /* OPTIONAL */ - /* sD */ - if (0) { - asn1cCalloc(DRB_Information->sNSSAI.sD, tmp); - OCTET_STRING_fromBuf(tmp, "asdsa1d32sa1d31asd31as", - strlen("asdsa1d32sa1d31asd31as")); - } - } - - /* OPTIONAL */ - /* 12.1.2.3 notificationControl */ - if (0) { - asn1cCallocOne(DRB_Information->notificationControl, - F1AP_NotificationControl_active); // enum - } - - /* 12.1.2.4 flows_Mapped_To_DRB_List */ // BK: need verifiy - - for (int k = 0; k < 1; k ++) { - asn1cSequenceAdd(DRB_Information->flows_Mapped_To_DRB_List.list, - F1AP_Flows_Mapped_To_DRB_Item_t, flows_mapped_to_drb_item); - /* qoSFlowIndicator */ - flows_mapped_to_drb_item->qoSFlowIdentifier = 1L; - /* qoSFlowLevelQoSParameters */ + } else { + /* 12.1.2 DRB_Information */ + drbs_toBeSetup_item->qoSInformation.present = F1AP_QoSInformation_PR_choice_extension; + F1AP_QoSInformation_ExtIEs_t *ie = (F1AP_QoSInformation_ExtIEs_t *)calloc(1, sizeof(*ie)); + ie->id = F1AP_ProtocolIE_ID_id_DRB_Information; + ie->criticality = F1AP_Criticality_reject; + ie->value.present = F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information; + F1AP_DRB_Information_t *DRB_Information = &ie->value.choice.DRB_Information; + drbs_toBeSetup_item->qoSInformation.choice.choice_extension = (struct F1AP_ProtocolIE_SingleContainer *)ie; + /* 12.1.2.1 dRB_QoS */ { /* qoS_Characteristics */ { int some_decide_qoS_characteristics = 0; // BK: Need Check - F1AP_QoS_Characteristics_t *QosParams=&flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.qoS_Characteristics; if (some_decide_qoS_characteristics) { - QosParams->present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI; - setQos(QosParams->choice.non_Dynamic_5QI); + DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI; + setQos(DRB_Information->dRB_QoS.qoS_Characteristics.choice.non_Dynamic_5QI); } else { - QosParams->present = F1AP_QoS_Characteristics_PR_dynamic_5QI; - asn1cCalloc(QosParams->choice.dynamic_5QI, tmp); + DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_dynamic_5QI; + asn1cCalloc(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI, tmp); /* qoSPriorityLevel */ tmp->qoSPriorityLevel = 1L; /* packetDelayBudget */ @@ -454,36 +348,33 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(instance_t instance, /* OPTIONAL */ /* delayCritical */ if (0) { - asn1cCalloc(QosParams->choice.dynamic_5QI->delayCritical, tmp); - *tmp = 1L; + asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->delayCritical, 1L); } /* OPTIONAL */ /* averagingWindow */ if (0) { - asn1cCalloc(QosParams->choice.dynamic_5QI->averagingWindow, tmp); - *tmp = 1L; + asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->averagingWindow, 1L); } /* OPTIONAL */ /* maxDataBurstVolume */ if (0) { - asn1cCalloc(QosParams->choice.dynamic_5QI->maxDataBurstVolume, tmp); - *tmp= 1L; + asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->maxDataBurstVolume, 1L); } } // if some_decide_qoS_characteristics } // qoS_Characteristics /* nGRANallocationRetentionPriority */ { - flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum - flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_shall_not_trigger_pre_emption; // enum - flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum + DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum + DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_shall_not_trigger_pre_emption; // enum + DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum } // nGRANallocationRetentionPriority /* OPTIONAL */ /* gBR_QoS_Flow_Information */ if (0) { - asn1cCalloc(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information, tmp); + asn1cCalloc(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information, tmp); asn_long2INTEGER(&tmp->maxFlowBitRateDownlink, 1L); asn_long2INTEGER(&tmp->maxFlowBitRateUplink, 1L); asn_long2INTEGER(&tmp->guaranteedFlowBitRateDownlink, 1L); @@ -492,81 +383,187 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(instance_t instance, /* OPTIONAL */ /* maxPacketLossRateDownlink */ if (0) { - asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information->maxPacketLossRateDownlink, 1L); + asn1cCallocOne(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information->maxPacketLossRateDownlink, 1L); } /* OPTIONAL */ /* maxPacketLossRateUplink */ if (0) { - asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information->maxPacketLossRateUplink, 1L); + asn1cCallocOne(DRB_Information->dRB_QoS.gBR_QoS_Flow_Information->maxPacketLossRateUplink, 1L); } } /* OPTIONAL */ /* reflective_QoS_Attribute */ if (0) { - asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.reflective_QoS_Attribute, 1L); + asn1cCallocOne(DRB_Information->dRB_QoS.reflective_QoS_Attribute, 1L); } - } // qoSFlowLevelQoSParameters - } - } // if some_decide_qos + } // dRB_QoS + /* 12.1.2.2 sNSSAI */ + { + /* sST */ + OCTET_STRING_fromBuf(&DRB_Information->sNSSAI.sST, "1", 1); - /* 12.1.3 uLUPTNLInformation_ToBeSetup_List */ - for (int j = 0; j < f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl_length; j++) { - /*Use a dummy teid for the outgoing GTP-U tunnel (DU) which will be updated once we get the UE context setup response from the DU*/ - transport_layer_addr_t addr; - int sz=sizeof(f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_dl_tnl[0].tl_address); - memcpy(addr.buffer,&f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_dl_tnl[0].tl_address, sz); - addr.length = sz*8; - f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl[j].teid= - newGtpuCreateTunnel(getCxt(CUtype, instance)->gtpInst, - f1ap_ue_context_setup_req->rnti, - f1ap_ue_context_setup_req->drbs_to_be_setup[i].drb_id, - f1ap_ue_context_setup_req->drbs_to_be_setup[i].drb_id, - 0xFFFF, // We will set the right value from DU answer - addr, - f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_dl_tnl[0].port, - cu_f1u_data_req); - /* 12.3.1 ULTunnels_ToBeSetup_Item */ - asn1cSequenceAdd(drbs_toBeSetup_item->uLUPTNLInformation_ToBeSetup_List.list, - F1AP_ULUPTNLInformation_ToBeSetup_Item_t, uLUPTNLInformation_ToBeSetup_Item); - uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; - asn1cCalloc( uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.choice.gTPTunnel, - gTPTunnel); - /* 12.3.1.1.1 transportLayerAddress */ - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl[j].tl_address, + /* OPTIONAL */ + /* sD */ + if (0) { + asn1cCalloc(DRB_Information->sNSSAI.sD, tmp); + OCTET_STRING_fromBuf(tmp, "asdsa1d32sa1d31asd31as", + strlen("asdsa1d32sa1d31asd31as")); + } + } + + /* OPTIONAL */ + /* 12.1.2.3 notificationControl */ + if (0) { + asn1cCallocOne(DRB_Information->notificationControl, + F1AP_NotificationControl_active); // enum + } + + /* 12.1.2.4 flows_Mapped_To_DRB_List */ // BK: need verifiy + + for (int k = 0; k < 1; k ++) { + asn1cSequenceAdd(DRB_Information->flows_Mapped_To_DRB_List.list, + F1AP_Flows_Mapped_To_DRB_Item_t, flows_mapped_to_drb_item); + /* qoSFlowIndicator */ + flows_mapped_to_drb_item->qoSFlowIdentifier = 1L; + /* qoSFlowLevelQoSParameters */ + { + /* qoS_Characteristics */ + { + int some_decide_qoS_characteristics = 0; // BK: Need Check + F1AP_QoS_Characteristics_t *QosParams=&flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.qoS_Characteristics; + + if (some_decide_qoS_characteristics) { + QosParams->present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI; + setQos(QosParams->choice.non_Dynamic_5QI); + } else { + QosParams->present = F1AP_QoS_Characteristics_PR_dynamic_5QI; + asn1cCalloc(QosParams->choice.dynamic_5QI, tmp); + /* qoSPriorityLevel */ + tmp->qoSPriorityLevel = 1L; + /* packetDelayBudget */ + tmp->packetDelayBudget = 1L; + /* packetErrorRate */ + tmp->packetErrorRate.pER_Scalar = 1L; + tmp->packetErrorRate.pER_Exponent = 6L; + + /* OPTIONAL */ + /* delayCritical */ + if (0) { + asn1cCalloc(QosParams->choice.dynamic_5QI->delayCritical, tmp); + *tmp = 1L; + } + + /* OPTIONAL */ + /* averagingWindow */ + if (0) { + asn1cCalloc(QosParams->choice.dynamic_5QI->averagingWindow, tmp); + *tmp = 1L; + } + + /* OPTIONAL */ + /* maxDataBurstVolume */ + if (0) { + asn1cCalloc(QosParams->choice.dynamic_5QI->maxDataBurstVolume, tmp); + *tmp= 1L; + } + } // if some_decide_qoS_characteristics + } // qoS_Characteristics + /* nGRANallocationRetentionPriority */ + { + flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum + flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_shall_not_trigger_pre_emption; // enum + flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum + } // nGRANallocationRetentionPriority + + /* OPTIONAL */ + /* gBR_QoS_Flow_Information */ + if (0) { + asn1cCalloc(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information, tmp); + asn_long2INTEGER(&tmp->maxFlowBitRateDownlink, 1L); + asn_long2INTEGER(&tmp->maxFlowBitRateUplink, 1L); + asn_long2INTEGER(&tmp->guaranteedFlowBitRateDownlink, 1L); + asn_long2INTEGER(&tmp->guaranteedFlowBitRateUplink, 1L); + + /* OPTIONAL */ + /* maxPacketLossRateDownlink */ + if (0) { + asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information->maxPacketLossRateDownlink, 1L); + } + + /* OPTIONAL */ + /* maxPacketLossRateUplink */ + if (0) { + asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information->maxPacketLossRateUplink, 1L); + } + } + + /* OPTIONAL */ + /* reflective_QoS_Attribute */ + if (0) { + asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.reflective_QoS_Attribute, 1L); + } + } // qoSFlowLevelQoSParameters + } + } // if some_decide_qos + + /* 12.1.3 uLUPTNLInformation_ToBeSetup_List */ + for (int j = 0; j < f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl_length; j++) { + /*Use a dummy teid for the outgoing GTP-U tunnel (DU) which will be updated once we get the UE context setup response from the DU*/ + transport_layer_addr_t addr; + int sz=sizeof(f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_dl_tnl[0].tl_address); + memcpy(addr.buffer,&f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_dl_tnl[0].tl_address, sz); + addr.length = sz*8; + f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl[j].teid= + newGtpuCreateTunnel(getCxt(CUtype, instance)->gtpInst, + f1ap_ue_context_setup_req->rnti, + f1ap_ue_context_setup_req->drbs_to_be_setup[i].drb_id, + f1ap_ue_context_setup_req->drbs_to_be_setup[i].drb_id, + 0xFFFF, // We will set the right value from DU answer + addr, + f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_dl_tnl[0].port, + cu_f1u_data_req); + /* 12.3.1 ULTunnels_ToBeSetup_Item */ + asn1cSequenceAdd(drbs_toBeSetup_item->uLUPTNLInformation_ToBeSetup_List.list, + F1AP_ULUPTNLInformation_ToBeSetup_Item_t, uLUPTNLInformation_ToBeSetup_Item); + uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; + asn1cCalloc( uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.choice.gTPTunnel, + gTPTunnel); + /* 12.3.1.1.1 transportLayerAddress */ + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl[j].tl_address, &gTPTunnel->transportLayerAddress); - /* 12.3.1.1.2 gTP_TEID */ - INT32_TO_OCTET_STRING(f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl[j].teid, - &gTPTunnel->gTP_TEID); - } + /* 12.3.1.1.2 gTP_TEID */ + INT32_TO_OCTET_STRING(f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl[j].teid, + &gTPTunnel->gTP_TEID); + } - /* 12.1.4 rLCMode */ - /* TODO use rlc_mode from f1ap_drb_to_be_setup */ - switch (f1ap_ue_context_setup_req->drbs_to_be_setup[i].rlc_mode) { - case RLC_MODE_AM: - drbs_toBeSetup_item->rLCMode = F1AP_RLCMode_rlc_am; - break; + /* 12.1.4 rLCMode */ + /* TODO use rlc_mode from f1ap_drb_to_be_setup */ + switch (f1ap_ue_context_setup_req->drbs_to_be_setup[i].rlc_mode) { + case RLC_MODE_AM: + drbs_toBeSetup_item->rLCMode = F1AP_RLCMode_rlc_am; + break; - default: - drbs_toBeSetup_item->rLCMode = F1AP_RLCMode_rlc_um_bidirectional; - } + default: + drbs_toBeSetup_item->rLCMode = F1AP_RLCMode_rlc_um_bidirectional; + } - /* OPTIONAL */ - /* 12.1.5 ULConfiguration */ - if (0) { - asn1cCalloc(drbs_toBeSetup_item->uLConfiguration, tmp); - tmp->uLUEConfiguration = F1AP_ULUEConfiguration_no_data; - } + /* OPTIONAL */ + /* 12.1.5 ULConfiguration */ + if (0) { + asn1cCalloc(drbs_toBeSetup_item->uLConfiguration, tmp); + tmp->uLUEConfiguration = F1AP_ULUEConfiguration_no_data; + } - /* OPTIONAL */ - /* 12.1.6 duplicationActivation */ - if (0) { - asn1cCalloc(drbs_toBeSetup_item->duplicationActivation, tmp); - *tmp = F1AP_DuplicationActivation_active; // enum + /* OPTIONAL */ + /* 12.1.6 duplicationActivation */ + if (0) { + asn1cCalloc(drbs_toBeSetup_item->duplicationActivation, tmp); + *tmp = F1AP_DuplicationActivation_active; // enum + } } } - } /* OPTIONAL */ /* InactivityMonitoringRequest */ @@ -673,9 +670,10 @@ int CU_handle_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, return -1; } - f1ap_ue_context_setup_resp->du_to_cu_rrc_information = (uint8_t *)calloc(1,ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size); - memcpy(f1ap_ue_context_setup_resp->du_to_cu_rrc_information, ie->value.choice.DUtoCURRCInformation.cellGroupConfig.buf, ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size); - f1ap_ue_context_setup_resp->du_to_cu_rrc_information_length = ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size; + f1ap_ue_context_setup_resp->du_to_cu_rrc_information = (du_to_cu_rrc_information_t *)calloc(1,sizeof(du_to_cu_rrc_information_t)); + f1ap_ue_context_setup_resp->du_to_cu_rrc_information->cellGroupConfig = (uint8_t *)calloc(1,ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size); + memcpy(f1ap_ue_context_setup_resp->du_to_cu_rrc_information->cellGroupConfig, ie->value.choice.DUtoCURRCInformation.cellGroupConfig.buf, ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size); + f1ap_ue_context_setup_resp->du_to_cu_rrc_information->cellGroupConfig_length = ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size; // DRBs_Setup_List F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupResponseIEs_t, ie, container, F1AP_ProtocolIE_ID_id_DRBs_Setup_List, false); @@ -1143,7 +1141,7 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, f1ap_ue_context /* optional */ /* c7. RRCRconfigurationCompleteIndicator */ - if (0) { + if (f1ap_ue_context_modification_req->ReconfigComplOutcome == RRCreconf_success) { asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie71); ie71->id = F1AP_ProtocolIE_ID_id_RRCReconfigurationCompleteIndicator; ie71->criticality = F1AP_Criticality_ignore; @@ -1153,13 +1151,13 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, f1ap_ue_context /* optional */ /* c8. RRCContainer */ - if (0) { + if (f1ap_ue_context_modification_req->rrc_container != NULL) { asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie81); ie81->id = F1AP_ProtocolIE_ID_id_RRCContainer; ie81->criticality = F1AP_Criticality_ignore; ie81->value.present = F1AP_UEContextModificationRequestIEs__value_PR_RRCContainer; - OCTET_STRING_fromBuf(&ie81->value.choice.RRCContainer, "asdsa1d32sa1d31asd31as", - strlen("asdsa1d32sa1d31asd31as")); + OCTET_STRING_fromBuf(&ie81->value.choice.RRCContainer, f1ap_ue_context_modification_req->rrc_container, + f1ap_ue_context_modification_req->rrc_container_length); } /* optional */ @@ -1232,10 +1230,8 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, f1ap_ue_context srbs_toBeSetupMod_item->sRBID = f1ap_ue_context_modification_req->srbs_to_be_setup[i].srb_id; /* OPTIONAL */ /* 11.1.2 duplicationIndication */ - //if (0) { asn1cCallocOne(srbs_toBeSetupMod_item->duplicationIndication, F1AP_DuplicationIndication_true); // enum - //} } } @@ -1310,42 +1306,42 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, f1ap_ue_context DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI; setQos(DRB_Information->dRB_QoS.qoS_Characteristics.choice.non_Dynamic_5QI); } else { - DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_dynamic_5QI; - asn1cCalloc(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI, tmp); - /* qoSPriorityLevel */ - tmp->qoSPriorityLevel = 1L; - /* packetDelayBudget */ - tmp->packetDelayBudget = 1L; - /* packetErrorRate */ - tmp->packetErrorRate.pER_Scalar = 1L; - tmp->packetErrorRate.pER_Exponent = 6L; + DRB_Information->dRB_QoS.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_dynamic_5QI; + asn1cCalloc(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI, tmp); + /* qoSPriorityLevel */ + tmp->qoSPriorityLevel = 1L; + /* packetDelayBudget */ + tmp->packetDelayBudget = 1L; + /* packetErrorRate */ + tmp->packetErrorRate.pER_Scalar = 1L; + tmp->packetErrorRate.pER_Exponent = 6L; - /* OPTIONAL */ - /* delayCritical */ - if (0) { - asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->delayCritical, 1L); - } + /* OPTIONAL */ + /* delayCritical */ + if (0) { + asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->delayCritical, 1L); + } - /* OPTIONAL */ - /* averagingWindow */ - if (0) { - asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->averagingWindow, 1L); - } + /* OPTIONAL */ + /* averagingWindow */ + if (0) { + asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->averagingWindow, 1L); + } - /* OPTIONAL */ - /* maxDataBurstVolume */ - if (0) { - asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->maxDataBurstVolume, 1L); - } - } // if some_decide_qoS_characteristics + /* OPTIONAL */ + /* maxDataBurstVolume */ + if (0) { + asn1cCallocOne(DRB_Information->dRB_QoS.qoS_Characteristics.choice.dynamic_5QI->maxDataBurstVolume, 1L); + } + } // if some_decide_qoS_characteristics - } // qoS_Characteristics - /* nGRANallocationRetentionPriority */ - { - DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum - DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_shall_not_trigger_pre_emption; // enum - DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum - } // nGRANallocationRetentionPriority + } // qoS_Characteristics + /* nGRANallocationRetentionPriority */ + { + DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum + DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_shall_not_trigger_pre_emption; // enum + DRB_Information->dRB_QoS.nGRANallocationRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum + } // nGRANallocationRetentionPriority /* OPTIONAL */ /* gBR_QoS_Flow_Information */ @@ -1682,10 +1678,11 @@ int CU_handle_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, F1AP_ProtocolIE_ID_id_DUtoCURRCInformation, false); if(ie!=NULL){ - f1ap_ue_context_modification_resp->du_to_cu_rrc_information = (uint8_t *)calloc(1,ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size); + f1ap_ue_context_modification_resp->du_to_cu_rrc_information = (du_to_cu_rrc_information_t *)calloc(1, sizeof(du_to_cu_rrc_information_t)); + f1ap_ue_context_modification_resp->du_to_cu_rrc_information->cellGroupConfig = (uint8_t *)calloc(1,ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size); - memcpy(f1ap_ue_context_modification_resp->du_to_cu_rrc_information, ie->value.choice.DUtoCURRCInformation.cellGroupConfig.buf, ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size); - f1ap_ue_context_modification_resp->du_to_cu_rrc_information_length = ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size; + memcpy(f1ap_ue_context_modification_resp->du_to_cu_rrc_information->cellGroupConfig, ie->value.choice.DUtoCURRCInformation.cellGroupConfig.buf, ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size); + f1ap_ue_context_modification_resp->du_to_cu_rrc_information->cellGroupConfig_length = ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size; } // DRBs_SetupMod_List diff --git a/openair2/F1AP/f1ap_du_interface_management.c b/openair2/F1AP/f1ap_du_interface_management.c index e972a31301..b48c576c75 100644 --- a/openair2/F1AP/f1ap_du_interface_management.c +++ b/openair2/F1AP/f1ap_du_interface_management.c @@ -172,25 +172,19 @@ int DU_send_F1_SETUP_REQUEST(instance_t instance) { MCC_MNC_TO_PLMNID(cell->mcc, cell->mnc, cell->mnc_digit_length, &servedPLMN_item->pLMN_Identity); // // /* - CHOICE NR-MODE-Info */ F1AP_NR_Mode_Info_t *nR_Mode_Info= &served_cell_information->nR_Mode_Info; - //if(0){ - //F1AP_ProtocolExtensionContainer_154P260_t *p_154P260=calloc(1, sizeof(* p_154P260)); - F1AP_ProtocolExtensionContainer_154P34_t *p_154P34=calloc(1,sizeof(* p_154P34)); - servedPLMN_item->iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)p_154P34; - asn1cSequenceAdd(p_154P34->list, F1AP_ServedPLMNs_ItemExtIEs_t , served_plmns_itemExtIEs); - served_plmns_itemExtIEs->criticality = F1AP_Criticality_ignore; - served_plmns_itemExtIEs->id = F1AP_ProtocolIE_ID_id_TAISliceSupportList; - served_plmns_itemExtIEs->extensionValue.present = F1AP_ServedPLMNs_ItemExtIEs__extensionValue_PR_SliceSupportList; - F1AP_SliceSupportList_t *slice_support_list = &served_plmns_itemExtIEs->extensionValue.choice.SliceSupportList; + F1AP_ProtocolExtensionContainer_154P34_t *p_154P34=calloc(1,sizeof(* p_154P34)); + servedPLMN_item->iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)p_154P34; + asn1cSequenceAdd(p_154P34->list, F1AP_ServedPLMNs_ItemExtIEs_t , served_plmns_itemExtIEs); + served_plmns_itemExtIEs->criticality = F1AP_Criticality_ignore; + served_plmns_itemExtIEs->id = F1AP_ProtocolIE_ID_id_TAISliceSupportList; + served_plmns_itemExtIEs->extensionValue.present = F1AP_ServedPLMNs_ItemExtIEs__extensionValue_PR_SliceSupportList; + F1AP_SliceSupportList_t *slice_support_list = &served_plmns_itemExtIEs->extensionValue.choice.SliceSupportList; - asn1cSequenceAdd(slice_support_list->list, F1AP_SliceSupportItem_t, SliceSupport_item); - INT8_TO_OCTET_STRING(1,&SliceSupport_item->sNSSAI.sST); - //OCTET_STRING_fromBuf(&SliceSupport_item->sNSSAI.sST, "1", 1); - asn1cCalloc(SliceSupport_item->sNSSAI.sD, tmp); - INT24_TO_OCTET_STRING(1,tmp); - //OCTET_STRING_fromBuf(tmp, "1",1); - //} + asn1cSequenceAdd(slice_support_list->list, F1AP_SliceSupportItem_t, SliceSupport_item); + INT8_TO_OCTET_STRING(1,&SliceSupport_item->sNSSAI.sST); + asn1cCalloc(SliceSupport_item->sNSSAI.sD, tmp); + INT24_TO_OCTET_STRING(1,tmp); - if (f1ap_req(false, instance)->fdd_flag) { // FDD nR_Mode_Info->present = F1AP_NR_Mode_Info_PR_fDD; asn1cCalloc(nR_Mode_Info->choice.fDD, fDD_Info); diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index ca0ddcc82d..ce99a31dd3 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -280,27 +280,30 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, f1ap_ue_context_setup /* mandatory */ /* c3. DUtoCURRCInformation */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie3); - ie3->id = F1AP_ProtocolIE_ID_id_DUtoCURRCInformation; - ie3->criticality = F1AP_Criticality_reject; - ie3->value.present = F1AP_UEContextSetupResponseIEs__value_PR_DUtoCURRCInformation; - { - /* cellGroupConfig */ - OCTET_STRING_fromBuf(&ie3->value.choice.DUtoCURRCInformation.cellGroupConfig, (const char *)resp->du_to_cu_rrc_information, - resp->du_to_cu_rrc_information_length); + if(resp->du_to_cu_rrc_information){ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie3); + ie3->id = F1AP_ProtocolIE_ID_id_DUtoCURRCInformation; + ie3->criticality = F1AP_Criticality_reject; + ie3->value.present = F1AP_UEContextSetupResponseIEs__value_PR_DUtoCURRCInformation; + if(resp->du_to_cu_rrc_information->cellGroupConfig!=NULL){ + /* cellGroupConfig */ + OCTET_STRING_fromBuf(&ie3->value.choice.DUtoCURRCInformation.cellGroupConfig, (const char *)resp->du_to_cu_rrc_information->cellGroupConfig, + resp->du_to_cu_rrc_information->cellGroupConfig_length); + } /* OPTIONAL */ /* measGapConfig */ - if (0) { - asn1cCalloc(ie3->value.choice.DUtoCURRCInformation.measGapConfig, tmp); - OCTET_STRING_fromBuf(tmp, "asdsa", strlen("asdsa")); + if (resp->du_to_cu_rrc_information->measGapConfig!=NULL) { + OCTET_STRING_fromBuf(ie3->value.choice.DUtoCURRCInformation.measGapConfig, resp->du_to_cu_rrc_information->measGapConfig, + resp->du_to_cu_rrc_information->measGapConfig_length); } /* OPTIONAL */ /* requestedP_MaxFR1 */ - if (0) { + if (resp->du_to_cu_rrc_information->requestedP_MaxFR1!=NULL) { asn1cCalloc(ie3->value.choice.DUtoCURRCInformation.requestedP_MaxFR1, tmp); - OCTET_STRING_fromBuf(tmp, "asdsa", strlen("asdsa")); + OCTET_STRING_fromBuf(ie3->value.choice.DUtoCURRCInformation.requestedP_MaxFR1, resp->du_to_cu_rrc_information->requestedP_MaxFR1, + resp->du_to_cu_rrc_information->requestedP_MaxFR1_length); } } @@ -676,14 +679,14 @@ int DU_send_UE_CONTEXT_RELEASE_REQUEST(instance_t instance, protocol_ctxt_t ctxt; DevAssert(pdu); container = &pdu->choice.initiatingMessage->value.choice.UEContextReleaseCommand; - // GNB_CU_UE_F1AP_ID + // GNB_CU_UE_F1AP_ID F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseCommandIEs_t, ie, container, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); ctxt.rnti = f1ap_get_rnti_by_cu_id(DUtype, instance, ie->value.choice.GNB_CU_UE_F1AP_ID); ctxt.instance = instance; ctxt.module_id = instance; ctxt.enb_flag = 1; - // GNB_DU_UE_F1AP_ID + // GNB_DU_UE_F1AP_ID F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseCommandIEs_t, ie, container, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); const rnti_t rnti = f1ap_get_rnti_by_du_id(DUtype, instance, @@ -711,13 +714,13 @@ int DU_send_UE_CONTEXT_RELEASE_REQUEST(instance_t instance, } } - // We don't need the Cause - // Optional RRC Container: if present, send to UE + // We don't need the Cause + // Optional RRC Container: if present, send to UE F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseCommandIEs_t, ie, container, F1AP_ProtocolIE_ID_id_RRCContainer, false); if (ie && !UE_out_of_sync) { - // RRC message and UE is reachable, send message + // RRC message and UE is reachable, send message const sdu_size_t sdu_len = ie->value.choice.RRCContainer.size; mem_block_t *pdu_p = NULL; pdu_p = get_free_mem_block(sdu_len, __func__); @@ -769,7 +772,7 @@ int DU_send_UE_CONTEXT_RELEASE_REQUEST(instance_t instance, if (ue_context_p && !UE_out_of_sync) { // UE exists and is in sync so we start a timer before releasing the - // connection + // connection pthread_mutex_lock(&rrc_release_freelist); for (uint16_t release_num = 0; release_num < NUMBER_OF_UE_MAX; release_num++) { @@ -793,13 +796,13 @@ int DU_send_UE_CONTEXT_RELEASE_REQUEST(instance_t instance, pthread_mutex_unlock(&rrc_release_freelist); ue_context_p->ue_context.ue_release_timer_s1 = 0; } else if (ue_context_p && UE_out_of_sync) { - // UE exists and is out of sync, drop the connection + // UE exists and is out of sync, drop the connection mac_eNB_rrc_ul_failure(instance, 0, 0, 0, rnti); } else { LOG_E(F1AP, "no ue_context for RNTI %x, acknowledging release\n", rnti); } - // TODO send this once the connection has really been released + // TODO send this once the connection has really been released f1ap_ue_context_release_cplt_t cplt; cplt.rnti = ctxt.rnti; DU_send_UE_CONTEXT_RELEASE_COMPLETE(instance, &cplt); @@ -1210,11 +1213,9 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, f1ap_ue_context_modification_req->rrc_container = malloc(ieRRC->value.choice.RRCContainer.size); memcpy(f1ap_ue_context_modification_req->rrc_container, ieRRC->value.choice.RRCContainer.buf, ieRRC->value.choice.RRCContainer.size); - // AssertFatal(0, "check configuration, send to appropriate handler\n"); protocol_ctxt_t ctxt; // decode RRC Container and act on the message type - //FIXME - //rnti_t rnti = f1ap_get_rnti_by_du_id(DUtype, instance, du_ue_f1ap_id); + ctxt.rnti = f1ap_ue_context_modification_req->rnti; ctxt.instance = instance; ctxt.module_id = instance; ctxt.enb_flag = 1; @@ -1223,10 +1224,10 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, memcpy(&pdcp_pdu_p->data[0], ieRRC->value.choice.RRCContainer.buf, ieRRC->value.choice.RRCContainer.size); du_rlc_data_req(&ctxt, 1, 0x00, 1, 1, 0, ieRRC->value.choice.RRCContainer.size, pdcp_pdu_p); } else { - LOG_E(F1AP, " RRCContainer in UEContextSetupRequestIEs size id 0\n"); + LOG_E(F1AP, " RRCContainer in UEContextModificationRequestIEs size id 0\n"); } } else { - LOG_W(F1AP, "can't find RRCContainer in UEContextSetupRequestIEs by id %ld \n", F1AP_ProtocolIE_ID_id_RRCContainer); + LOG_W(F1AP, "can't find RRCContainer in UEContextModificationRequestIEs by id %ld \n", F1AP_ProtocolIE_ID_id_RRCContainer); } itti_send_msg_to_task(TASK_RRC_GNB, instance, msg_p); @@ -1273,32 +1274,34 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, f1ap_ue_contex strlen("asdsa1d32sa1d31asd31as")); } - /* mandatory */ + /* optional */ /* c4. DUtoCURRCInformation */ + if(resp->du_to_cu_rrc_information!=NULL){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie4); ie4->id = F1AP_ProtocolIE_ID_id_DUtoCURRCInformation; ie4->criticality = F1AP_Criticality_reject; ie4->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DUtoCURRCInformation; - { + if(resp->du_to_cu_rrc_information->cellGroupConfig!=NULL){ /* cellGroupConfig */ - OCTET_STRING_fromBuf(&ie4->value.choice.DUtoCURRCInformation.cellGroupConfig, (const char *)resp->du_to_cu_rrc_information, - resp->du_to_cu_rrc_information_length); - - /* OPTIONAL */ - /* measGapConfig */ - if (0) { - asn1cCalloc(ie4->value.choice.DUtoCURRCInformation.measGapConfig, tmp); - OCTET_STRING_fromBuf(tmp, "asdsa", strlen("asdsa")); - } - - /* OPTIONAL */ - /* requestedP_MaxFR1 */ - if (0) { - asn1cCalloc(ie4->value.choice.DUtoCURRCInformation.requestedP_MaxFR1, tmp); - OCTET_STRING_fromBuf(tmp, "asdsa", strlen("asdsa")); - } + OCTET_STRING_fromBuf(&ie4->value.choice.DUtoCURRCInformation.cellGroupConfig, (const char *)resp->du_to_cu_rrc_information->cellGroupConfig, + resp->du_to_cu_rrc_information->cellGroupConfig_length); } + /* OPTIONAL */ + /* measGapConfig */ + if (resp->du_to_cu_rrc_information->measGapConfig!=NULL) { + OCTET_STRING_fromBuf(ie4->value.choice.DUtoCURRCInformation.measGapConfig, resp->du_to_cu_rrc_information->measGapConfig, + resp->du_to_cu_rrc_information->measGapConfig_length); + } + + /* OPTIONAL */ + /* requestedP_MaxFR1 */ + if (resp->du_to_cu_rrc_information->requestedP_MaxFR1!=NULL) { + OCTET_STRING_fromBuf(ie4->value.choice.DUtoCURRCInformation.requestedP_MaxFR1, resp->du_to_cu_rrc_information->requestedP_MaxFR1, + resp->du_to_cu_rrc_information->requestedP_MaxFR1_length); + } + } + /* optional */ /* c5. DRBs_Setup_List */ @@ -1318,11 +1321,6 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, f1ap_ue_contex /* dRBID */ drbs_setupmod_item->dRBID = resp->drbs_to_be_setup[i].drb_id; - /* OPTIONAL */ - /* lCID */ - //drbs_setup_item.lCID = (F1AP_LCID_t *)calloc(1, sizeof(F1AP_LCID_t)); - //drbs_setup_item.lCID = 1L; - for (int j=0; jdrbs_to_be_setup[i].up_dl_tnl_length; j++) { /* ADD */ asn1cSequenceAdd(drbs_setupmod_item->dLUPTNLInformation_ToBeSetup_List.list, @@ -1344,47 +1342,52 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, f1ap_ue_contex /* optional */ /* c6. DRBs_Modified_List */ - if(0){ + if(resp->drbs_to_be_modified_length > 0){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie6); ie6->id = F1AP_ProtocolIE_ID_id_DRBs_Modified_List; - ie6->criticality = F1AP_Criticality_reject; + ie6->criticality = F1AP_Criticality_ignore; ie6->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DRBs_Modified_List; - for (int i=0; i<1; i++) { + for (int i=0; idrbs_to_be_modified_length; i++) { asn1cSequenceAdd(ie6->value.choice.DRBs_Modified_List.list, F1AP_DRBs_Modified_ItemIEs_t, drbs_modified_item_ies); drbs_modified_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_Modified_Item; - drbs_modified_item_ies->criticality = F1AP_Criticality_reject; + drbs_modified_item_ies->criticality = F1AP_Criticality_ignore; drbs_modified_item_ies->value.present = F1AP_DRBs_Modified_ItemIEs__value_PR_DRBs_Modified_Item; /* DRBs_modified_Item */ F1AP_DRBs_Modified_Item_t *drbs_modified_item= &drbs_modified_item_ies->value.choice.DRBs_Modified_Item; /* dRBID */ - drbs_modified_item->dRBID = 25L; + drbs_modified_item->dRBID = resp->drbs_to_be_modified[i].drb_id; /* ULTunnels_Modified_List */ int maxnoofULTunnels = 1; // 2; - for (int j=0; jdrbs_to_be_modified[i].up_dl_tnl_length; j++) { /* DLTunnels_Modified_Item */ asn1cSequenceAdd(drbs_modified_item->dLUPTNLInformation_ToBeSetup_List.list, F1AP_DLUPTNLInformation_ToBeSetup_Item_t, dLUPTNLInformation_ToBeSetup_Item); asn1cCalloc(dLUPTNLInformation_ToBeSetup_Item, tmp); tmp->dLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; asn1cCalloc(dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.choice.gTPTunnel, gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(1234, &gTPTunnel->transportLayerAddress); - OCTET_STRING_fromBuf(&gTPTunnel->gTP_TEID, "1204", strlen("1204")); + /* transportLayerAddress */ + struct sockaddr_in addr= {0}; + inet_pton(AF_INET, getCxt(false,instance)->setupReq.DU_f1_ip_address.ipv4_address, + &addr.sin_addr.s_addr); + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(addr.sin_addr.s_addr, &gTPTunnel->transportLayerAddress); + /* gTP_TEID */ + INT32_TO_OCTET_STRING(resp->drbs_to_be_modified[i].up_dl_tnl[j].teid, &gTPTunnel->gTP_TEID); } } } /* optional */ /* c7. SRBs_FailedToBeSetupMod_List */ - if(0){ + if(resp->srbs_failed_to_be_setup_length > 0){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie7); ie7->id = F1AP_ProtocolIE_ID_id_SRBs_FailedToBeSetupMod_List; ie7->criticality = F1AP_Criticality_reject; ie7->value.present = F1AP_UEContextModificationResponseIEs__value_PR_SRBs_FailedToBeSetupMod_List; - for (int i=0; i<1; i++) { + for (int i=0; isrbs_to_be_setup_length; i++) { asn1cSequenceAdd(ie7->value.choice.SRBs_FailedToBeSetupMod_List.list, F1AP_SRBs_FailedToBeSetupMod_ItemIEs_t, srbs_failedToBeSetupMod_item_ies); srbs_failedToBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_FailedToBeSetupMod_Item; @@ -1394,7 +1397,7 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, f1ap_ue_contex F1AP_SRBs_FailedToBeSetupMod_Item_t *srbs_failedToBeSetupMod_item= &srbs_failedToBeSetupMod_item_ies->value.choice.SRBs_FailedToBeSetupMod_Item; /* - sRBID */ - srbs_failedToBeSetupMod_item->sRBID = 50L; + srbs_failedToBeSetupMod_item->sRBID = resp->srbs_failed_to_be_setup[i].rb_id; asn1cCalloc(srbs_failedToBeSetupMod_item->cause, tmp) tmp->present = F1AP_Cause_PR_radioNetwork; tmp->choice.radioNetwork = F1AP_CauseRadioNetwork_unknown_or_already_allocated_gnb_du_ue_f1ap_id; @@ -1403,13 +1406,13 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, f1ap_ue_contex /* optional */ /* c8. DRBs_FailedToBeSetupMod_List */ - if(0){ + if(resp->drbs_failed_to_be_setup_length > 0){ asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie8); ie8->id = F1AP_ProtocolIE_ID_id_DRBs_FailedToBeSetupMod_List; ie8->criticality = F1AP_Criticality_reject; ie8->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DRBs_FailedToBeSetupMod_List; - for (int i=0; i<1; i++) { + for (int i=0; idrbs_failed_to_be_setup_length; i++) { asn1cSequenceAdd(ie8->value.choice.DRBs_FailedToBeSetupMod_List.list, F1AP_DRBs_FailedToBeSetupMod_ItemIEs_t, drbs_failedToBeSetupMod_item_ies); drbs_failedToBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_FailedToBeSetupMod_Item; @@ -1419,7 +1422,7 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, f1ap_ue_contex F1AP_DRBs_FailedToBeSetupMod_Item_t *drbs_failedToBeSetupMod_item= &drbs_failedToBeSetupMod_item_ies->value.choice.DRBs_FailedToBeSetupMod_Item; /* dRBID */ - drbs_failedToBeSetupMod_item->dRBID = 30L; + drbs_failedToBeSetupMod_item->dRBID = resp->drbs_failed_to_be_setup[i].rb_id; drbs_failedToBeSetupMod_item->cause = (F1AP_Cause_t *)calloc(1, sizeof(F1AP_Cause_t)); drbs_failedToBeSetupMod_item->cause->present = F1AP_Cause_PR_radioNetwork; drbs_failedToBeSetupMod_item->cause->choice.radioNetwork = F1AP_CauseRadioNetwork_unknown_or_already_allocated_gnb_du_ue_f1ap_id; diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 42b23da09d..1dac3178da 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1879,11 +1879,7 @@ int RCconfig_NR_DU_F1(MessageDef *msg_p, uint32_t i) { f1Setup->ranac[k] = 0; f1Setup->mib[k] = rrc->carrier.MIB; f1Setup->mib_length[k] = rrc->carrier.sizeof_MIB; - if(0){ - f1Setup->sib1[k] = rrc->carrier.SIB1; - f1Setup->sib1_length[k] = rrc->carrier.sizeof_SIB1; - } - else{ + NR_BCCH_DL_SCH_Message_t *bcch_message = NULL; asn_dec_rval_t dec_rval = uper_decode_complete( NULL, @@ -1914,7 +1910,6 @@ int RCconfig_NR_DU_F1(MessageDef *msg_p, uint32_t i) { xer_fprint(stdout, &asn_DEF_NR_SIB1,(void *)bcch_message->message.choice.c1->choice.systemInformationBlockType1 ); //} f1Setup->sib1_length[k] = (enc_rval.encoded+7)/8; - } break; } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 84099a58e6..79f1fcfdbe 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -992,10 +992,6 @@ void nr_schedule_ue_spec(module_id_t module_id, return; /* PREPROCESSOR */ - //Following commented section condition should be removed before update with develop. - /*if(slot!= 1 && slot!=11){ - return; - }*/ gNB_mac->pre_processor_dl(module_id, frame, slot); const int CC_id = 0; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index bded0a619d..97cc60d31c 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1388,49 +1388,6 @@ rrc_gNB_process_RRCReconfigurationComplete( NULL, get_softmodem_params()->sa ? ue_context_pP->ue_context.masterCellGroup->rlc_BearerToAddModList : NULL); } - /*else if(SRB_configList!=NULL || DRB_configList!=NULL){ - MessageDef *message_p; - message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, F1AP_UE_CONTEXT_SETUP_REQ); - f1ap_ue_context_setup_t *req=&F1AP_UE_CONTEXT_SETUP_REQ (message_p); - req->gNB_CU_ue_id = 0; - req->gNB_DU_ue_id = 0; - req->rnti = ue_context_pP->ue_context.rnti; - req->mcc = rrc->configuration.mcc[0]; - req->mnc = rrc->configuration.mnc[0]; - req->mnc_digit_length = rrc->configuration.mnc_digit_length[0]; - req->nr_cellid = rrc->nr_cellid; - if(SRB_configList!=NULL){ - req->srbs_to_be_setup = malloc(SRB_configList->list.count*sizeof(f1ap_srb_to_be_setup_t)); - req->srbs_to_be_setup_length = SRB_configList->list.count; - f1ap_srb_to_be_setup_t *SRBs=req->srbs_to_be_setup; - for (int i = 0; i < SRB_configList->list.count; i++){ - if(SRB_configList->list.array[i]->srb_Identity > 1){ - SRBs[i].srb_id = SRB_configList->list.array[i]->srb_Identity; - SRBs[i].lcid = SRB_configList->list.array[i]->srb_Identity; - } - } - } - if(DRB_configList!=NULL){ - gtpv1u_gnb_create_tunnel_req_t create_tunnel_req; - memset(&create_tunnel_req, 0, sizeof(gtpv1u_gnb_create_tunnel_req_t)); - req->drbs_to_be_setup = malloc(DRB_configList->list.count*sizeof(f1ap_drb_to_be_setup_t)); - req->drbs_to_be_setup_length = DRB_configList->list.count; - f1ap_drb_to_be_setup_t *DRBs=req->drbs_to_be_setup; - LOG_I(RRC, "Length of DRB list:%d, %d \n", DRB_configList->list.count, req->drbs_to_be_setup_length); - for (int i = 0; i < DRB_configList->list.count; i++){ - DRBs[i].drb_id = DRB_configList->list.array[i]->drb_Identity; - DRBs[i].rlc_mode = RLC_MODE_AM; - DRBs[i].up_ul_tnl[0].tl_address = inet_addr(rrc->eth_params_s.my_addr); - DRBs[i].up_ul_tnl[0].port=rrc->eth_params_s.my_portd; - DRBs[i].up_ul_tnl_length = 1; - DRBs[i].up_dl_tnl[0].tl_address = inet_addr(rrc->eth_params_s.remote_addr); - DRBs[i].up_dl_tnl[0].port=rrc->eth_params_s.remote_portd; - DRBs[i].up_dl_tnl_length = 1; - } - LOG_I(RRC, "Send F1AP_UE_CONTEXT_SETUP_REQ with ITTI\n"); - } - itti_send_msg_to_task (TASK_CU_F1, ctxt_pP->module_id, message_p); - }*/ #endif /* Set the SRB active in UE context */ @@ -2840,9 +2797,6 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *f1_setup_req) { memset(mib->message.choice.mib,0,sizeof(struct NR_MIB)); memcpy(mib->message.choice.mib, mib_DU->message.choice.mib, sizeof(struct NR_MIB)); - /*rrc->carrier.SIB1 = malloc(f1_setup_req->sib1_length[i]); - rrc->carrier.sizeof_SIB1 = f1_setup_req->sib1_length[i]; - memcpy((void *)rrc->carrier.SIB1,f1_setup_req->sib1[i],f1_setup_req->sib1_length[i]);*/ dec_rval = uper_decode_complete(NULL, &asn_DEF_NR_SIB1, //&asn_DEF_NR_BCCH_DL_SCH_Message, (void **)&rrc->carrier.siblock1_DU, @@ -2860,12 +2814,6 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *f1_setup_req) { xer_fprint(stdout, &asn_DEF_NR_SIB1,(void *)rrc->carrier.sib1); } - /*NR_BCCH_DL_SCH_Message_t *bcch_message = rrc->carrier.siblock1_DU; - AssertFatal(bcch_message->message.present == NR_BCCH_DL_SCH_MessageType_PR_c1, - "bcch_message->message.present != NR_BCCH_DL_SCH_MessageType_PR_c1\n"); - AssertFatal(bcch_message->message.choice.c1->present == NR_BCCH_DL_SCH_MessageType__c1_PR_systemInformationBlockType1, - "bcch_message->message.choice.c1->present != NR_BCCH_DL_SCH_MessageType__c1_PR_systemInformationBlockType1\n"); - rrc->carrier.sib1 = bcch_message->message.choice.c1->choice.systemInformationBlockType1;*/ rrc->carrier.physCellId = f1_setup_req->cell[i].nr_pci; F1AP_GNB_CU_CONFIGURATION_UPDATE (msg_p2).gNB_CU_name = rrc->node_name; @@ -3387,20 +3335,20 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha LOG_W(NR_RRC, "No SRB added upon reception of F1 UE Context setup request at the DU\n"); } /* fixme: - * Here we should be encoding the updates on cellgroupconfig. Currently the content of - * celGroupConfig is empty because update_cellGroupConfig() function that is previously called is empty. + * Here we should be encoding the updates on cellgroupconfig based on the content of UE capabilities */ - resp->du_to_cu_rrc_information = calloc(1,1024*sizeof(uint8_t)); + resp->du_to_cu_rrc_information = calloc(1, sizeof(du_to_cu_rrc_information_t)); + resp->du_to_cu_rrc_information->cellGroupConfig = calloc(1,1024); asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, ue_context_p->ue_context.masterCellGroup, //(void *)cellGroupConfig, - resp->du_to_cu_rrc_information, + resp->du_to_cu_rrc_information->cellGroupConfig, 1024); if (enc_rval.encoded == -1) { LOG_E(F1AP,"Could not encode ue_context.masterCellGroup, failed element %s\n",enc_rval.failed_type->name); exit(-1); } - resp->du_to_cu_rrc_information_length = (enc_rval.encoded+7)>>3; + resp->du_to_cu_rrc_information->cellGroupConfig_length = (enc_rval.encoded+7)>>3; free(cellGroupConfig); itti_send_msg_to_task (TASK_DU_F1, ctxt.module_id, message_p); } @@ -3520,13 +3468,14 @@ static void rrc_DU_process_ue_context_modification_request(MessageDef *msg_p, co } //if(cellGroupConfig != NULL) { - resp->du_to_cu_rrc_information = calloc(1,1024*sizeof(uint8_t)); + resp->du_to_cu_rrc_information = calloc(1,sizeof(du_to_cu_rrc_information_t)); + resp->du_to_cu_rrc_information->cellGroupConfig = calloc(1,1024); asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, ue_context_p->ue_context.masterCellGroup, //(void *)cellGroupConfig, - resp->du_to_cu_rrc_information, + resp->du_to_cu_rrc_information->cellGroupConfig, 1024); - resp->du_to_cu_rrc_information_length = (enc_rval.encoded+7)>>3; + resp->du_to_cu_rrc_information->cellGroupConfig_length = (enc_rval.encoded+7)>>3; //} itti_send_msg_to_task (TASK_DU_F1, ctxt.module_id, message_p); } @@ -3546,8 +3495,8 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, const ch asn_dec_rval_t dec_rval = uper_decode_complete( NULL, &asn_DEF_NR_CellGroupConfig, (void **)&cellGroupConfig, - (uint8_t *)resp->du_to_cu_rrc_information, - (int) resp->du_to_cu_rrc_information_length); + (uint8_t *)resp->du_to_cu_rrc_information->cellGroupConfig, + (int) resp->du_to_cu_rrc_information->cellGroupConfig_length); if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { AssertFatal(1==0,"Cell group config decode error\n"); @@ -3601,12 +3550,12 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, c struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_get_ue_context(rrc, ctxt.rnti); NR_CellGroupConfig_t *cellGroupConfig = NULL; - if(resp->du_to_cu_rrc_information!=NULL){ + if(resp->du_to_cu_rrc_information->cellGroupConfig!=NULL){ asn_dec_rval_t dec_rval = uper_decode_complete( NULL, &asn_DEF_NR_CellGroupConfig, (void **)&cellGroupConfig, - (uint8_t *)resp->du_to_cu_rrc_information, - (int) resp->du_to_cu_rrc_information_length); + (uint8_t *)resp->du_to_cu_rrc_information->cellGroupConfig, + (int) resp->du_to_cu_rrc_information->cellGroupConfig_length); if((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { AssertFatal(1==0,"Cell group config decode error\n"); @@ -3619,15 +3568,7 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, c if(ue_context_p->ue_context.masterCellGroup == NULL){ ue_context_p->ue_context.masterCellGroup = calloc(1, sizeof(NR_CellGroupConfig_t)); } - /*if(cellGroupConfig->rlc_BearerToAddModList!=NULL){ - if(ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList != NULL){ - LOG_I(NR_RRC, "rlc_BearerToAddModList not empty before filling it \n"); - free(ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList); - } - ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList = calloc(1, sizeof(*cellGroupConfig->rlc_BearerToAddModList)); - memcpy(ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList, cellGroupConfig->rlc_BearerToAddModList, - sizeof(*cellGroupConfig->rlc_BearerToAddModList)); - }*/ + if(cellGroupConfig->rlc_BearerToAddModList!=NULL){ if(ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList != NULL){ int ue_ctxt_rlc_Bearers = ue_context_p->ue_context.masterCellGroup->rlc_BearerToAddModList->list.count; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 20e60eedb0..79e1f1f4ce 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -1058,39 +1058,34 @@ rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ( MessageDef *message_p; message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, F1AP_UE_CONTEXT_MODIFICATION_REQ); f1ap_ue_context_setup_t *req=&F1AP_UE_CONTEXT_MODIFICATION_REQ (message_p); - //UE_IDs will be extracted from F1AP layer - req->gNB_CU_ue_id = 0; - req->gNB_DU_ue_id = 0; req->rnti = ue_context_p->ue_context.rnti; req->mcc = RC.nrrrc[ctxt.module_id]->configuration.mcc[0]; req->mnc = RC.nrrrc[ctxt.module_id]->configuration.mnc[0]; req->mnc_digit_length = RC.nrrrc[ctxt.module_id]->configuration.mnc_digit_length[0]; req->nr_cellid = RC.nrrrc[ctxt.module_id]->nr_cellid; - //if (ue_context_p->ue_context.established_pdu_sessions_flag == 1) { - /*Instruction towards the DU for SRB2 configuration*/ - req->srbs_to_be_setup = malloc(1*sizeof(f1ap_srb_to_be_setup_t)); - req->srbs_to_be_setup_length = 1; - f1ap_srb_to_be_setup_t *SRBs=req->srbs_to_be_setup; - SRBs[0].srb_id = 2; - SRBs[0].lcid = 2; + /*Instruction towards the DU for SRB2 configuration*/ + req->srbs_to_be_setup = malloc(1*sizeof(f1ap_srb_to_be_setup_t)); + req->srbs_to_be_setup_length = 1; + f1ap_srb_to_be_setup_t *SRBs=req->srbs_to_be_setup; + SRBs[0].srb_id = 2; + SRBs[0].lcid = 2; - /*Instruction towards the DU for DRB configuration and tunnel creation*/ - gtpv1u_gnb_create_tunnel_req_t create_tunnel_req; - memset(&create_tunnel_req, 0, sizeof(gtpv1u_gnb_create_tunnel_req_t)); - req->drbs_to_be_setup = malloc(1*sizeof(f1ap_drb_to_be_setup_t)); - req->drbs_to_be_setup_length = 1; - f1ap_drb_to_be_setup_t *DRBs=req->drbs_to_be_setup; - LOG_I(RRC, "Length of DRB list:%d \n", req->drbs_to_be_setup_length); - DRBs[0].drb_id = 1; - DRBs[0].rlc_mode = RLC_MODE_AM; - DRBs[0].up_ul_tnl[0].tl_address = inet_addr(RC.nrrrc[ctxt.module_id]->eth_params_s.my_addr); - DRBs[0].up_ul_tnl[0].port=RC.nrrrc[ctxt.module_id]->eth_params_s.my_portd; - DRBs[0].up_ul_tnl_length = 1; - DRBs[0].up_dl_tnl[0].tl_address = inet_addr(RC.nrrrc[ctxt.module_id]->eth_params_s.remote_addr); - DRBs[0].up_dl_tnl[0].port=RC.nrrrc[ctxt.module_id]->eth_params_s.remote_portd; - DRBs[0].up_dl_tnl_length = 1; - //} + /*Instruction towards the DU for DRB configuration and tunnel creation*/ + gtpv1u_gnb_create_tunnel_req_t create_tunnel_req; + memset(&create_tunnel_req, 0, sizeof(gtpv1u_gnb_create_tunnel_req_t)); + req->drbs_to_be_setup = malloc(1*sizeof(f1ap_drb_to_be_setup_t)); + req->drbs_to_be_setup_length = 1; + f1ap_drb_to_be_setup_t *DRBs=req->drbs_to_be_setup; + LOG_D(RRC, "Length of DRB list:%d \n", req->drbs_to_be_setup_length); + DRBs[0].drb_id = 1; + DRBs[0].rlc_mode = RLC_MODE_AM; + DRBs[0].up_ul_tnl[0].tl_address = inet_addr(RC.nrrrc[ctxt.module_id]->eth_params_s.my_addr); + DRBs[0].up_ul_tnl[0].port=RC.nrrrc[ctxt.module_id]->eth_params_s.my_portd; + DRBs[0].up_ul_tnl_length = 1; + DRBs[0].up_dl_tnl[0].tl_address = inet_addr(RC.nrrrc[ctxt.module_id]->eth_params_s.remote_addr); + DRBs[0].up_dl_tnl[0].port=RC.nrrrc[ctxt.module_id]->eth_params_s.remote_portd; + DRBs[0].up_dl_tnl_length = 1; itti_send_msg_to_task (TASK_CU_F1, ctxt.module_id, message_p); } diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 739bad594e..fa1690e450 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -2699,9 +2699,9 @@ nr_rrc_ue_process_ueCapabilityEnquiry( AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n", enc_rval.failed_type->name, enc_rval.encoded); - //if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { + if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { xer_fprint(stdout, &asn_DEF_NR_UL_DCCH_Message, (void *)&ul_dcch_msg); - //} + } LOG_I(NR_RRC, "UECapabilityInformation Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); #ifdef ITTI_SIM diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index 856597cb0e..08d1f5be64 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -815,12 +815,6 @@ static int Gtpv1uHandleGpdu(int h, return GTPNOK; } - /*int offset=8; - - if( msgHdr->E || msgHdr->S ||msgHdr->PN) - offset+=8;*/ - - //Minimum length of GTP-U header if non of the optional fields are present int offset= sizeof(Gtpv1uMsgHeaderT); From 693d687d3fdba898ab544f059f76fef55c13e55b Mon Sep 17 00:00:00 2001 From: matzakos Date: Wed, 6 Apr 2022 10:57:36 +0200 Subject: [PATCH 062/267] Restore nr_l1_helpers.h and dependencies --- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 2 +- openair2/LAYER2/NR_MAC_UE/nr_l1_helpers.c | 2 +- openair2/LAYER2/NR_MAC_UE/nr_l1_helpers.h | 27 ++++++++++++++++++++ openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c | 2 +- 4 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 openair2/LAYER2/NR_MAC_UE/nr_l1_helpers.h diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index b5265767ee..ddddcd09e2 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -50,7 +50,7 @@ #include "executables/softmodem-common.h" #include "executables/nr-uesoftmodem.h" #include "LAYER2/NR_MAC_UE/mac_proto.h" -//#include "LAYER2/NR_MAC_UE/nr_l1_helpers.h" +#include "LAYER2/NR_MAC_UE/nr_l1_helpers.h" //#define DEBUG_PHY_PROC #define NR_PDCCH_SCHED diff --git a/openair2/LAYER2/NR_MAC_UE/nr_l1_helpers.c b/openair2/LAYER2/NR_MAC_UE/nr_l1_helpers.c index be5c103a84..2d704b5c81 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_l1_helpers.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_l1_helpers.c @@ -35,7 +35,7 @@ #include "mac_defs.h" #include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" #include "LAYER2/NR_MAC_UE/mac_proto.h" -//#include "LAYER2/NR_MAC_UE/nr_l1_helpers.h" +#include "LAYER2/NR_MAC_UE/nr_l1_helpers.h" #include "NR_P-Max.h" // Implementation of 6.2.4 Configured ransmitted power diff --git a/openair2/LAYER2/NR_MAC_UE/nr_l1_helpers.h b/openair2/LAYER2/NR_MAC_UE/nr_l1_helpers.h new file mode 100644 index 0000000000..3bfeb29e2e --- /dev/null +++ b/openair2/LAYER2/NR_MAC_UE/nr_l1_helpers.h @@ -0,0 +1,27 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/** \brief Function to compute configured maximum output power according to clause 6.2.4 of 3GPP TS 38.101-1 version 16.5.0 Release 16 + @param Mod_id Module id of UE +*/ +long nr_get_Pcmax(module_id_t mod_id); +/** @}*/ + diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index 4d303f0507..3851ee011d 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -41,7 +41,7 @@ #include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" #include "NR_MAC_COMMON/nr_mac.h" #include "LAYER2/NR_MAC_UE/mac_proto.h" -//#include "LAYER2/NR_MAC_UE/nr_l1_helpers.h" +#include "LAYER2/NR_MAC_UE/nr_l1_helpers.h" #include From 8e58e83be62400a3762a7e080487e4e74bb45395 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Wed, 6 Apr 2022 14:52:34 +0100 Subject: [PATCH 063/267] Remove log --- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 09b32f1a33..532c27e247 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -370,7 +370,6 @@ int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, *rank_indicator = 0; if (ue->frame_parms.nb_antennas_rx == 1 || ue->nr_csi_rs_info->N_ports == 1) { - LOG_I(NR_PHY, "RI = %i\n", *rank_indicator + 1); return 0; } else if( !(ue->frame_parms.nb_antennas_rx == 2 && ue->nr_csi_rs_info->N_ports == 2) ) { LOG_W(NR_PHY, "Rank indicator computation is not implemented for %i x %i system\n", From 66b3fffbf00c63fac96e2e86134666b4301164de Mon Sep 17 00:00:00 2001 From: rmagueta Date: Wed, 6 Apr 2022 17:44:47 +0100 Subject: [PATCH 064/267] Minor improvements --- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 532c27e247..b3325fba47 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -468,13 +468,15 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, uint8_t *i2) { NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; - i1[0] = 1; - i1[1] = 1; - i1[2] = 1; - *i2 = 0; + memset(i1,0,3*sizeof(uint8_t)); + i2[0] = 0; - // TS 38.214: For 2 antenna ports {3000, 3001} and the UE configured with higher layer parameter codebookType set to - // 'typeISinglePanel' each PMI value corresponds to a codebook index given in Table 5.2.2.2.1-1. + // i1 is a three-element vector in the form of [i11 i12 i13], when CodebookType is specified as 'Type1SinglePanel'. + // Note that i13 is not applicable when the number of transmission layers is one of {1, 5, 6, 7, 8}. + // i2, for 'Type1SinglePanel' codebook type, it is a scalar when PMIMode is specified as 'wideband', and when PMIMode + // is specified as 'subband' or when PRGSize, the length of the i2 vector equals to the number of subbands or PRGs. + // Note that when the number of CSI-RS ports is 2, the applicable codebook type is 'Type1SinglePanel'. In this case, + // the precoding matrix is obtained by a single index (i2 field here) based on TS 38.214 Table 5.2.2.2.1-1. // The first column is applicable if the UE is reporting a Rank = 1, whereas the second column is applicable if the // UE is reporting a Rank = 2. @@ -517,8 +519,8 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, } for(int tested_i2 = 0; tested_i2 < 4; tested_i2++) { - if(metric[tested_i2] > metric[*i2]) { - *i2 = tested_i2; + if(metric[tested_i2] > metric[i2[0]]) { + i2[0] = tested_i2; } } @@ -597,10 +599,10 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t ue->nr_csi_rs_info->i1, ue->nr_csi_rs_info->i2); - LOG_I(NR_PHY, "RI = %i, i1 = [%i %i %i], i2 = %i\n", + LOG_I(NR_PHY, "RI = %i, i1 = %i.%i.%i, i2 = %i\n", *ue->nr_csi_rs_info->rank_indicator + 1, ue->nr_csi_rs_info->i1[0], ue->nr_csi_rs_info->i1[1], ue->nr_csi_rs_info->i1[2], - *ue->nr_csi_rs_info->i2); + ue->nr_csi_rs_info->i2[0]); return 0; } From 6e4bbe8f49c9a19e876fa8e065b8a70a4d59d513 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Wed, 6 Apr 2022 18:42:00 +0100 Subject: [PATCH 065/267] PMI computation for rank=2 case --- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index b3325fba47..684de4a462 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -484,7 +484,7 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, return 0; } - if(rank_indicator == 0) { + if(rank_indicator == 0 || rank_indicator == 1) { uint32_t metric[4] = {0}; uint16_t shift = nr_csi_rs_info->log2_maxh + log2_approx(frame_parms->nb_antennas_rx) + log2_approx(csirs_config_pdu->nr_of_rbs) - 1; @@ -518,14 +518,16 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, } } - for(int tested_i2 = 0; tested_i2 < 4; tested_i2++) { - if(metric[tested_i2] > metric[i2[0]]) { - i2[0] = tested_i2; + if(rank_indicator == 0) { + for(int tested_i2 = 0; tested_i2 < 4; tested_i2++) { + if(metric[tested_i2] > metric[i2[0]]) { + i2[0] = tested_i2; + } } + } else { + i2[0] = metric[0]+metric[2] > metric[1]+metric[3] ? 0 : 1; } - } else if(rank_indicator == 1) { - } else { LOG_W(NR_PHY, "PMI computation is not implemented for rank indicator %i\n", rank_indicator); } From bf56e881b2ba458bde7f74d0f53685d56cfe562e Mon Sep 17 00:00:00 2001 From: rmagueta Date: Wed, 6 Apr 2022 18:43:56 +0100 Subject: [PATCH 066/267] Fix log --- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 684de4a462..4e3ac6dd69 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -529,7 +529,8 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, } } else { - LOG_W(NR_PHY, "PMI computation is not implemented for rank indicator %i\n", rank_indicator); + LOG_W(NR_PHY, "PMI computation is not implemented for rank indicator %i\n", rank_indicator+1); + return -1; } return 0; From 596282403856f723ff3396ba527b912e3299adc6 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Thu, 7 Apr 2022 16:34:16 +0200 Subject: [PATCH 067/267] Integrate true reporting of buffer availability of RLC(DU) towards the CU --- openair2/F1AP/f1ap_du_task.c | 2 +- openair2/F1AP/f1ap_itti_messaging.c | 2 +- openair2/LAYER2/nr_rlc/nr_rlc_entity.c | 51 ++++++++++++----------- openair2/LAYER2/nr_rlc/nr_rlc_entity.h | 2 + openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c | 6 +++ openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h | 1 + openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c | 6 +++ openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.h | 1 + openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c | 6 +++ openair2/LAYER2/nr_rlc/nr_rlc_entity_um.h | 1 + openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c | 34 ++++++++++++++- openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h | 6 ++- openair2/RRC/NR/rrc_gNB.c | 2 +- openair3/ocp-gtpu/gtp_itf.cpp | 5 ++- 14 files changed, 94 insertions(+), 31 deletions(-) diff --git a/openair2/F1AP/f1ap_du_task.c b/openair2/F1AP/f1ap_du_task.c index 24a1c44697..4982f7617b 100644 --- a/openair2/F1AP/f1ap_du_task.c +++ b/openair2/F1AP/f1ap_du_task.c @@ -175,7 +175,7 @@ void *F1AP_DU_task(void *arg) { break; case F1AP_UL_RRC_MESSAGE: // to rrc - LOG_I(F1AP, "DU Task Received F1AP_UL_RRC_MESSAGE\n"); + LOG_D(F1AP, "DU Task Received F1AP_UL_RRC_MESSAGE\n"); if (RC.nrrrc && RC.nrrrc[0]->node_type == ngran_gNB_DU) { DU_send_UL_NR_RRC_MESSAGE_TRANSFER(myInstance, diff --git a/openair2/F1AP/f1ap_itti_messaging.c b/openair2/F1AP/f1ap_itti_messaging.c index 21096a6518..e45edcc3a3 100644 --- a/openair2/F1AP/f1ap_itti_messaging.c +++ b/openair2/F1AP/f1ap_itti_messaging.c @@ -32,7 +32,7 @@ void f1ap_itti_send_sctp_data_req(bool isCu, instance_t instance, uint8_t *buffe sctp_data_req->buffer = buffer; sctp_data_req->buffer_length = buffer_length; sctp_data_req->stream = stream; - LOG_I(F1AP, "Sending ITTI message to SCTP Task\n"); + LOG_D(F1AP, "Sending ITTI message to SCTP Task\n"); itti_send_msg_to_task(TASK_SCTP, instance, message_p); } diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity.c index fefe2fc77d..1883bbdd6c 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity.c @@ -77,14 +77,15 @@ nr_rlc_entity_t *new_nr_rlc_entity_am( ret->sn_modulus = 1 << ret->sn_field_length; ret->window_size = ret->sn_modulus / 2; - ret->common.recv_pdu = nr_rlc_entity_am_recv_pdu; - ret->common.buffer_status = nr_rlc_entity_am_buffer_status; - ret->common.generate_pdu = nr_rlc_entity_am_generate_pdu; - ret->common.recv_sdu = nr_rlc_entity_am_recv_sdu; - ret->common.set_time = nr_rlc_entity_am_set_time; - ret->common.discard_sdu = nr_rlc_entity_am_discard_sdu; - ret->common.reestablishment = nr_rlc_entity_am_reestablishment; - ret->common.delete = nr_rlc_entity_am_delete; + ret->common.recv_pdu = nr_rlc_entity_am_recv_pdu; + ret->common.buffer_status = nr_rlc_entity_am_buffer_status; + ret->common.generate_pdu = nr_rlc_entity_am_generate_pdu; + ret->common.recv_sdu = nr_rlc_entity_am_recv_sdu; + ret->common.set_time = nr_rlc_entity_am_set_time; + ret->common.discard_sdu = nr_rlc_entity_am_discard_sdu; + ret->common.reestablishment = nr_rlc_entity_am_reestablishment; + ret->common.delete = nr_rlc_entity_am_delete; + ret->common.available_tx_space = nr_rlc_entity_am_available_tx_space; ret->common.deliver_sdu = deliver_sdu; ret->common.deliver_sdu_data = deliver_sdu_data; @@ -127,14 +128,15 @@ nr_rlc_entity_t *new_nr_rlc_entity_um( ret->sn_modulus = 1 << ret->sn_field_length; ret->window_size = ret->sn_modulus / 2; - ret->common.recv_pdu = nr_rlc_entity_um_recv_pdu; - ret->common.buffer_status = nr_rlc_entity_um_buffer_status; - ret->common.generate_pdu = nr_rlc_entity_um_generate_pdu; - ret->common.recv_sdu = nr_rlc_entity_um_recv_sdu; - ret->common.set_time = nr_rlc_entity_um_set_time; - ret->common.discard_sdu = nr_rlc_entity_um_discard_sdu; - ret->common.reestablishment = nr_rlc_entity_um_reestablishment; - ret->common.delete = nr_rlc_entity_um_delete; + ret->common.recv_pdu = nr_rlc_entity_um_recv_pdu; + ret->common.buffer_status = nr_rlc_entity_um_buffer_status; + ret->common.generate_pdu = nr_rlc_entity_um_generate_pdu; + ret->common.recv_sdu = nr_rlc_entity_um_recv_sdu; + ret->common.set_time = nr_rlc_entity_um_set_time; + ret->common.discard_sdu = nr_rlc_entity_um_discard_sdu; + ret->common.reestablishment = nr_rlc_entity_um_reestablishment; + ret->common.delete = nr_rlc_entity_um_delete; + ret->common.available_tx_space = nr_rlc_entity_um_available_tx_space; ret->common.deliver_sdu = deliver_sdu; ret->common.deliver_sdu_data = deliver_sdu_data; @@ -158,14 +160,15 @@ nr_rlc_entity_t *new_nr_rlc_entity_tm( ret->tx_maxsize = tx_maxsize; - ret->common.recv_pdu = nr_rlc_entity_tm_recv_pdu; - ret->common.buffer_status = nr_rlc_entity_tm_buffer_status; - ret->common.generate_pdu = nr_rlc_entity_tm_generate_pdu; - ret->common.recv_sdu = nr_rlc_entity_tm_recv_sdu; - ret->common.set_time = nr_rlc_entity_tm_set_time; - ret->common.discard_sdu = nr_rlc_entity_tm_discard_sdu; - ret->common.reestablishment = nr_rlc_entity_tm_reestablishment; - ret->common.delete = nr_rlc_entity_tm_delete; + ret->common.recv_pdu = nr_rlc_entity_tm_recv_pdu; + ret->common.buffer_status = nr_rlc_entity_tm_buffer_status; + ret->common.generate_pdu = nr_rlc_entity_tm_generate_pdu; + ret->common.recv_sdu = nr_rlc_entity_tm_recv_sdu; + ret->common.set_time = nr_rlc_entity_tm_set_time; + ret->common.discard_sdu = nr_rlc_entity_tm_discard_sdu; + ret->common.reestablishment = nr_rlc_entity_tm_reestablishment; + ret->common.delete = nr_rlc_entity_tm_delete; + ret->common.available_tx_space = nr_rlc_entity_tm_available_tx_space; ret->common.deliver_sdu = deliver_sdu; ret->common.deliver_sdu_data = deliver_sdu_data; diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity.h b/openair2/LAYER2/nr_rlc/nr_rlc_entity.h index b9b638fe07..5cd3bee650 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity.h @@ -50,6 +50,8 @@ typedef struct nr_rlc_entity_t { void (*delete)(struct nr_rlc_entity_t *entity); + int (*available_tx_space)(struct nr_rlc_entity_t *entity); + /* callbacks provided to the RLC module */ void (*deliver_sdu)(void *deliver_sdu_data, struct nr_rlc_entity_t *entity, char *buf, int size); diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c index af8cb5715a..ba7a4a82ee 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c @@ -1887,3 +1887,9 @@ void nr_rlc_entity_am_delete(nr_rlc_entity_t *_entity) clear_entity(entity); free(entity); } + +int nr_rlc_entity_am_available_tx_space(nr_rlc_entity_t *_entity) +{ + nr_rlc_entity_am_t *entity = (nr_rlc_entity_am_t *)_entity; + return entity->tx_maxsize - entity->tx_size; +} diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h index 453fe87026..d36876ed72 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h @@ -102,5 +102,6 @@ void nr_rlc_entity_am_set_time(nr_rlc_entity_t *entity, uint64_t now); void nr_rlc_entity_am_discard_sdu(nr_rlc_entity_t *_entity, int sdu_id); void nr_rlc_entity_am_reestablishment(nr_rlc_entity_t *_entity); void nr_rlc_entity_am_delete(nr_rlc_entity_t *entity); +int nr_rlc_entity_am_available_tx_space(nr_rlc_entity_t *entity); #endif /* _NR_RLC_ENTITY_AM_H_ */ diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c index 75408276d1..f85edbba0f 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c @@ -174,3 +174,9 @@ void nr_rlc_entity_tm_delete(nr_rlc_entity_t *_entity) clear_entity(entity); free(entity); } + +int nr_rlc_entity_tm_available_tx_space(nr_rlc_entity_t *_entity) +{ + nr_rlc_entity_tm_t *entity = (nr_rlc_entity_tm_t *)_entity; + return entity->tx_maxsize - entity->tx_size; +} diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.h b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.h index 7c8c7e40a0..7918703799 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.h @@ -51,5 +51,6 @@ void nr_rlc_entity_tm_set_time(nr_rlc_entity_t *entity, uint64_t now); void nr_rlc_entity_tm_discard_sdu(nr_rlc_entity_t *_entity, int sdu_id); void nr_rlc_entity_tm_reestablishment(nr_rlc_entity_t *_entity); void nr_rlc_entity_tm_delete(nr_rlc_entity_t *entity); +int nr_rlc_entity_tm_available_tx_space(nr_rlc_entity_t *entity); #endif /* _NR_RLC_ENTITY_TM_H_ */ diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c index b34a7dc894..5f2fd592a0 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c @@ -695,3 +695,9 @@ void nr_rlc_entity_um_delete(nr_rlc_entity_t *_entity) clear_entity(entity); free(entity); } + +int nr_rlc_entity_um_available_tx_space(nr_rlc_entity_t *_entity) +{ + nr_rlc_entity_um_t *entity = (nr_rlc_entity_um_t *)_entity; + return entity->tx_maxsize - entity->tx_size; +} diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.h b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.h index 21063a1ea1..c40e72ada1 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.h @@ -75,5 +75,6 @@ void nr_rlc_entity_um_set_time(nr_rlc_entity_t *entity, uint64_t now); void nr_rlc_entity_um_discard_sdu(nr_rlc_entity_t *_entity, int sdu_id); void nr_rlc_entity_um_reestablishment(nr_rlc_entity_t *_entity); void nr_rlc_entity_um_delete(nr_rlc_entity_t *entity); +int nr_rlc_entity_um_available_tx_space(nr_rlc_entity_t *entity); #endif /* _NR_RLC_ENTITY_UM_H_ */ diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index e033aa33b7..dea72d6e42 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -101,6 +101,7 @@ void nr_drb_config(struct NR_RLC_Config *rlc_Config, NR_RLC_Config_PR rlc_config switch (rlc_config_pr){ case NR_RLC_Config_PR_um_Bi_Directional: // RLC UM Bi-directional Bearer configuration + LOG_I(RLC, "RLC UM Bi-directional Bearer configuration selected \n"); rlc_Config->choice.um_Bi_Directional = calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional)); rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength = calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength)); *rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength = NR_SN_FieldLengthUM_size12; @@ -397,6 +398,35 @@ rlc_op_status_t rlc_data_req (const protocol_ctxt_t *const ctxt_pP, return RLC_OP_STATUS_OK; } +int nr_rlc_get_available_tx_space( + const rnti_t rntiP, + const logical_chan_id_t channel_idP) +{ + nr_rlc_ue_t *ue; + nr_rlc_entity_t *rb; + int ret; + + nr_rlc_manager_lock(nr_rlc_ue_manager); + ue = nr_rlc_manager_get_ue(nr_rlc_ue_manager, rntiP); + + switch (channel_idP) { + case 1 ... 3: rb = ue->srb[channel_idP - 1]; break; + case 4 ... 8: rb = ue->drb[channel_idP - 1]; break; + default: rb = NULL; break; + } + + if (rb != NULL) { + ret = rb->available_tx_space(rb); + } else { + LOG_E(RLC, "[%s] Radio Bearer (channel ID %d) is NULL for UE with rntiP %x\n", __FUNCTION__, channel_idP, rntiP); + ret = -1; + } + + nr_rlc_manager_unlock(nr_rlc_ue_manager); + + return ret; +} + int rlc_module_init(int enb_flag) { static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; @@ -850,11 +880,11 @@ static void add_drb_um(int rnti, struct NR_DRB_ToAddMod *s, NR_RLC_BearerConfig_ exit(1); } - if (channel_id != drb_id + 3) { + /*if (channel_id != drb_id + 3) { LOG_E(RLC, "%s:%d:%s: todo, remove this limitation\n", __FILE__, __LINE__, __FUNCTION__); exit(1); - } + }*/ logical_channel_group = *l->ul_SpecificParameters->logicalChannelGroup; diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h index 6b3c228163..92fbba9bec 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h @@ -46,4 +46,8 @@ void nr_rlc_bearer_init(NR_RLC_BearerConfig_t *RLC_BearerConfig, NR_RLC_BearerCo void nr_drb_config(struct NR_RLC_Config *rlc_Config, NR_RLC_Config_PR rlc_config_pr); -void nr_rlc_bearer_init_ul_spec(struct NR_LogicalChannelConfig *mac_LogicalChannelConfig); \ No newline at end of file +void nr_rlc_bearer_init_ul_spec(struct NR_LogicalChannelConfig *mac_LogicalChannelConfig); + +int nr_rlc_get_available_tx_space( + const rnti_t rntiP, + const logical_chan_id_t channel_idP); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index d7ff9492a5..11718d49b2 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -3497,7 +3497,7 @@ static void rrc_DU_process_ue_context_modification_request(MessageDef *msg_p, co gtpv1u_DU_buffer_report_req_t *req=>PV1U_DU_BUFFER_REPORT_REQ(msg); req->pdusession_id = drb_id; req->rnti = rnti; - req->buffer_availability = 1000000; //Hardcoding to be removed and read the actual RLC buffer availability instead + req->buffer_availability = 10000000; //Hardcoding to be removed and read the actual RLC buffer availability instead extern instance_t DUuniqInstance; itti_send_msg_to_task(TASK_GTPV1_U, DUuniqInstance, msg); diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index 20db486561..822825c75a 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -17,6 +17,7 @@ extern "C" { #include #include #include +#include #include "openair2/SDAP/nr_sdap/nr_sdap_gnb.h" //#include @@ -999,6 +1000,8 @@ static int Gtpv1uHandleGpdu(int h, LOG_E(GTPU,"[%d] down layer refused incoming packet\n", h); if(NR_PDCP_PDU_SN > 0 && NR_PDCP_PDU_SN %5 ==0){ LOG_D (GTPU, "Create and send DL DATA Delivery status for the previously received PDU, NR_PDCP_PDU_SN: %u \n", NR_PDCP_PDU_SN); + int rlc_tx_buffer_space = nr_rlc_get_available_tx_space(ctxt.rnti, rb_id); + LOG_D(GTPU, "Available buffer size in RLC for Tx: %d \n", rlc_tx_buffer_space); /*Total size of DDD_status PDU = 1 octet to report extension header length * size of mandatory part + 3 octets for highest transmitted/delivered PDCP SN * 1 octet for padding + 1 octet for next extension header type, @@ -1010,7 +1013,7 @@ static int Gtpv1uHandleGpdu(int h, DlDataDeliveryStatus.deliveredPdcpSn = 0; DlDataDeliveryStatus.transmittedPdcpSn= 1; DlDataDeliveryStatus.pduType = 1; - DlDataDeliveryStatus.drbBufferSize = htonl(1000000); //hardcoded for now but normally we should extract it from RLC + DlDataDeliveryStatus.drbBufferSize = htonl(rlc_tx_buffer_space); //htonl(10000000); //hardcoded for now but normally we should extract it from RLC memcpy(extensionHeader->buffer+1, &DlDataDeliveryStatus, sizeof(DlDataDeliveryStatus_flagsT)); uint8_t offset = sizeof(DlDataDeliveryStatus_flagsT)+1; From 7286552aa5eda07958f2029e6685c5d89fb58a12 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Thu, 7 Apr 2022 18:58:18 +0100 Subject: [PATCH 068/267] Improvements in PMI computation to allow computation CQI more easily --- openair1/PHY/INIT/nr_init_ue.c | 1 + openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 60 ++++++++++++++++++++------- openair1/PHY/defs_nr_common.h | 2 + 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index e5402c1c04..2e32b7e3e6 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -349,6 +349,7 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) ue->nr_csi_rs_info->rank_indicator = (uint8_t*)malloc16_clear(sizeof(uint8_t)); ue->nr_csi_rs_info->i1 = (uint8_t*)malloc16_clear(3*sizeof(uint8_t)); ue->nr_csi_rs_info->i2 = (uint8_t*)malloc16_clear(sizeof(uint8_t)); + ue->nr_csi_rs_info->precoded_sinr = (uint32_t*)malloc16_clear(sizeof(uint32_t)); ue->nr_csi_rs_info->csi_rs_generated_signal = (int32_t **)malloc16(NR_MAX_NB_PORTS * sizeof(int32_t *) ); for (i=0; inr_csi_rs_info->csi_rs_generated_signal[i] = (int32_t *) malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t)); diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 4e3ac6dd69..7eb0b68307 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -206,6 +206,7 @@ int nr_csi_rs_channel_estimation(PHY_VARS_NR_UE *ue, int dataF_offset = proc->nr_slot_rx*ue->frame_parms.samples_per_slot_wCP; *noise_power = 0; int maxh = 0; + int count = 0; for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) { @@ -291,6 +292,8 @@ int nr_csi_rs_channel_estimation(PHY_VARS_NR_UE *ue, continue; } + count++; + uint16_t k = (frame_parms->first_carrier_offset + rb*NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size; for(uint16_t port_tx = 0; port_txN_ports; port_tx++) { int16_t *csi_rs_ls_estimated_channel = (int16_t*)&nr_csi_rs_info->csi_rs_ls_estimated_channel[ant_rx][port_tx][k]; @@ -350,6 +353,7 @@ int nr_csi_rs_channel_estimation(PHY_VARS_NR_UE *ue, *noise_power /= (frame_parms->nb_antennas_rx*nr_csi_rs_info->N_ports); nr_csi_rs_info->log2_maxh = log2_approx(maxh-1); + nr_csi_rs_info->log2_re = log2_approx(count-1); #ifdef NR_CSIRS_DEBUG LOG_I(NR_PHY, "Noise power estimation based on CSI-RS: %i\n", *noise_power); @@ -463,9 +467,11 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, nr_csi_rs_info_t *nr_csi_rs_info, int32_t ***csi_rs_estimated_channel_freq, + uint32_t noise_power, uint8_t rank_indicator, uint8_t *i1, - uint8_t *i2) { + uint8_t *i2, + uint32_t *precoded_sinr) { NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; memset(i1,0,3*sizeof(uint8_t)); @@ -480,13 +486,18 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, // The first column is applicable if the UE is reporting a Rank = 1, whereas the second column is applicable if the // UE is reporting a Rank = 2. - if(ue->nr_csi_rs_info->N_ports == 1) { + if(nr_csi_rs_info->N_ports == 1 || noise_power == 0) { return 0; } if(rank_indicator == 0 || rank_indicator == 1) { - uint32_t metric[4] = {0}; + int32_t sum_re[4] = {0}; + int32_t sum_im[4] = {0}; + int32_t sum2_re[4] = {0}; + int32_t sum2_im[4] = {0}; + int32_t tested_precoded_sinr[4] = {0}; + uint16_t shift = nr_csi_rs_info->log2_maxh + log2_approx(frame_parms->nb_antennas_rx) + log2_approx(csirs_config_pdu->nr_of_rbs) - 1; for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) { @@ -497,35 +508,54 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, uint16_t k = (frame_parms->first_carrier_offset + rb * NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size; for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) { + int16_t *csi_rs_estimated_channel_p0 = (int16_t *) &csi_rs_estimated_channel_freq[ant_rx][0][k]; int16_t *csi_rs_estimated_channel_p1 = (int16_t *) &csi_rs_estimated_channel_freq[ant_rx][1][k]; // H_p0 + 1*H_p1 = (H_p0_re + H_p1_re) + 1j*(H_p0_im + H_p1_im) - metric[0] += ((csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[0]) - + (csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[1]))>>shift; + sum_re[0] += (csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[0]); + sum_im[0] += (csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[1]); + sum2_re[0] += ((csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[0]))>>nr_csi_rs_info->log2_re; + sum2_im[0] += ((csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[1]))>>nr_csi_rs_info->log2_re; // H_p0 + 1j*H_p1 = (H_p0_re - H_p1_im) + 1j*(H_p0_im + H_p1_re) - metric[1] += ((csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[1]) - + (csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[0]))>>shift; + sum_re[1] += (csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[1]); + sum_im[1] += (csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[0]); + sum2_re[1] += ((csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[1]))>>nr_csi_rs_info->log2_re; + sum2_im[1] += ((csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[0]))>>nr_csi_rs_info->log2_re; // H_p0 - 1*H_p1 = (H_p0_re - H_p1_re) + 1j*(H_p0_im - H_p1_im) - metric[2] += ((csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[0]) - + (csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[1]))>>shift; + sum_re[2] += (csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[0]); + sum_im[2] += (csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[1]); + sum2_re[2] += ((csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[0]))>>nr_csi_rs_info->log2_re; + sum2_im[2] += ((csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[1]))>>nr_csi_rs_info->log2_re; // H_p0 - 1j*H_p1 = (H_p0_re + H_p1_im) + 1j*(H_p0_im - H_p1_re) - metric[3] += ((csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[1]) - + (csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[0]))>>shift; + sum_re[3] += (csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[1]); + sum_im[3] += (csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[0]); + sum2_re[3] += ((csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[1]))>>nr_csi_rs_info->log2_re; + sum2_im[3] += ((csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[0]))>>nr_csi_rs_info->log2_re; } } + // We should perform >>nr_csi_rs_info->log2_re here for all terms, but since sum2_re and sum2_im can be high values, + // we performed this above. + for(int p = 0; p<4; p++) { + int32_t power_re = sum2_re[p] - (sum_re[p]>>nr_csi_rs_info->log2_re)*(sum_re[p]>>nr_csi_rs_info->log2_re); + int32_t power_im = sum2_im[p] - (sum_im[p]>>nr_csi_rs_info->log2_re)*(sum_im[p]>>nr_csi_rs_info->log2_re); + tested_precoded_sinr[p] = (power_re+power_im)/(int32_t)noise_power; + } + if(rank_indicator == 0) { for(int tested_i2 = 0; tested_i2 < 4; tested_i2++) { - if(metric[tested_i2] > metric[i2[0]]) { + if(tested_precoded_sinr[tested_i2] > tested_precoded_sinr[i2[0]]) { i2[0] = tested_i2; } } + *precoded_sinr = tested_precoded_sinr[i2[0]]; } else { - i2[0] = metric[0]+metric[2] > metric[1]+metric[3] ? 0 : 1; + i2[0] = tested_precoded_sinr[0]+tested_precoded_sinr[2] > tested_precoded_sinr[1]+tested_precoded_sinr[3] ? 0 : 1; + *precoded_sinr = (tested_precoded_sinr[i2[0]] + tested_precoded_sinr[i2[0]+2])>>1; } } else { @@ -598,9 +628,11 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t csirs_config_pdu, ue->nr_csi_rs_info, ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, + *ue->nr_csi_rs_info->noise_power, *ue->nr_csi_rs_info->rank_indicator, ue->nr_csi_rs_info->i1, - ue->nr_csi_rs_info->i2); + ue->nr_csi_rs_info->i2, + ue->nr_csi_rs_info->precoded_sinr); LOG_I(NR_PHY, "RI = %i, i1 = %i.%i.%i, i2 = %i\n", *ue->nr_csi_rs_info->rank_indicator + 1, diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index c1157e452f..4616a87f16 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -261,6 +261,7 @@ typedef struct { int32_t **csi_rs_received_signal; int32_t ***csi_rs_ls_estimated_channel; int32_t ***csi_rs_estimated_channel_freq; + int16_t log2_re; int16_t log2_maxh; int32_t csi_rs_estimated_conjch_ch[4][4][4][4][NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32))); int32_t csi_rs_estimated_A_MF[2][2][NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32))); @@ -271,6 +272,7 @@ typedef struct { uint8_t *rank_indicator; uint8_t *i1; uint8_t *i2; + uint32_t *precoded_sinr; } nr_csi_rs_info_t; typedef struct NR_DL_FRAME_PARMS NR_DL_FRAME_PARMS; From d6a155a803dca272099af4aa3e0657074eacb4e4 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Thu, 7 Apr 2022 19:30:33 +0100 Subject: [PATCH 069/267] SINR in dB --- openair1/PHY/INIT/nr_init_ue.c | 3 ++- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 27 +++++++++++++++++++-------- openair1/PHY/defs_nr_common.h | 3 ++- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 2e32b7e3e6..1d44475d81 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -349,7 +349,8 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) ue->nr_csi_rs_info->rank_indicator = (uint8_t*)malloc16_clear(sizeof(uint8_t)); ue->nr_csi_rs_info->i1 = (uint8_t*)malloc16_clear(3*sizeof(uint8_t)); ue->nr_csi_rs_info->i2 = (uint8_t*)malloc16_clear(sizeof(uint8_t)); - ue->nr_csi_rs_info->precoded_sinr = (uint32_t*)malloc16_clear(sizeof(uint32_t)); + ue->nr_csi_rs_info->precoded_sinr_dB = (uint32_t*)malloc16_clear(sizeof(uint32_t)); + ue->nr_csi_rs_info->cqi = (uint8_t*)malloc16_clear(sizeof(uint8_t)); ue->nr_csi_rs_info->csi_rs_generated_signal = (int32_t **)malloc16(NR_MAX_NB_PORTS * sizeof(int32_t *) ); for (i=0; inr_csi_rs_info->csi_rs_generated_signal[i] = (int32_t *) malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t)); diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 7eb0b68307..4e16a63302 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -471,7 +471,7 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, uint8_t rank_indicator, uint8_t *i1, uint8_t *i2, - uint32_t *precoded_sinr) { + uint32_t *precoded_sinr_dB) { NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; memset(i1,0,3*sizeof(uint8_t)); @@ -498,8 +498,6 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, int32_t sum2_im[4] = {0}; int32_t tested_precoded_sinr[4] = {0}; - uint16_t shift = nr_csi_rs_info->log2_maxh + log2_approx(frame_parms->nb_antennas_rx) + log2_approx(csirs_config_pdu->nr_of_rbs) - 1; - for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) { if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) { @@ -552,10 +550,10 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, i2[0] = tested_i2; } } - *precoded_sinr = tested_precoded_sinr[i2[0]]; + *precoded_sinr_dB = dB_fixed(tested_precoded_sinr[i2[0]]); } else { i2[0] = tested_precoded_sinr[0]+tested_precoded_sinr[2] > tested_precoded_sinr[1]+tested_precoded_sinr[3] ? 0 : 1; - *precoded_sinr = (tested_precoded_sinr[i2[0]] + tested_precoded_sinr[i2[0]+2])>>1; + *precoded_sinr_dB = dB_fixed((tested_precoded_sinr[i2[0]] + tested_precoded_sinr[i2[0]+2]))>>1; } } else { @@ -566,6 +564,14 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, return 0; } +int nr_csi_rs_cqi_estimation(uint32_t precoded_sinr, + uint8_t *cqi) { + + *cqi = 0; + + return 0; +} + int nr_ue_csi_im_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t gNB_id) { return 0; } @@ -632,12 +638,17 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t *ue->nr_csi_rs_info->rank_indicator, ue->nr_csi_rs_info->i1, ue->nr_csi_rs_info->i2, - ue->nr_csi_rs_info->precoded_sinr); + ue->nr_csi_rs_info->precoded_sinr_dB); - LOG_I(NR_PHY, "RI = %i, i1 = %i.%i.%i, i2 = %i\n", + nr_csi_rs_cqi_estimation(*ue->nr_csi_rs_info->precoded_sinr_dB, + ue->nr_csi_rs_info->cqi); + + LOG_I(NR_PHY, "RI = %i, i1 = %i.%i.%i, i2 = %i. SINR = %i dB, CQI = %i\n", *ue->nr_csi_rs_info->rank_indicator + 1, ue->nr_csi_rs_info->i1[0], ue->nr_csi_rs_info->i1[1], ue->nr_csi_rs_info->i1[2], - ue->nr_csi_rs_info->i2[0]); + ue->nr_csi_rs_info->i2[0], + *ue->nr_csi_rs_info->precoded_sinr_dB, + *ue->nr_csi_rs_info->cqi); return 0; } diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 4616a87f16..0e90c2087b 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -272,7 +272,8 @@ typedef struct { uint8_t *rank_indicator; uint8_t *i1; uint8_t *i2; - uint32_t *precoded_sinr; + uint32_t *precoded_sinr_dB; + uint8_t *cqi; } nr_csi_rs_info_t; typedef struct NR_DL_FRAME_PARMS NR_DL_FRAME_PARMS; From 8ffecf4bdf350c1ea701e2293ce7c493a6b67dee Mon Sep 17 00:00:00 2001 From: rmagueta Date: Thu, 7 Apr 2022 19:58:56 +0100 Subject: [PATCH 070/267] CQI computation --- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 29 ++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 4e16a63302..ad80261aa2 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -569,6 +569,33 @@ int nr_csi_rs_cqi_estimation(uint32_t precoded_sinr, *cqi = 0; + // Default SINR table for an AWGN channel for SISO scenario, considering 0.1 BLER condition and TS 38.214 Table 5.2.2.1-2 + if(precoded_sinr>0 && precoded_sinr<=2) { + *cqi = 4; + } else if(precoded_sinr==3) { + *cqi = 5; + } else if(precoded_sinr>3 && precoded_sinr<=5) { + *cqi = 6; + } else if(precoded_sinr>5 && precoded_sinr<=7) { + *cqi = 7; + } else if(precoded_sinr>7 && precoded_sinr<=9) { + *cqi = 8; + } else if(precoded_sinr==10) { + *cqi = 9; + } else if(precoded_sinr>10 && precoded_sinr<=12) { + *cqi = 10; + } else if(precoded_sinr>12 && precoded_sinr<=15) { + *cqi = 11; + } else if(precoded_sinr==16) { + *cqi = 12; + } else if(precoded_sinr>16 && precoded_sinr<=18) { + *cqi = 13; + } else if(precoded_sinr==19) { + *cqi = 14; + } else if(precoded_sinr>19) { + *cqi = 15; + } + return 0; } @@ -643,7 +670,7 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t nr_csi_rs_cqi_estimation(*ue->nr_csi_rs_info->precoded_sinr_dB, ue->nr_csi_rs_info->cqi); - LOG_I(NR_PHY, "RI = %i, i1 = %i.%i.%i, i2 = %i. SINR = %i dB, CQI = %i\n", + LOG_I(NR_PHY, "RI = %i, i1 = %i.%i.%i, i2 = %i, SINR = %i dB, CQI = %i\n", *ue->nr_csi_rs_info->rank_indicator + 1, ue->nr_csi_rs_info->i1[0], ue->nr_csi_rs_info->i1[1], ue->nr_csi_rs_info->i1[2], ue->nr_csi_rs_info->i2[0], From bfc7c1b36132105858fd1404e8f67ca6611f457c Mon Sep 17 00:00:00 2001 From: matzakos Date: Mon, 11 Apr 2022 19:35:05 +0200 Subject: [PATCH 071/267] Remove bad return before unlocking mutex in pdcp UL indication --- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 78c2dbc34c..bcef0d5e23 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -276,8 +276,6 @@ static void do_pdcp_data_ind( } else { LOG_E(PDCP, "%s:%d:%s: no RB found (rb_id %ld, srb_flag %d)\n", __FILE__, __LINE__, __FUNCTION__, rb_id, srb_flagP); - return; - } nr_pdcp_manager_unlock(nr_pdcp_ue_manager); From 47c9ded00714158a66774a7ac2079cb96cdccbe6 Mon Sep 17 00:00:00 2001 From: matzakos Date: Mon, 11 Apr 2022 19:53:36 +0200 Subject: [PATCH 072/267] Use higher data type to store the length of UE capability RAT container --- openair2/COMMON/f1ap_messages_types.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index 4a0d3eb411..92208c2b77 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -345,11 +345,11 @@ typedef struct f1ap_rb_failed_to_be_setup_s { typedef struct cu_to_du_rrc_information_s { uint8_t * cG_ConfigInfo; - uint8_t cG_ConfigInfo_length; + uint32_t cG_ConfigInfo_length; uint8_t * uE_CapabilityRAT_ContainerList; - uint8_t uE_CapabilityRAT_ContainerList_length; + uint32_t uE_CapabilityRAT_ContainerList_length; uint8_t * measConfig; - uint8_t measConfig_length; + uint32_t measConfig_length; }cu_to_du_rrc_information_t; typedef struct du_to_du_rrc_information_s { From 04b234c8784a85e38d4dd261c281f66b190df209 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Tue, 12 Apr 2022 19:06:02 +0100 Subject: [PATCH 073/267] Send CSI-RS measurements from PHY to MAC at UE --- .../nfapi/public_inc/fapi_nr_ue_constants.h | 1 + .../nfapi/public_inc/fapi_nr_ue_interface.h | 11 +++++++---- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 17 +++++++++++++++++ openair1/SCHED_NR_UE/defs.h | 2 +- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 10 +++++++--- openair1/SIMULATION/NR_PHY/nr_dummy_functions.c | 2 +- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 3 +++ openair2/LAYER2/NR_MAC_UE/mac_proto.h | 1 + openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 10 ++++++++++ openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c | 12 +++++++++++- 10 files changed, 59 insertions(+), 10 deletions(-) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h index 7fb42e566a..6524fcb396 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h @@ -19,6 +19,7 @@ #define FAPI_NR_RX_PDU_TYPE_DLSCH 0x03 #define FAPI_NR_DCI_IND 0x04 #define FAPI_NR_RX_PDU_TYPE_RAR 0x05 +#define FAPI_NR_CSIRS_IND 0x06 #define FAPI_NR_SIBS_MASK_SIB1 0x1 diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index 725c389070..e67897b44d 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -36,9 +36,6 @@ */ - - - typedef struct { uint8_t uci_format; uint8_t uci_channel; @@ -50,7 +47,12 @@ typedef struct { uint32_t sr; } fapi_nr_uci_pdu_rel15_t; - +typedef struct { + uint8_t *rank_indicator; + uint8_t *i1; + uint8_t *i2; + uint8_t *cqi; +} fapi_nr_csirs_measurements_t; typedef struct { /// frequency_domain_resource; @@ -130,6 +132,7 @@ typedef struct { fapi_nr_pdsch_pdu_t pdsch_pdu; fapi_nr_ssb_pdu_t ssb_pdu; fapi_nr_sib_pdu_t sib_pdu; + fapi_nr_csirs_measurements_t csirs_measurements; }; } fapi_nr_rx_indication_body_t; diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 77b611d73c..0b63c4a149 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -676,5 +676,22 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t *ue->nr_csi_rs_info->precoded_sinr_dB, *ue->nr_csi_rs_info->cqi); + // Send CSI measurements to MAC + fapi_nr_csirs_measurements_t csirs_measurements; + csirs_measurements.rank_indicator = ue->nr_csi_rs_info->rank_indicator; + csirs_measurements.i1 = ue->nr_csi_rs_info->i1; + csirs_measurements.i2 = ue->nr_csi_rs_info->i2; + csirs_measurements.cqi = ue->nr_csi_rs_info->cqi; + nr_downlink_indication_t *dl_indication = calloc(sizeof(*dl_indication),1); + fapi_nr_rx_indication_t *rx_ind = calloc(sizeof(*rx_ind),1); + nr_fill_dl_indication(dl_indication, NULL, rx_ind, proc, ue, gNB_id); + nr_fill_rx_indication(rx_ind, FAPI_NR_CSIRS_IND, gNB_id, ue, NULL, NULL, 1, proc, (void *)&csirs_measurements); + if (ue->if_inst && ue->if_inst->dl_indication) { + ue->if_inst->dl_indication(dl_indication, NULL); + } else { + free(dl_indication); + free(rx_ind); + } + return 0; } diff --git a/openair1/SCHED_NR_UE/defs.h b/openair1/SCHED_NR_UE/defs.h index c449dba159..39faaa0cb3 100644 --- a/openair1/SCHED_NR_UE/defs.h +++ b/openair1/SCHED_NR_UE/defs.h @@ -402,7 +402,7 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind, NR_UE_DLSCH_t *dlsch1, uint16_t n_pdus, UE_nr_rxtx_proc_t *proc, - void * typeSpecific); + void *typeSpecific); bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 262acdec3a..59b08d9823 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -118,9 +118,8 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind, NR_UE_DLSCH_t *dlsch0, NR_UE_DLSCH_t *dlsch1, uint16_t n_pdus, - UE_nr_rxtx_proc_t *proc, - void * typeSpecific){ - + UE_nr_rxtx_proc_t *proc, + void *typeSpecific){ NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; @@ -174,6 +173,11 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind, rx_ind->rx_indication_body[n_pdus - 1].ssb_pdu.ssb_start_subcarrier = frame_parms->ssb_start_subcarrier; rx_ind->rx_indication_body[n_pdus - 1].ssb_pdu.rsrp_dBm = ue->measurements.rsrp_dBm[gNB_id]; break; + case FAPI_NR_CSIRS_IND: + memcpy(&rx_ind->rx_indication_body[n_pdus - 1].csirs_measurements, + (fapi_nr_csirs_measurements_t*)typeSpecific, + sizeof(*(fapi_nr_csirs_measurements_t*)typeSpecific)); + break; default: break; } diff --git a/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c b/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c index 351c2f33c4..de715214b9 100644 --- a/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c +++ b/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c @@ -37,4 +37,4 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind, NR_UE_DLSCH_t *dlsch1, uint16_t n_pdus, UE_nr_rxtx_proc_t *proc, - void * typeSpecific ) {} + void *typeSpecific ) {} diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index fc2c2d2c8b..09153e6f13 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -399,6 +399,9 @@ typedef struct { /// measured SSB RSRP in dBm short ssb_rsrp_dBm; + /// measurements from CSI-RS + fapi_nr_csirs_measurements_t csirs_measurements; + /// Last NDI of UL HARQ processes uint8_t UL_ndi[NR_MAX_HARQ_PROCESSES]; /// first ULTX of UL HARQ processes diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 3e4d53b985..c57c427f14 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -193,6 +193,7 @@ int nr_get_sf_retxBSRTimer(uint8_t retxBSR_Timer); int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, frame_t frame, int slot, dci_pdu_rel15_t *dci, fapi_nr_dci_indication_pdu_t *dci_ind); int nr_ue_process_dci_indication_pdu(module_id_t module_id, int cc_id, int gNB_index, frame_t frame, int slot, fapi_nr_dci_indication_pdu_t *dci); +int8_t nr_ue_process_csirs_measurements(module_id_t module_id, frame_t frame, int slot, fapi_nr_csirs_measurements_t *csirs_measurements); uint32_t get_ssb_frame(uint32_t test); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 192fb25405..220dc799e5 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -1371,6 +1371,16 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr } +int8_t nr_ue_process_csirs_measurements(module_id_t module_id, + frame_t frame, + int slot, + fapi_nr_csirs_measurements_t *csirs_measurements) { + LOG_D(NR_MAC,"(%d.%d) Received CSI-RS measurements\n", frame, slot); + NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); + memcpy(&mac->csirs_measurements, csirs_measurements, sizeof(*csirs_measurements)); + return 0; +} + void set_harq_status(NR_UE_MAC_INST_t *mac, uint8_t pucch_id, uint8_t harq_id, diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c index 26c60fbb9b..30aa921765 100644 --- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c @@ -1112,6 +1112,10 @@ int8_t handle_dlsch(nr_downlink_indication_t *dl_info, NR_UL_TIME_ALIGNMENT_t *u return 0; } +int8_t handle_csirs_measurements(module_id_t module_id, frame_t frame, int slot, fapi_nr_csirs_measurements_t *csirs_measurements) { + return nr_ue_process_csirs_measurements(module_id, frame, slot, csirs_measurements); +} + void update_harq_status(module_id_t module_id, uint8_t harq_pid, uint8_t ack_nack) { NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); @@ -1236,7 +1240,7 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info, NR_UL_TIME_ALIGNMENT_ (dl_info->rx_ind->rx_indication_body+i)->ssb_pdu.ssb_length, (dl_info->rx_ind->rx_indication_body+i)->ssb_pdu.ssb_start_subcarrier, (dl_info->rx_ind->rx_indication_body+i)->ssb_pdu.cell_id)) << FAPI_NR_RX_PDU_TYPE_SSB; - free((dl_info->rx_ind->rx_indication_body+i)->ssb_pdu.pdu); + free((dl_info->rx_ind->rx_indication_body+i)->ssb_pdu.pdu); break; case FAPI_NR_RX_PDU_TYPE_SIB: ret_mask |= (handle_bcch_dlsch(dl_info->module_id, @@ -1251,6 +1255,12 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info, NR_UL_TIME_ALIGNMENT_ case FAPI_NR_RX_PDU_TYPE_RAR: ret_mask |= (handle_dlsch(dl_info, ul_time_alignment, i)) << FAPI_NR_RX_PDU_TYPE_RAR; break; + case FAPI_NR_CSIRS_IND: + ret_mask |= (handle_csirs_measurements(dl_info->module_id, + dl_info->frame, + dl_info->slot, + &(dl_info->rx_ind->rx_indication_body+i)->csirs_measurements)) << FAPI_NR_CSIRS_IND; + break; default: break; } From 40279dddf3548962a97ef264154114a31bd7d708 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Wed, 13 Apr 2022 01:07:01 +0100 Subject: [PATCH 074/267] Get cri_bitlen, ri_bitlen, pmi_bitlen and cqi_bitlen at UE --- openair2/LAYER2/NR_MAC_COMMON/nr_mac.h | 31 ++ openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 481 +++++++++++++++++ openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h | 32 +- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 2 + openair2/LAYER2/NR_MAC_UE/mac_proto.h | 6 + openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 44 +- openair2/LAYER2/NR_MAC_gNB/config.c | 2 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 2 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 485 ------------------ openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 2 - openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 30 -- 11 files changed, 596 insertions(+), 521 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h index 9dd03ddcf6..7b687f6bda 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h @@ -39,6 +39,7 @@ #include #include "NR_SubcarrierSpacing.h" +#include "NR_CSI-ReportConfig.h" #include "openair1/SCHED_NR_UE/harq_nr.h" #define NR_SHORT_BSR_TABLE_SIZE 32 @@ -63,6 +64,7 @@ #define CCCH_PAYLOAD_SIZE_MAX 512 #define RAR_PAYLOAD_SIZE_MAX 128 #define MAX_BWP_SIZE 275 +#define MAX_CSI_REPORTCONFIG 48 typedef enum frequency_range_e { FR1 = 0, @@ -496,5 +498,34 @@ typedef struct Type0_PDCCH_CSS_config_s { bool active; } NR_Type0_PDCCH_CSS_config_t; +typedef struct { + uint8_t nb_ssbri_cri; + uint8_t cri_ssbri_bitlen; + uint8_t rsrp_bitlen; + uint8_t diff_rsrp_bitlen; +} L1_RSRP_bitlen_t; + +typedef struct{ + uint8_t ri_restriction; + uint8_t cri_bitlen; + uint8_t ri_bitlen; + uint8_t li_bitlen[8]; + uint8_t pmi_x1_bitlen[8]; + uint8_t pmi_x2_bitlen[8]; + uint8_t cqi_bitlen[8]; +} CSI_Meas_bitlen_t; + +typedef struct nr_csi_report { + NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type; + long periodicity; + uint16_t offset; + long ** SSB_Index_list; + long ** CSI_Index_list; +// uint8_t nb_of_nzp_csi_report; + uint8_t nb_of_csi_ssb_report; + L1_RSRP_bitlen_t CSI_report_bitlen; + CSI_Meas_bitlen_t csi_meas_bitlen; +} nr_csi_report_t; + #endif /*__LAYER2_MAC_H__ */ diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index 26ccbb473a..e8634e7f9e 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -4161,3 +4161,484 @@ bool set_ul_ptrs_values(NR_PTRS_UplinkConfig_t *ul_ptrs_config, } return valid; } + +//! Calculating number of bits set +uint8_t number_of_bits_set(uint8_t buf) { + uint8_t nb_of_bits_set = 0; + uint8_t mask = 0xff; + uint8_t index = 0; + + for (index=7; (buf & mask) && (index>=0) ; index--){ + if (buf & (1<>=1; + } + return nb_of_bits_set; +} + +void compute_rsrp_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, + uint8_t nb_resources, + nr_csi_report_t *csi_report) { + + if (NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled == csi_reportconfig->groupBasedBeamReporting.present) { + if (NULL != csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS) + csi_report->CSI_report_bitlen.nb_ssbri_cri = *(csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS)+1; + else + /*! From Spec 38.331 + * nrofReportedRS + * The number (N) of measured RS resources to be reported per report setting in a non-group-based report. N <= N_max, where N_max is either 2 or 4 depending on UE + * capability. FFS: The signaling mechanism for the gNB to select a subset of N beams for the UE to measure and report. + * When the field is absent the UE applies the value 1 + */ + csi_report->CSI_report_bitlen.nb_ssbri_cri= 1; + } else + csi_report->CSI_report_bitlen.nb_ssbri_cri= 2; + + if (nb_resources) { + csi_report->CSI_report_bitlen.cri_ssbri_bitlen =ceil(log2 (nb_resources)); + csi_report->CSI_report_bitlen.rsrp_bitlen = 7; //From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP + csi_report->CSI_report_bitlen.diff_rsrp_bitlen =4; //From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP + } else { + csi_report->CSI_report_bitlen.cri_ssbri_bitlen =0; + csi_report->CSI_report_bitlen.rsrp_bitlen = 0; + csi_report->CSI_report_bitlen.diff_rsrp_bitlen =0; + } +} + +uint8_t compute_ri_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, + nr_csi_report_t *csi_report) { + + struct NR_CodebookConfig *codebookConfig = csi_reportconfig->codebookConfig; + uint8_t nb_allowed_ri, ri_bitlen; + uint8_t ri_restriction = 0; + + if (codebookConfig == NULL) { + csi_report->csi_meas_bitlen.ri_bitlen=0; + return ri_restriction; + } + + // codebook type1 single panel + if (NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel==codebookConfig->codebookType.choice.type1->subType.present){ + struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel *type1single = codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel; + if (type1single->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_two){ + + ri_restriction = csi_reportconfig->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->typeI_SinglePanel_ri_Restriction.buf[0]; + + nb_allowed_ri = number_of_bits_set(ri_restriction); + ri_bitlen = ceil(log2(nb_allowed_ri)); + + ri_bitlen = ri_bitlen<1?ri_bitlen:1; //from the spec 38.212 and table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel + csi_report->csi_meas_bitlen.ri_bitlen=ri_bitlen; + } + if (type1single->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_moreThanTwo){ + if (type1single->nrOfAntennaPorts.choice.moreThanTwo->n1_n2.present == + NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_two_one_TypeI_SinglePanel_Restriction) { + // 4 ports + + ri_restriction = csi_reportconfig->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->typeI_SinglePanel_ri_Restriction.buf[0]; + + nb_allowed_ri = number_of_bits_set(ri_restriction); + ri_bitlen = ceil(log2(nb_allowed_ri)); + + ri_bitlen = ri_bitlen<2?ri_bitlen:2; //from the spec 38.212 and table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel + csi_report->csi_meas_bitlen.ri_bitlen=ri_bitlen; + } + else { + // more than 4 ports + + ri_restriction = csi_reportconfig->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->typeI_SinglePanel_ri_Restriction.buf[0]; + + nb_allowed_ri = number_of_bits_set(ri_restriction); + ri_bitlen = ceil(log2(nb_allowed_ri)); + + csi_report->csi_meas_bitlen.ri_bitlen=ri_bitlen; + } + } + return ri_restriction; + } + else + AssertFatal(1==0,"Other configurations not yet implemented\n"); + return -1; +} + +void compute_li_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, + uint8_t ri_restriction, + nr_csi_report_t *csi_report) { + + struct NR_CodebookConfig *codebookConfig = csi_reportconfig->codebookConfig; + for(int i=0; i<8; i++) { + if (codebookConfig == NULL || ((ri_restriction>>i)&0x01) == 0) + csi_report->csi_meas_bitlen.li_bitlen[i]=0; + else { + // codebook type1 single panel + if (NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel==codebookConfig->codebookType.choice.type1->subType.present) + csi_report->csi_meas_bitlen.li_bitlen[i]=ceil(log2(i+1))<2?ceil(log2(i+1)):2; + else + AssertFatal(1==0,"Other configurations not yet implemented\n"); + } + } +} + +void get_n1n2_o1o2_singlepanel(int *n1, int *n2, int *o1, int *o2, + struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo *morethantwo) { + + // Table 5.2.2.2.1-2 in 38.214 for supported configurations + switch(morethantwo->n1_n2.present){ + case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_two_one_TypeI_SinglePanel_Restriction): + *n1 = 2; + *n2 = 1; + *o1 = 4; + *o2 = 1; + break; + case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_two_two_TypeI_SinglePanel_Restriction): + *n1 = 2; + *n2 = 2; + *o1 = 4; + *o2 = 4; + break; + case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_four_one_TypeI_SinglePanel_Restriction): + *n1 = 4; + *n2 = 1; + *o1 = 4; + *o2 = 1; + break; + case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_three_two_TypeI_SinglePanel_Restriction): + *n1 = 3; + *n2 = 2; + *o1 = 4; + *o2 = 4; + break; + case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_six_one_TypeI_SinglePanel_Restriction): + *n1 = 6; + *n2 = 1; + *o1 = 4; + *o2 = 1; + break; + case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_four_two_TypeI_SinglePanel_Restriction): + *n1 = 4; + *n2 = 2; + *o1 = 4; + *o2 = 4; + break; + case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_eight_one_TypeI_SinglePanel_Restriction): + *n1 = 8; + *n2 = 1; + *o1 = 4; + *o2 = 1; + break; + case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_four_three_TypeI_SinglePanel_Restriction): + *n1 = 4; + *n2 = 3; + *o1 = 4; + *o2 = 4; + break; + case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_six_two_TypeI_SinglePanel_Restriction): + *n1 = 4; + *n2 = 2; + *o1 = 4; + *o2 = 4; + break; + case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_twelve_one_TypeI_SinglePanel_Restriction): + *n1 = 12; + *n2 = 1; + *o1 = 4; + *o2 = 1; + break; + case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_four_four_TypeI_SinglePanel_Restriction): + *n1 = 4; + *n2 = 4; + *o1 = 4; + *o2 = 4; + break; + case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_eight_two_TypeI_SinglePanel_Restriction): + *n1 = 8; + *n2 = 2; + *o1 = 4; + *o2 = 4; + break; + case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_sixteen_one_TypeI_SinglePanel_Restriction): + *n1 = 16; + *n2 = 1; + *o1 = 4; + *o2 = 1; + break; + default: + AssertFatal(1==0,"Not supported configuration for n1_n2 in codebook configuration"); + } +} + +void get_x1x2_bitlen_singlepanel(int n1, int n2, int o1, int o2, + int *x1, int *x2, int rank, int codebook_mode) { + + // Table 6.3.1.1.2-1 in 38.212 + switch(rank){ + case 1: + if(n2>1) { + if (codebook_mode == 1) { + *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2)); + *x2 = 2; + } + else { + *x1 = ceil(log2(n1*o1/2)) + ceil(log2(n2*o2/2)); + *x2 = 4; + } + } + else{ + if (codebook_mode == 1) { + *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2)); + *x2 = 2; + } + else { + *x1 = ceil(log2(n1*o1/2)); + *x2 = 4; + } + } + break; + case 2: + if(n1*n2 == 2) { + if (codebook_mode == 1) { + *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2)); + *x2 = 1; + } + else { + *x1 = ceil(log2(n1*o1/2)); + *x2 = 3; + } + *x1 += 1; + } + else { + if(n2>1) { + if (codebook_mode == 1) { + *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2)); + *x2 = 3; + } + else { + *x1 = ceil(log2(n1*o1/2)) + ceil(log2(n2*o2/2)); + *x2 = 3; + } + } + else{ + if (codebook_mode == 1) { + *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2)); + *x2 = 1; + } + else { + *x1 = ceil(log2(n1*o1/2)); + *x2 = 3; + } + } + *x1 += 2; + } + break; + case 3: + case 4: + if(n1*n2 == 2) { + *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2)); + *x2 = 1; + } + else { + if(n1*n2 >= 8) { + *x1 = ceil(log2(n1*o1/2)) + ceil(log2(n2*o2)) + 2; + *x2 = 1; + } + else { + *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2)) + 2; + *x2 = 1; + } + } + break; + case 5: + case 6: + *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2)); + *x2 = 1; + break; + case 7: + case 8: + if(n1 == 4 && n2 == 1) { + *x1 = ceil(log2(n1*o1/2)) + ceil(log2(n2*o2)); + *x2 = 1; + } + else { + if(n1 > 2 && n2 == 2) { + *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2/2)); + *x2 = 1; + } + else { + *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2)); + *x2 = 1; + } + } + break; + default: + AssertFatal(1==0,"Invalid rank in x1 x2 bit length computation\n"); + } +} + + +void compute_pmi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, + uint8_t ri_restriction, + nr_csi_report_t *csi_report) { + + struct NR_CodebookConfig *codebookConfig = csi_reportconfig->codebookConfig; + for(int i=0; i<8; i++) { + csi_report->csi_meas_bitlen.pmi_x1_bitlen[i]=0; + csi_report->csi_meas_bitlen.pmi_x2_bitlen[i]=0; + if (codebookConfig == NULL || ((ri_restriction>>i)&0x01) == 0) + return; + else { + if(codebookConfig->codebookType.present == NR_CodebookConfig__codebookType_PR_type1) { + if(codebookConfig->codebookType.choice.type1->subType.present == NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel) { + if(codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->nrOfAntennaPorts.present == + NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_two) { + if (i==0) + csi_report->csi_meas_bitlen.pmi_x2_bitlen[i]=2; + if (i==1) + csi_report->csi_meas_bitlen.pmi_x2_bitlen[i]=1; + } + else { // more than two + int n1,n2,o1,o2,x1,x2; + get_n1n2_o1o2_singlepanel(&n1,&n2,&o1,&o2,codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->nrOfAntennaPorts.choice.moreThanTwo); + get_x1x2_bitlen_singlepanel(n1,n2,o1,o2,&x1,&x2,i+1,codebookConfig->codebookType.choice.type1->codebookMode); + csi_report->csi_meas_bitlen.pmi_x1_bitlen[i]=x1; + csi_report->csi_meas_bitlen.pmi_x2_bitlen[i]=x2; + } + } + else + AssertFatal(1==0,"Type1 Multi-panel Codebook Config not yet implemented\n"); + } + else + AssertFatal(1==0,"Type2 Codebook Config not yet implemented\n"); + } + } +} + +void compute_cqi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, + uint8_t ri_restriction, + nr_csi_report_t *csi_report) { + + struct NR_CodebookConfig *codebookConfig = csi_reportconfig->codebookConfig; + struct NR_CSI_ReportConfig__reportFreqConfiguration *freq_config = csi_reportconfig->reportFreqConfiguration; + + if (*freq_config->cqi_FormatIndicator == NR_CSI_ReportConfig__reportFreqConfiguration__cqi_FormatIndicator_widebandCQI) { + for(int i=0; i<8; i++) { + if ((ri_restriction>>i)&0x01) { + csi_report->csi_meas_bitlen.cqi_bitlen[i] = 4; + if(codebookConfig != NULL) { + if (NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel == codebookConfig->codebookType.choice.type1->subType.present){ + struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel *type1single = codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel; + if (type1single->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_moreThanTwo) { + if (type1single->nrOfAntennaPorts.choice.moreThanTwo->n1_n2.present > + NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_two_one_TypeI_SinglePanel_Restriction) { + // more than 4 antenna ports + if (i > 4) + csi_report->csi_meas_bitlen.cqi_bitlen[i] += 4; // CQI for second TB + } + } + } + } + } + else + csi_report->csi_meas_bitlen.cqi_bitlen[i] = 0; + } + } + else + AssertFatal(1==0,"Sub-band CQI reporting not yet supported"); +} + +//!TODO : same function can be written to handle csi_resources +void compute_csi_bitlen(NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report_t *csi_report_template) { + uint8_t csi_report_id = 0; + uint8_t nb_resources = 0; + NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type; + NR_CSI_ResourceConfigId_t csi_ResourceConfigId; + struct NR_CSI_ResourceConfig *csi_resourceconfig; + + // for each CSI measurement report configuration (list of CSI-ReportConfig) + LOG_D(NR_MAC,"Searching %d csi_reports\n",csi_MeasConfig->csi_ReportConfigToAddModList->list.count); + for (csi_report_id=0; csi_report_id < csi_MeasConfig->csi_ReportConfigToAddModList->list.count; csi_report_id++){ + struct NR_CSI_ReportConfig *csi_reportconfig = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; + // MAC structure for CSI measurement reports (per UE and per report) + nr_csi_report_t *csi_report = &csi_report_template[csi_report_id]; + // csi-ResourceConfigId of a CSI-ResourceConfig included in the configuration + // (either CSI-RS or SSB) + csi_ResourceConfigId = csi_reportconfig->resourcesForChannelMeasurement; + // looking for CSI-ResourceConfig + int found_resource = 0; + int csi_resourceidx = 0; + while (found_resource == 0 && csi_resourceidx < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count) { + csi_resourceconfig = csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx]; + if ( csi_resourceconfig->csi_ResourceConfigId == csi_ResourceConfigId) + found_resource = 1; + csi_resourceidx++; + } + AssertFatal(found_resource==1,"Not able to found any CSI-ResourceConfig with csi-ResourceConfigId %ld\n", + csi_ResourceConfigId); + + long resourceType = csi_resourceconfig->resourceType; + + reportQuantity_type = csi_reportconfig->reportQuantity.present; + csi_report->reportQuantity_type = reportQuantity_type; + + // setting the CSI or SSB index list + if (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP == csi_report->reportQuantity_type) { + for (int csi_idx = 0; csi_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_idx++) { + if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_idx]->csi_SSB_ResourceSetId == + *(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])){ + //We can configure only one SSB resource set from spec 38.331 IE CSI-ResourceConfig + nb_resources= csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_idx]->csi_SSB_ResourceList.list.count; + csi_report->SSB_Index_list = csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_idx]->csi_SSB_ResourceList.list.array; + csi_report->CSI_Index_list = NULL; + break; + } + } + } + else { + if (resourceType == NR_CSI_ResourceConfig__resourceType_periodic) { + AssertFatal(csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList != NULL, + "Wrong settings! Report quantity requires CSI-RS but csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList is NULL\n"); + for (int csi_idx = 0; csi_idx < csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList->list.count; csi_idx++) { + if (csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList->list.array[csi_idx]->nzp_CSI_ResourceSetId == + *(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.array[0])) { + //For periodic and semi-persistent CSI Resource Settings, the number of CSI-RS Resource Sets configured is limited to S=1 for spec 38.212 + nb_resources = csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList->list.array[csi_idx]->nzp_CSI_RS_Resources.list.count; + csi_report->CSI_Index_list = csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList->list.array[csi_idx]->nzp_CSI_RS_Resources.list.array; + csi_report->SSB_Index_list = NULL; + break; + } + } + } + else AssertFatal(1==0,"Only periodic resource configuration currently supported\n"); + } + LOG_D(NR_MAC,"nb_resources %d\n",nb_resources); + // computation of bit length depending on the report type + switch(reportQuantity_type){ + case (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP): + compute_rsrp_bitlen(csi_reportconfig, nb_resources, csi_report); + break; + case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP): + compute_rsrp_bitlen(csi_reportconfig, nb_resources, csi_report); + break; + case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI): + csi_report->csi_meas_bitlen.cri_bitlen=ceil(log2(nb_resources)); + csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); + compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); + break; + case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI): + csi_report->csi_meas_bitlen.cri_bitlen=ceil(log2(nb_resources)); + csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); + compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); + compute_pmi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); + break; + case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI): + csi_report->csi_meas_bitlen.cri_bitlen=ceil(log2(nb_resources)); + csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); + compute_li_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); + compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); + compute_pmi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); + break; + default: + AssertFatal(1==0,"Not yet supported CSI report quantity type"); + } + } +} \ No newline at end of file diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index 0f2cb42b88..e4316f8d06 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -102,7 +102,7 @@ uint8_t get_pusch_mcs_table(long *mcs_Table, uint8_t compute_nr_root_seq(NR_RACH_ConfigCommon_t *rach_config, uint8_t nb_preambles, uint8_t unpaired, - frequency_range_t); + frequency_range_t); int ul_ant_bits(NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig,long transformPrecoder); @@ -203,4 +203,34 @@ void nr_mac_gNB_rrc_ul_failure_reset(const module_id_t Mod_instP, const frame_t frameP, const sub_frame_t subframeP, const rnti_t rntiP); + +uint8_t number_of_bits_set(uint8_t buf); + +void compute_rsrp_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, + uint8_t nb_resources, + nr_csi_report_t *csi_report); + +uint8_t compute_ri_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, + nr_csi_report_t *csi_report); + +void compute_li_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, + uint8_t ri_restriction, + nr_csi_report_t *csi_report); + +void get_n1n2_o1o2_singlepanel(int *n1, int *n2, int *o1, int *o2, + struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo *morethantwo); + +void get_x1x2_bitlen_singlepanel(int n1, int n2, int o1, int o2, + int *x1, int *x2, int rank, int codebook_mode); + +void compute_pmi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, + uint8_t ri_restriction, + nr_csi_report_t *csi_report); + +void compute_cqi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, + uint8_t ri_restriction, + nr_csi_report_t *csi_report); + +void compute_csi_bitlen(NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report_t *csi_report_template); + #endif diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 09153e6f13..1d9852ccfb 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -399,6 +399,8 @@ typedef struct { /// measured SSB RSRP in dBm short ssb_rsrp_dBm; + nr_csi_report_t csi_report_template[MAX_CSI_REPORTCONFIG]; + /// measurements from CSI-RS fapi_nr_csirs_measurements_t csirs_measurements; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index c57c427f14..3997da63b0 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -213,6 +213,12 @@ uint8_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, NR_CSI_ResourceConfigId_t csi_ResourceConfigId, NR_CSI_MeasConfig_t *csi_MeasConfig); +uint8_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, + PUCCH_sched_t *pucch, + struct NR_CSI_ReportConfig *csi_reportconfig, + NR_CSI_ResourceConfigId_t csi_ResourceConfigId, + NR_CSI_MeasConfig_t *csi_MeasConfig); + uint8_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac, PUCCH_sched_t *pucch, int csi_report_id, diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 220dc799e5..a2391809ad 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2486,8 +2486,10 @@ uint8_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac, case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP: n_csi_bits = get_ssb_rsrp_payload(mac,pucch,csi_reportconfig,csi_ResourceConfigId,csi_MeasConfig); break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP: case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI: + n_csi_bits = get_csirs_RI_PMI_CQI_payload(mac,pucch,csi_reportconfig,csi_ResourceConfigId,csi_MeasConfig); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP: case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1: case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI: case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI: @@ -2580,6 +2582,46 @@ uint8_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, return bits; } +uint8_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, + PUCCH_sched_t *pucch, + struct NR_CSI_ReportConfig *csi_reportconfig, + NR_CSI_ResourceConfigId_t csi_ResourceConfigId, + NR_CSI_MeasConfig_t *csi_MeasConfig) { + + int bits = 0; + uint32_t temp_payload = 0; + + for (int csi_resourceidx = 0; csi_resourceidx < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_resourceidx++) { + + struct NR_CSI_ResourceConfig *csi_resourceconfig = csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx]; + if (csi_resourceconfig->csi_ResourceConfigId == csi_ResourceConfigId) { + + for (int csi_idx = 0; csi_idx < csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList->list.count; csi_idx++) { + if (csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList->list.array[csi_idx]->nzp_CSI_ResourceSetId == + *(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.array[0])) { + + nr_csi_report_t *csi_report = &mac->csi_report_template[csi_reportconfig->reportConfigId]; + compute_csi_bitlen(csi_MeasConfig, mac->csi_report_template); + + int cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; + int ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; + int pmi_bitlen = csi_report->csi_meas_bitlen.pmi_x1_bitlen[*mac->csirs_measurements.rank_indicator] + + csi_report->csi_meas_bitlen.pmi_x2_bitlen[*mac->csirs_measurements.rank_indicator]; + int cqi_bitlen = csi_report->csi_meas_bitlen.cqi_bitlen[*mac->csirs_measurements.rank_indicator]; + + LOG_I(NR_MAC, "cri_bitlen = %d\n", cri_bitlen); + LOG_I(NR_MAC, "ri_bitlen = %d\n", ri_bitlen); + LOG_I(NR_MAC, "pmi_bitlen = %d\n", pmi_bitlen); + LOG_I(NR_MAC, "cqi_bitlen = %d\n", cqi_bitlen); + + break; + } + } + } + } + pucch->csi_part1_payload = temp_payload; + return bits; +} // returns index from RSRP // according to Table 10.1.6.1-1 in 38.133 diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index c39f4fa510..27041a27e3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -687,7 +687,7 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, CellGroup->spCellConfig->spCellConfigDedicated && CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig && CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup) { - compute_csi_bitlen(CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup, UE_info, UE_id, Mod_idP); + compute_csi_bitlen(CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup, UE_info->csi_report_template[UE_id]); } } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index aac73d55f2..ee07250ad4 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2296,7 +2296,7 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP, NR_CellGroupConfig_t *CellG CellGroup->spCellConfig->spCellConfigDedicated && CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig && CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup) { - compute_csi_bitlen (CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup, UE_info, UE_id, mod_idP); + compute_csi_bitlen(CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup, UE_info->csi_report_template[UE_id]); } NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; memset(sched_ctrl, 0, sizeof(*sched_ctrl)); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index ed80910bd0..c43e54d883 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -170,491 +170,6 @@ void nr_schedule_pucch(int Mod_idP, } } - -//! Calculating number of bits set -uint8_t number_of_bits_set (uint8_t buf){ - uint8_t nb_of_bits_set = 0; - uint8_t mask = 0xff; - uint8_t index = 0; - - for (index=7; (buf & mask) && (index>=0) ; index--){ - if (buf & (1<>=1; - } - return nb_of_bits_set; -} - - -void compute_rsrp_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, - uint8_t nb_resources, - nr_csi_report_t *csi_report) { - - if (NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled == csi_reportconfig->groupBasedBeamReporting.present) { - if (NULL != csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS) - csi_report->CSI_report_bitlen.nb_ssbri_cri = *(csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS)+1; - else - /*! From Spec 38.331 - * nrofReportedRS - * The number (N) of measured RS resources to be reported per report setting in a non-group-based report. N <= N_max, where N_max is either 2 or 4 depending on UE - * capability. FFS: The signaling mechanism for the gNB to select a subset of N beams for the UE to measure and report. - * When the field is absent the UE applies the value 1 - */ - csi_report->CSI_report_bitlen.nb_ssbri_cri= 1; - } else - csi_report->CSI_report_bitlen.nb_ssbri_cri= 2; - - if (nb_resources) { - csi_report->CSI_report_bitlen.cri_ssbri_bitlen =ceil(log2 (nb_resources)); - csi_report->CSI_report_bitlen.rsrp_bitlen = 7; //From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP - csi_report->CSI_report_bitlen.diff_rsrp_bitlen =4; //From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP - } else { - csi_report->CSI_report_bitlen.cri_ssbri_bitlen =0; - csi_report->CSI_report_bitlen.rsrp_bitlen = 0; - csi_report->CSI_report_bitlen.diff_rsrp_bitlen =0; - } -} - - -uint8_t compute_ri_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, - nr_csi_report_t *csi_report){ - - struct NR_CodebookConfig *codebookConfig = csi_reportconfig->codebookConfig; - uint8_t nb_allowed_ri, ri_bitlen; - uint8_t ri_restriction = 0; - - if (codebookConfig == NULL) { - csi_report->csi_meas_bitlen.ri_bitlen=0; - return ri_restriction; - } - - // codebook type1 single panel - if (NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel==codebookConfig->codebookType.choice.type1->subType.present){ - struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel *type1single = codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel; - if (type1single->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_two){ - - ri_restriction = csi_reportconfig->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->typeI_SinglePanel_ri_Restriction.buf[0]; - - nb_allowed_ri = number_of_bits_set(ri_restriction); - ri_bitlen = ceil(log2(nb_allowed_ri)); - - ri_bitlen = ri_bitlen<1?ri_bitlen:1; //from the spec 38.212 and table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel - csi_report->csi_meas_bitlen.ri_bitlen=ri_bitlen; - } - if (type1single->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_moreThanTwo){ - if (type1single->nrOfAntennaPorts.choice.moreThanTwo->n1_n2.present == - NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_two_one_TypeI_SinglePanel_Restriction) { - // 4 ports - - ri_restriction = csi_reportconfig->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->typeI_SinglePanel_ri_Restriction.buf[0]; - - nb_allowed_ri = number_of_bits_set(ri_restriction); - ri_bitlen = ceil(log2(nb_allowed_ri)); - - ri_bitlen = ri_bitlen<2?ri_bitlen:2; //from the spec 38.212 and table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel - csi_report->csi_meas_bitlen.ri_bitlen=ri_bitlen; - } - else { - // more than 4 ports - - ri_restriction = csi_reportconfig->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->typeI_SinglePanel_ri_Restriction.buf[0]; - - nb_allowed_ri = number_of_bits_set(ri_restriction); - ri_bitlen = ceil(log2(nb_allowed_ri)); - - csi_report->csi_meas_bitlen.ri_bitlen=ri_bitlen; - } - } - return ri_restriction; - } - else - AssertFatal(1==0,"Other configurations not yet implemented\n"); - return -1; -} - -void compute_li_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, - uint8_t ri_restriction, - nr_csi_report_t *csi_report){ - - struct NR_CodebookConfig *codebookConfig = csi_reportconfig->codebookConfig; - for(int i=0; i<8; i++) { - if (codebookConfig == NULL || ((ri_restriction>>i)&0x01) == 0) - csi_report->csi_meas_bitlen.li_bitlen[i]=0; - else { - // codebook type1 single panel - if (NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel==codebookConfig->codebookType.choice.type1->subType.present) - csi_report->csi_meas_bitlen.li_bitlen[i]=ceil(log2(i+1))<2?ceil(log2(i+1)):2; - else - AssertFatal(1==0,"Other configurations not yet implemented\n"); - } - } -} - -void get_n1n2_o1o2_singlepanel(int *n1, int *n2, int *o1, int *o2, - struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo *morethantwo) { - - // Table 5.2.2.2.1-2 in 38.214 for supported configurations - switch(morethantwo->n1_n2.present){ - case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_two_one_TypeI_SinglePanel_Restriction): - *n1 = 2; - *n2 = 1; - *o1 = 4; - *o2 = 1; - break; - case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_two_two_TypeI_SinglePanel_Restriction): - *n1 = 2; - *n2 = 2; - *o1 = 4; - *o2 = 4; - break; - case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_four_one_TypeI_SinglePanel_Restriction): - *n1 = 4; - *n2 = 1; - *o1 = 4; - *o2 = 1; - break; - case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_three_two_TypeI_SinglePanel_Restriction): - *n1 = 3; - *n2 = 2; - *o1 = 4; - *o2 = 4; - break; - case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_six_one_TypeI_SinglePanel_Restriction): - *n1 = 6; - *n2 = 1; - *o1 = 4; - *o2 = 1; - break; - case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_four_two_TypeI_SinglePanel_Restriction): - *n1 = 4; - *n2 = 2; - *o1 = 4; - *o2 = 4; - break; - case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_eight_one_TypeI_SinglePanel_Restriction): - *n1 = 8; - *n2 = 1; - *o1 = 4; - *o2 = 1; - break; - case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_four_three_TypeI_SinglePanel_Restriction): - *n1 = 4; - *n2 = 3; - *o1 = 4; - *o2 = 4; - break; - case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_six_two_TypeI_SinglePanel_Restriction): - *n1 = 4; - *n2 = 2; - *o1 = 4; - *o2 = 4; - break; - case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_twelve_one_TypeI_SinglePanel_Restriction): - *n1 = 12; - *n2 = 1; - *o1 = 4; - *o2 = 1; - break; - case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_four_four_TypeI_SinglePanel_Restriction): - *n1 = 4; - *n2 = 4; - *o1 = 4; - *o2 = 4; - break; - case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_eight_two_TypeI_SinglePanel_Restriction): - *n1 = 8; - *n2 = 2; - *o1 = 4; - *o2 = 4; - break; - case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_sixteen_one_TypeI_SinglePanel_Restriction): - *n1 = 16; - *n2 = 1; - *o1 = 4; - *o2 = 1; - break; - default: - AssertFatal(1==0,"Not supported configuration for n1_n2 in codebook configuration"); - } -} - -void get_x1x2_bitlen_singlepanel(int n1, int n2, int o1, int o2, - int *x1, int *x2, int rank, int codebook_mode) { - - // Table 6.3.1.1.2-1 in 38.212 - switch(rank){ - case 1: - if(n2>1) { - if (codebook_mode == 1) { - *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2)); - *x2 = 2; - } - else { - *x1 = ceil(log2(n1*o1/2)) + ceil(log2(n2*o2/2)); - *x2 = 4; - } - } - else{ - if (codebook_mode == 1) { - *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2)); - *x2 = 2; - } - else { - *x1 = ceil(log2(n1*o1/2)); - *x2 = 4; - } - } - break; - case 2: - if(n1*n2 == 2) { - if (codebook_mode == 1) { - *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2)); - *x2 = 1; - } - else { - *x1 = ceil(log2(n1*o1/2)); - *x2 = 3; - } - *x1 += 1; - } - else { - if(n2>1) { - if (codebook_mode == 1) { - *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2)); - *x2 = 3; - } - else { - *x1 = ceil(log2(n1*o1/2)) + ceil(log2(n2*o2/2)); - *x2 = 3; - } - } - else{ - if (codebook_mode == 1) { - *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2)); - *x2 = 1; - } - else { - *x1 = ceil(log2(n1*o1/2)); - *x2 = 3; - } - } - *x1 += 2; - } - break; - case 3: - case 4: - if(n1*n2 == 2) { - *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2)); - *x2 = 1; - } - else { - if(n1*n2 >= 8) { - *x1 = ceil(log2(n1*o1/2)) + ceil(log2(n2*o2)) + 2; - *x2 = 1; - } - else { - *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2)) + 2; - *x2 = 1; - } - } - break; - case 5: - case 6: - *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2)); - *x2 = 1; - break; - case 7: - case 8: - if(n1 == 4 && n2 == 1) { - *x1 = ceil(log2(n1*o1/2)) + ceil(log2(n2*o2)); - *x2 = 1; - } - else { - if(n1 > 2 && n2 == 2) { - *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2/2)); - *x2 = 1; - } - else { - *x1 = ceil(log2(n1*o1)) + ceil(log2(n2*o2)); - *x2 = 1; - } - } - break; - default: - AssertFatal(1==0,"Invalid rank in x1 x2 bit length computation\n"); - } -} - - -void compute_pmi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, - uint8_t ri_restriction, - nr_csi_report_t *csi_report){ - - struct NR_CodebookConfig *codebookConfig = csi_reportconfig->codebookConfig; - for(int i=0; i<8; i++) { - csi_report->csi_meas_bitlen.pmi_x1_bitlen[i]=0; - csi_report->csi_meas_bitlen.pmi_x2_bitlen[i]=0; - if (codebookConfig == NULL || ((ri_restriction>>i)&0x01) == 0) - return; - else { - if(codebookConfig->codebookType.present == NR_CodebookConfig__codebookType_PR_type1) { - if(codebookConfig->codebookType.choice.type1->subType.present == NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel) { - if(codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->nrOfAntennaPorts.present == - NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_two) { - if (i==0) - csi_report->csi_meas_bitlen.pmi_x2_bitlen[i]=2; - if (i==1) - csi_report->csi_meas_bitlen.pmi_x2_bitlen[i]=1; - } - else { // more than two - int n1,n2,o1,o2,x1,x2; - get_n1n2_o1o2_singlepanel(&n1,&n2,&o1,&o2,codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->nrOfAntennaPorts.choice.moreThanTwo); - get_x1x2_bitlen_singlepanel(n1,n2,o1,o2,&x1,&x2,i+1,codebookConfig->codebookType.choice.type1->codebookMode); - csi_report->csi_meas_bitlen.pmi_x1_bitlen[i]=x1; - csi_report->csi_meas_bitlen.pmi_x2_bitlen[i]=x2; - } - } - else - AssertFatal(1==0,"Type1 Multi-panel Codebook Config not yet implemented\n"); - } - else - AssertFatal(1==0,"Type2 Codebook Config not yet implemented\n"); - } - } -} - -void compute_cqi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, - uint8_t ri_restriction, - nr_csi_report_t *csi_report){ - - struct NR_CodebookConfig *codebookConfig = csi_reportconfig->codebookConfig; - struct NR_CSI_ReportConfig__reportFreqConfiguration *freq_config = csi_reportconfig->reportFreqConfiguration; - - if (*freq_config->cqi_FormatIndicator == NR_CSI_ReportConfig__reportFreqConfiguration__cqi_FormatIndicator_widebandCQI) { - for(int i=0; i<8; i++) { - if ((ri_restriction>>i)&0x01) { - csi_report->csi_meas_bitlen.cqi_bitlen[i] = 4; - if(codebookConfig != NULL) { - if (NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel == codebookConfig->codebookType.choice.type1->subType.present){ - struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel *type1single = codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel; - if (type1single->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_moreThanTwo) { - if (type1single->nrOfAntennaPorts.choice.moreThanTwo->n1_n2.present > - NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_two_one_TypeI_SinglePanel_Restriction) { - // more than 4 antenna ports - if (i > 4) - csi_report->csi_meas_bitlen.cqi_bitlen[i] += 4; // CQI for second TB - } - } - } - } - } - else - csi_report->csi_meas_bitlen.cqi_bitlen[i] = 0; - } - } - else - AssertFatal(1==0,"Sub-band CQI reporting not yet supported"); -} - -//!TODO : same function can be written to handle csi_resources -void compute_csi_bitlen(NR_CSI_MeasConfig_t *csi_MeasConfig, NR_UE_info_t *UE_info, int UE_id, module_id_t Mod_idP){ - uint8_t csi_report_id = 0; - uint8_t nb_resources = 0; - NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type; - NR_CSI_ResourceConfigId_t csi_ResourceConfigId; - struct NR_CSI_ResourceConfig *csi_resourceconfig; - - // for each CSI measurement report configuration (list of CSI-ReportConfig) - LOG_D(NR_MAC,"Searching %d csi_reports\n",csi_MeasConfig->csi_ReportConfigToAddModList->list.count); - for (csi_report_id=0; csi_report_id < csi_MeasConfig->csi_ReportConfigToAddModList->list.count; csi_report_id++){ - struct NR_CSI_ReportConfig *csi_reportconfig = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; - // MAC structure for CSI measurement reports (per UE and per report) - nr_csi_report_t *csi_report = &UE_info->csi_report_template[UE_id][csi_report_id]; - // csi-ResourceConfigId of a CSI-ResourceConfig included in the configuration - // (either CSI-RS or SSB) - csi_ResourceConfigId = csi_reportconfig->resourcesForChannelMeasurement; - // looking for CSI-ResourceConfig - int found_resource = 0; - int csi_resourceidx = 0; - while (found_resource == 0 && csi_resourceidx < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count) { - csi_resourceconfig = csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx]; - if ( csi_resourceconfig->csi_ResourceConfigId == csi_ResourceConfigId) - found_resource = 1; - csi_resourceidx++; - } - AssertFatal(found_resource==1,"Not able to found any CSI-ResourceConfig with csi-ResourceConfigId %ld\n", - csi_ResourceConfigId); - - long resourceType = csi_resourceconfig->resourceType; - - reportQuantity_type = csi_reportconfig->reportQuantity.present; - csi_report->reportQuantity_type = reportQuantity_type; - - // setting the CSI or SSB index list - if (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP == csi_report->reportQuantity_type) { - for (int csi_idx = 0; csi_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_idx++) { - if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_idx]->csi_SSB_ResourceSetId == - *(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])){ - //We can configure only one SSB resource set from spec 38.331 IE CSI-ResourceConfig - nb_resources= csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_idx]->csi_SSB_ResourceList.list.count; - csi_report->SSB_Index_list = csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_idx]->csi_SSB_ResourceList.list.array; - csi_report->CSI_Index_list = NULL; - break; - } - } - } - else { - if (resourceType == NR_CSI_ResourceConfig__resourceType_periodic) { - AssertFatal(csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList != NULL, - "Wrong settings! Report quantity requires CSI-RS but csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList is NULL\n"); - for (int csi_idx = 0; csi_idx < csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList->list.count; csi_idx++) { - if (csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList->list.array[csi_idx]->nzp_CSI_ResourceSetId == - *(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.array[0])) { - //For periodic and semi-persistent CSI Resource Settings, the number of CSI-RS Resource Sets configured is limited to S=1 for spec 38.212 - nb_resources = csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList->list.array[csi_idx]->nzp_CSI_RS_Resources.list.count; - csi_report->CSI_Index_list = csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList->list.array[csi_idx]->nzp_CSI_RS_Resources.list.array; - csi_report->SSB_Index_list = NULL; - break; - } - } - } - else AssertFatal(1==0,"Only periodic resource configuration currently supported\n"); - } - LOG_D(NR_MAC,"nb_resources %d\n",nb_resources); - // computation of bit length depending on the report type - switch(reportQuantity_type){ - case (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP): - compute_rsrp_bitlen(csi_reportconfig, nb_resources, csi_report); - break; - case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP): - compute_rsrp_bitlen(csi_reportconfig, nb_resources, csi_report); - break; - case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI): - csi_report->csi_meas_bitlen.cri_bitlen=ceil(log2(nb_resources)); - csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); - compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); - break; - case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI): - csi_report->csi_meas_bitlen.cri_bitlen=ceil(log2(nb_resources)); - csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); - compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); - compute_pmi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); - break; - case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI): - csi_report->csi_meas_bitlen.cri_bitlen=ceil(log2(nb_resources)); - csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); - compute_li_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); - compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); - compute_pmi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); - break; - default: - AssertFatal(1==0,"Not yet supported CSI report quantity type"); - } - } -} - - uint16_t nr_get_csi_bitlen(int Mod_idP, int UE_id, uint8_t csi_report_id) { diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 399033abd0..05faa2849b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -416,8 +416,6 @@ int allocate_nr_CCEs(gNB_MAC_INST *nr_mac, int nr_get_default_pucch_res(int pucch_ResourceCommon); -void compute_csi_bitlen(NR_CSI_MeasConfig_t *csi_MeasConfig, NR_UE_info_t *UE_info, int UE_id, module_id_t Mod_idP); - int get_dlscs(nfapi_nr_config_request_t *cfg); int get_ulscs(nfapi_nr_config_request_t *cfg); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 9021a58079..155d67c2f1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -502,35 +502,6 @@ struct CSI_Report { #define MAX_SR_BITLEN 8 -typedef struct { - uint8_t nb_ssbri_cri; - uint8_t cri_ssbri_bitlen; - uint8_t rsrp_bitlen; - uint8_t diff_rsrp_bitlen; -}L1_RSRP_bitlen_t; - -typedef struct{ - uint8_t ri_restriction; - uint8_t cri_bitlen; - uint8_t ri_bitlen; - uint8_t li_bitlen[8]; - uint8_t pmi_x1_bitlen[8]; - uint8_t pmi_x2_bitlen[8]; - uint8_t cqi_bitlen[8]; -} CSI_Meas_bitlen_t; - -typedef struct nr_csi_report { - NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type; - long periodicity; - uint16_t offset; - long ** SSB_Index_list; - long ** CSI_Index_list; -// uint8_t nb_of_nzp_csi_report; - uint8_t nb_of_csi_ssb_report; - L1_RSRP_bitlen_t CSI_report_bitlen; - CSI_Meas_bitlen_t csi_meas_bitlen; -} nr_csi_report_t; - /*! As per the spec 38.212 and table: 6.3.1.1.2-12 in a single UCI sequence we can have multiple CSI_report the number of CSI_report will depend on number of CSI resource sets that are configured in CSI-ResourceConfig RRC IE From spec 38.331 from the IE CSI-ResourceConfig for SSB RSRP reporting we can configure only one resource set @@ -679,7 +650,6 @@ typedef struct { /*! \brief UE list used by gNB to order UEs/CC for scheduling*/ -#define MAX_CSI_REPORTCONFIG 48 typedef struct { /// scheduling control info nr_csi_report_t csi_report_template[MAX_MOBILES_PER_GNB][MAX_CSI_REPORTCONFIG]; From cfda6c7b1dc73319821e60002df25d10357a254c Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 13 Apr 2022 10:58:28 +0200 Subject: [PATCH 075/267] renaming SR config function --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 2 +- openair2/RRC/NR/nr_rrc_config.c | 6 +++--- openair2/RRC/NR/nr_rrc_config.h | 6 +++--- openair2/RRC/NR/rrc_gNB_reconfig.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 7e0271e609..2819394635 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1185,7 +1185,7 @@ void fill_initial_SpCellConfig(int uid, srs_res0->spatialRelationInfo->referenceSignal.choice.csi_RS_Index=0; ASN_SEQUENCE_ADD(&srs_Config->srs_ResourceToAddModList->list,srs_res0); - schedulingrequest_config(scc, cellGroupConfig->mac_CellGroupConfig, pucch_Config); + scheduling_request_config(scc, cellGroupConfig->mac_CellGroupConfig, pucch_Config); set_dl_DataToUL_ACK(pucch_Config, configuration->minRXTXTIME); diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 388c09c7cb..848d09b8ef 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -473,9 +473,9 @@ void set_SR_periodandoffset(NR_SchedulingRequestResourceConfig_t *schedulingRequ schedulingRequestResourceConfig->periodicityAndOffset->choice.sl640 = sr_slot; } -void schedulingrequest_config(NR_ServingCellConfigCommon_t *scc, - NR_MAC_CellGroupConfig_t *mac_CellGroupConfig, - NR_PUCCH_Config_t *pucch_Config) { +void scheduling_request_config(NR_ServingCellConfigCommon_t *scc, + NR_MAC_CellGroupConfig_t *mac_CellGroupConfig, + NR_PUCCH_Config_t *pucch_Config) { mac_CellGroupConfig->schedulingRequestConfig = calloc(1, sizeof(*mac_CellGroupConfig->schedulingRequestConfig)); mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList = CALLOC(1,sizeof(*mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList)); diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index f744338921..d40c4dd209 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -117,9 +117,9 @@ void config_pucch_resset0(NR_PUCCH_Config_t *pucch_Config, int uid, int curr_bwp void config_pucch_resset1(NR_PUCCH_Config_t *pucch_Config, NR_UE_NR_Capability_t *uecap); void set_dl_DataToUL_ACK(NR_PUCCH_Config_t *pucch_Config, int min_feedback_time); void set_pucch_power_config(NR_PUCCH_Config_t *pucch_Config, int do_csirs); -void schedulingrequest_config(NR_ServingCellConfigCommon_t *scc, - NR_MAC_CellGroupConfig_t *mac_CellGroupConfig, - NR_PUCCH_Config_t *pucch_Config); +void scheduling_request_config(NR_ServingCellConfigCommon_t *scc, + NR_MAC_CellGroupConfig_t *mac_CellGroupConfig, + NR_PUCCH_Config_t *pucch_Config); void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, NR_CSI_MeasConfig_t *csi_MeasConfig, int uid, diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index 22d3a4552c..335e7d3bda 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -861,7 +861,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco config_pucch_resset0(pucch_Config, uid, curr_bwp, uecap); // <= 2 bits config_pucch_resset1(pucch_Config, uecap); // > 2 bits - schedulingrequest_config(servingcellconfigcommon, secondaryCellGroup->mac_CellGroupConfig, pucch_Config); + scheduling_request_config(servingcellconfigcommon, secondaryCellGroup->mac_CellGroupConfig, pucch_Config); pucch_Config->schedulingRequestResourceToReleaseList=NULL; pucch_Config->multi_CSI_PUCCH_ResourceList=NULL; From cd6ee6a01ef456366c91c7c8925bb484ea0acf52 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Wed, 13 Apr 2022 11:12:49 +0100 Subject: [PATCH 076/267] Fix build after merge --- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 0b63c4a149..09522a5411 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -684,7 +684,7 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t csirs_measurements.cqi = ue->nr_csi_rs_info->cqi; nr_downlink_indication_t *dl_indication = calloc(sizeof(*dl_indication),1); fapi_nr_rx_indication_t *rx_ind = calloc(sizeof(*rx_ind),1); - nr_fill_dl_indication(dl_indication, NULL, rx_ind, proc, ue, gNB_id); + nr_fill_dl_indication(dl_indication, NULL, rx_ind, proc, ue, gNB_id, NULL); nr_fill_rx_indication(rx_ind, FAPI_NR_CSIRS_IND, gNB_id, ue, NULL, NULL, 1, proc, (void *)&csirs_measurements); if (ue->if_inst && ue->if_inst->dl_indication) { ue->if_inst->dl_indication(dl_indication, NULL); From 0c05e283e2cda03ef4cb3ff38c278b33770efe7e Mon Sep 17 00:00:00 2001 From: matzakos Date: Wed, 13 Apr 2022 13:19:04 +0200 Subject: [PATCH 077/267] Remove warnings and unused code --- openair2/F1AP/f1ap_cu_ue_context_management.c | 2 +- openair2/F1AP/f1ap_du_ue_context_management.c | 13 +++++-------- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 1 + openair2/RRC/NR/rrc_gNB.c | 12 ------------ 4 files changed, 7 insertions(+), 21 deletions(-) diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index 08d0ff042e..859a9f5e0d 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -1156,7 +1156,7 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, f1ap_ue_context ie81->id = F1AP_ProtocolIE_ID_id_RRCContainer; ie81->criticality = F1AP_Criticality_ignore; ie81->value.present = F1AP_UEContextModificationRequestIEs__value_PR_RRCContainer; - OCTET_STRING_fromBuf(&ie81->value.choice.RRCContainer, f1ap_ue_context_modification_req->rrc_container, + OCTET_STRING_fromBuf(&ie81->value.choice.RRCContainer, (const char*)f1ap_ue_context_modification_req->rrc_container, f1ap_ue_context_modification_req->rrc_container_length); } diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index ce99a31dd3..7767606804 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -233,7 +233,6 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, ieRRC->value.choice.RRCContainer.buf, ieRRC->value.choice.RRCContainer.size); f1ap_ue_context_setup_req->rrc_container_length = ieRRC->value.choice.RRCContainer.size; // AssertFatal(0, "check configuration, send to appropriate handler\n"); - protocol_ctxt_t ctxt; } else { LOG_E(F1AP, " RRCContainer in UEContextSetupRequestIEs size id 0\n"); } @@ -294,15 +293,14 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, f1ap_ue_context_setup /* OPTIONAL */ /* measGapConfig */ if (resp->du_to_cu_rrc_information->measGapConfig!=NULL) { - OCTET_STRING_fromBuf(ie3->value.choice.DUtoCURRCInformation.measGapConfig, resp->du_to_cu_rrc_information->measGapConfig, + OCTET_STRING_fromBuf(ie3->value.choice.DUtoCURRCInformation.measGapConfig, (const char *)resp->du_to_cu_rrc_information->measGapConfig, resp->du_to_cu_rrc_information->measGapConfig_length); } /* OPTIONAL */ /* requestedP_MaxFR1 */ if (resp->du_to_cu_rrc_information->requestedP_MaxFR1!=NULL) { - asn1cCalloc(ie3->value.choice.DUtoCURRCInformation.requestedP_MaxFR1, tmp); - OCTET_STRING_fromBuf(ie3->value.choice.DUtoCURRCInformation.requestedP_MaxFR1, resp->du_to_cu_rrc_information->requestedP_MaxFR1, + OCTET_STRING_fromBuf(ie3->value.choice.DUtoCURRCInformation.requestedP_MaxFR1, (const char *)resp->du_to_cu_rrc_information->requestedP_MaxFR1, resp->du_to_cu_rrc_information->requestedP_MaxFR1_length); } } @@ -1290,14 +1288,14 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, f1ap_ue_contex /* OPTIONAL */ /* measGapConfig */ if (resp->du_to_cu_rrc_information->measGapConfig!=NULL) { - OCTET_STRING_fromBuf(ie4->value.choice.DUtoCURRCInformation.measGapConfig, resp->du_to_cu_rrc_information->measGapConfig, + OCTET_STRING_fromBuf(ie4->value.choice.DUtoCURRCInformation.measGapConfig, (const char *)resp->du_to_cu_rrc_information->measGapConfig, resp->du_to_cu_rrc_information->measGapConfig_length); } /* OPTIONAL */ /* requestedP_MaxFR1 */ if (resp->du_to_cu_rrc_information->requestedP_MaxFR1!=NULL) { - OCTET_STRING_fromBuf(ie4->value.choice.DUtoCURRCInformation.requestedP_MaxFR1, resp->du_to_cu_rrc_information->requestedP_MaxFR1, + OCTET_STRING_fromBuf(ie4->value.choice.DUtoCURRCInformation.requestedP_MaxFR1, (const char *)resp->du_to_cu_rrc_information->requestedP_MaxFR1, resp->du_to_cu_rrc_information->requestedP_MaxFR1_length); } } @@ -1358,9 +1356,8 @@ int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, f1ap_ue_contex F1AP_DRBs_Modified_Item_t *drbs_modified_item= &drbs_modified_item_ies->value.choice.DRBs_Modified_Item; /* dRBID */ drbs_modified_item->dRBID = resp->drbs_to_be_modified[i].drb_id; + /* ULTunnels_Modified_List */ - int maxnoofULTunnels = 1; // 2; - for (int j=0; jdrbs_to_be_modified[i].up_dl_tnl_length; j++) { /* DLTunnels_Modified_Item */ asn1cSequenceAdd(drbs_modified_item->dLUPTNLInformation_ToBeSetup_List.list, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 9105c9e93c..9258a2a826 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -36,6 +36,7 @@ #include #include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" +extern void process_CellGroup(NR_CellGroupConfig_t *CellGroup, NR_UE_sched_ctrl_t *sched_ctrl); int get_dci_format(NR_UE_sched_ctrl_t *sched_ctrl) { diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 97cc60d31c..992c33cb05 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1486,18 +1486,6 @@ rrc_gNB_process_RRCReconfigurationComplete( free(DRB_Release_configList2); ue_context_pP->ue_context.DRB_Release_configList2[xid] = NULL; } - //Temporarily trigger artificially UE context release for the CU case just to be able to test it with OAI UE. To be removed later - if(0){ - if(NODE_IS_CU(RC.nrrrc[ctxt_pP->instance]->node_type)){ - MessageDef *message_p; - message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, F1AP_UE_CONTEXT_RELEASE_CMD); - f1ap_ue_context_release_cmd_t *rel_cmd=&F1AP_UE_CONTEXT_RELEASE_CMD (message_p); - rel_cmd->rnti = ctxt_pP->rnti; - rel_cmd->cause = F1AP_CAUSE_RADIO_NETWORK; - rel_cmd->cause_value = 10; // 10 = F1AP_CauseRadioNetwork_normal_release - itti_send_msg_to_task(TASK_CU_F1, ctxt_pP->module_id, message_p); - } - } } //----------------------------------------------------------------------------- From 27bac2f2c4ae09c2f7ee73593ef030066de9b393 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Wed, 13 Apr 2022 15:33:37 +0100 Subject: [PATCH 078/267] The RI, PMI and CQI estimated at the UE are sent by the UE and correctly received by the gNB --- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 29 ++++++++++++++------ 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 7bb8fa93a3..b46bfecc35 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2590,7 +2590,7 @@ uint8_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, NR_CSI_ResourceConfigId_t csi_ResourceConfigId, NR_CSI_MeasConfig_t *csi_MeasConfig) { - int bits = 0; + int n_bits = 0; uint32_t temp_payload = 0; for (int csi_resourceidx = 0; csi_resourceidx < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_resourceidx++) { @@ -2607,14 +2607,27 @@ uint8_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, int cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; int ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; - int pmi_bitlen = csi_report->csi_meas_bitlen.pmi_x1_bitlen[*mac->csirs_measurements.rank_indicator] + - csi_report->csi_meas_bitlen.pmi_x2_bitlen[*mac->csirs_measurements.rank_indicator]; + int pmi_x1_bitlen = csi_report->csi_meas_bitlen.pmi_x1_bitlen[*mac->csirs_measurements.rank_indicator]; + int pmi_x2_bitlen = csi_report->csi_meas_bitlen.pmi_x2_bitlen[*mac->csirs_measurements.rank_indicator]; int cqi_bitlen = csi_report->csi_meas_bitlen.cqi_bitlen[*mac->csirs_measurements.rank_indicator]; - LOG_I(NR_MAC, "cri_bitlen = %d\n", cri_bitlen); - LOG_I(NR_MAC, "ri_bitlen = %d\n", ri_bitlen); - LOG_I(NR_MAC, "pmi_bitlen = %d\n", pmi_bitlen); - LOG_I(NR_MAC, "cqi_bitlen = %d\n", cqi_bitlen); + n_bits = cri_bitlen + ri_bitlen + pmi_x1_bitlen + pmi_x2_bitlen + cqi_bitlen; + + // TODO: Improvements will be needed to cri_bitlen>0 and pmi_x1_bitlen>0 + temp_payload = (*mac->csirs_measurements.rank_indicator<<(cri_bitlen+cqi_bitlen+pmi_x2_bitlen+pmi_x1_bitlen)) | + (*mac->csirs_measurements.i1<<(cri_bitlen+cqi_bitlen+pmi_x2_bitlen)) | + (*mac->csirs_measurements.i2<<(cri_bitlen+cqi_bitlen)) | + (*mac->csirs_measurements.cqi<csi_part1_payload = temp_payload; - return bits; + return n_bits; } // returns index from RSRP From ad3253fef62adaa029da975ec6fc6f8cdeb242c4 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Wed, 13 Apr 2022 19:45:10 +0100 Subject: [PATCH 079/267] Move CSI-RS configuration from fill_initial_SpCellConfig to update_cellGroupConfig --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 30 ++--------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index d690db3a75..81582a57c8 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1308,13 +1308,8 @@ void fill_initial_SpCellConfig(int uid, NR_PUCCH_SpatialRelationInfo_t *pucchspatial = calloc(1,sizeof(*pucchspatial)); pucchspatial->pucch_SpatialRelationInfoId = 1; pucchspatial->servingCellId = NULL; - - // TODO: Remove this if - if(!configuration->do_CSIRS) { - pucchspatial->referenceSignal.present = NR_PUCCH_SpatialRelationInfo__referenceSignal_PR_ssb_Index; - pucchspatial->referenceSignal.choice.ssb_Index = 0; - } - + pucchspatial->referenceSignal.present = NR_PUCCH_SpatialRelationInfo__referenceSignal_PR_ssb_Index; + pucchspatial->referenceSignal.choice.ssb_Index = 0; pucchspatial->pucch_PathlossReferenceRS_Id = 0; pucchspatial->p0_PUCCH_Id = 1; pucchspatial->closedLoopIndex = NR_PUCCH_SpatialRelationInfo__closedLoopIndex_i0; @@ -1608,25 +1603,6 @@ void fill_initial_SpCellConfig(int uid, SpCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->present = NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup; SpCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup = pdsch_servingcellconfig; - // TODO: Delete this code and calls in update_cellGroupConfig() - if (configuration->do_CSIRS) { - struct NR_PUCCH_Config__spatialRelationInfoToAddModList *spatialRelationInfoToAddModList = calloc(1,sizeof(*spatialRelationInfoToAddModList)); - NR_PUCCH_SpatialRelationInfo_t *pucchspatial = calloc(1,sizeof(*pucchspatial)); - pucchspatial->pucch_SpatialRelationInfoId = 1; - pucchspatial->servingCellId = NULL; - pucchspatial->referenceSignal.present = NR_PUCCH_SpatialRelationInfo__referenceSignal_PR_csi_RS_Index; - pucchspatial->referenceSignal.choice.csi_RS_Index = 0; - pucchspatial->pucch_PathlossReferenceRS_Id = 0; - pucchspatial->p0_PUCCH_Id = 1; - pucchspatial->closedLoopIndex = NR_PUCCH_SpatialRelationInfo__closedLoopIndex_i0; - ASN_SEQUENCE_ADD(&spatialRelationInfoToAddModList->list,pucchspatial); - SpCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pucch_Config->choice.setup->spatialRelationInfoToAddModList = spatialRelationInfoToAddModList; - if(!SpCellConfig->spCellConfigDedicated->csi_MeasConfig) { - SpCellConfig->spCellConfigDedicated->csi_MeasConfig=calloc(1,sizeof(*SpCellConfig->spCellConfigDedicated->csi_MeasConfig)); - } - fill_default_csi_MeasConfig(uid, SpCellConfig->spCellConfigDedicated->csi_MeasConfig, scc, configuration); - } - pdsch_servingcellconfig->codeBlockGroupTransmission = NULL; pdsch_servingcellconfig->xOverhead = NULL; pdsch_servingcellconfig->nrofHARQ_ProcessesForPDSCH = calloc(1, sizeof(*pdsch_servingcellconfig->nrofHARQ_ProcessesForPDSCH)); @@ -1734,7 +1710,6 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_ServingCellConfigCommon_t *scc = configuration->scc; // Config CSI-RS - /* if (configuration->do_CSIRS) { struct NR_PUCCH_Config__spatialRelationInfoToAddModList *spatialRelationInfoToAddModList = calloc(1,sizeof(*spatialRelationInfoToAddModList)); NR_PUCCH_SpatialRelationInfo_t *pucchspatial = calloc(1,sizeof(*pucchspatial)); @@ -1752,7 +1727,6 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, } fill_default_csi_MeasConfig(uid, SpCellConfig->spCellConfigDedicated->csi_MeasConfig, scc, configuration); } - */ // Set DL MCS table NR_BWP_DownlinkDedicated_t *bwp_Dedicated = SpCellConfig->spCellConfigDedicated->initialDownlinkBWP; From b216c58526c4afcea7e27cd4ae34b115efebd77b Mon Sep 17 00:00:00 2001 From: matzakos Date: Fri, 15 Apr 2022 10:34:53 +0200 Subject: [PATCH 080/267] Remove xml prints of F1AP messages --- openair2/F1AP/f1ap_decoder.c | 2 +- openair2/F1AP/f1ap_encoder.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/F1AP/f1ap_decoder.c b/openair2/F1AP/f1ap_decoder.c index beecf70401..60b3f94310 100644 --- a/openair2/F1AP/f1ap_decoder.c +++ b/openair2/F1AP/f1ap_decoder.c @@ -33,7 +33,7 @@ #include "f1ap_common.h" #include "f1ap_decoder.h" -int asn1_decoder_xer_print = 1; +int asn1_decoder_xer_print = 0; static int f1ap_decode_initiating_message(F1AP_F1AP_PDU_t *pdu) { //MessageDef *message_p; diff --git a/openair2/F1AP/f1ap_encoder.c b/openair2/F1AP/f1ap_encoder.c index e623e66536..b249f23cfe 100644 --- a/openair2/F1AP/f1ap_encoder.c +++ b/openair2/F1AP/f1ap_encoder.c @@ -33,7 +33,7 @@ #include "f1ap_common.h" #include "f1ap_encoder.h" -int asn1_encoder_xer_print = 1; +int asn1_encoder_xer_print = 0; int f1ap_encode_pdu(F1AP_F1AP_PDU_t *pdu, uint8_t **buffer, uint32_t *length) { ssize_t encoded; From 3feb0f472f263199e197fd7f4f9e99e61c793a1b Mon Sep 17 00:00:00 2001 From: matzakos Date: Fri, 15 Apr 2022 10:35:39 +0200 Subject: [PATCH 081/267] Add more proper parsing of NR-RAN gtp-u extension header --- openair3/ocp-gtpu/gtp_itf.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index 822825c75a..472ed0c44d 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -947,10 +947,20 @@ static int Gtpv1uHandleGpdu(int h, if(msgBuf[offset-1] == 0x84){ //Extension header corresponding to NR-RAN container type uint8_t PDU_type = (msgBuf[offset+1]>>4) & 0x0f; if (PDU_type == 0){ //DL USER Data Format - if((msgBuf[offset+2]>>2)& 0x3){ //"Report delivered" and "User data existence flags" enabled (TS 38.425, 5.4) + int additional_offset = 6; //Additional offset capturing the first non-mandatory octet (TS 38.425, Figure 5.5.2.1-1) + if(msgBuf[offset+1]>>2 & 0x1){ //DL Discard Blocks flag is present + LOG_I(GTPU, "DL User Data: DL Discard Blocks handling not enabled\n"); + additional_offset = additional_offset + 9; //For the moment ignore + } + if(msgBuf[offset+1]>>1 & 0x1){ //DL Flush flag is present + LOG_I(GTPU, "DL User Data: DL Flush handling not enabled\n"); + additional_offset = additional_offset + 3; //For the moment ignore + } + if((msgBuf[offset+2]>>3)& 0x1){ //"Report delivered" enabled (TS 38.425, 5.4) /*Store the NR PDCP PDU SN for which a delivery status report shall be generated once the *PDU gets forwarded to the lower layers*/ - NR_PDCP_PDU_SN = msgBuf[offset+3] << 16 | msgBuf[offset+4] << 8 | msgBuf[offset+5]; + //NR_PDCP_PDU_SN = msgBuf[offset+6] << 16 | msgBuf[offset+7] << 8 | msgBuf[offset+8]; + NR_PDCP_PDU_SN = msgBuf[offset+additional_offset] << 16 | msgBuf[offset+additional_offset+1] << 8 | msgBuf[offset+additional_offset+2]; LOG_D(GTPU, " NR_PDCP_PDU_SN: %u \n", NR_PDCP_PDU_SN); } } From 9b2a163ebb0c9766337d05a924c85c45bf46962b Mon Sep 17 00:00:00 2001 From: matzakos Date: Fri, 15 Apr 2022 10:36:31 +0200 Subject: [PATCH 082/267] Add true reporting of RLC buffer availability in first DDD report from DU to CU --- openair2/RRC/NR/rrc_gNB.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 11718d49b2..1c7b2a1ec9 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -99,6 +99,7 @@ #include #include #include +#include "LAYER2/nr_rlc/nr_rlc_oai_api.h" #include "BIT_STRING.h" #include "assertions.h" @@ -3491,13 +3492,14 @@ static void rrc_DU_process_ue_context_modification_request(MessageDef *msg_p, co LOG_I(NR_RRC, "Send first DDD buffer status reporting towards the CU through an ITTI message to gtp-u \n"); uint8_t drb_id = ue_context_p->ue_context.DRB_configList->list.array[0]->drb_Identity; rnti_t rnti = ue_context_p->ue_context.rnti; + int rlc_tx_buffer_space = nr_rlc_get_available_tx_space(rnti, drb_id); LOG_I(NR_RRC, "Reported in DDD drb_id:%d, rnti:%d\n", drb_id, rnti); MessageDef *msg = itti_alloc_new_message_sized(TASK_RRC_GNB, 0, GTPV1U_DU_BUFFER_REPORT_REQ, sizeof(gtpv1u_gnb_tunnel_data_req_t)); gtpv1u_DU_buffer_report_req_t *req=>PV1U_DU_BUFFER_REPORT_REQ(msg); req->pdusession_id = drb_id; req->rnti = rnti; - req->buffer_availability = 10000000; //Hardcoding to be removed and read the actual RLC buffer availability instead + req->buffer_availability = rlc_tx_buffer_space; //10000000; //Hardcoding to be removed and read the actual RLC buffer availability instead extern instance_t DUuniqInstance; itti_send_msg_to_task(TASK_GTPV1_U, DUuniqInstance, msg); From eb12cb8f10a446468cc0fa4202cd750ec503ca2b Mon Sep 17 00:00:00 2001 From: rmagueta Date: Mon, 18 Apr 2022 15:19:29 +0100 Subject: [PATCH 083/267] Fix CI test for FR2 RA --- ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf b/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf index 9353bd12d2..dcb3dd89b7 100644 --- a/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf +++ b/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf @@ -225,6 +225,7 @@ RUs = ( att_tx = 0; att_rx = 0; bands = [7]; + sl_ahead = 12; max_pdschReferenceSignalPower = -27; max_rxgain = 75; eNB_instances = [0]; From 2f753873bc9ebdf6c0156f440970cd8748c11e95 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Sat, 30 Apr 2022 16:12:27 +0100 Subject: [PATCH 084/267] =?UTF-8?q?Fix=20warning:=20this=20=E2=80=98if?= =?UTF-8?q?=E2=80=99=20clause=20does=20not=20guard...=20[-Wmisleading-inde?= =?UTF-8?q?ntation]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 8aace75610..18ffe85cad 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -451,10 +451,11 @@ int nr_process_mac_pdu(module_id_t module_idP, 0); break; - case UL_SCH_LCID_DTCH: - // check if LCID is valid at current time. - if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len)) - return 0; + case UL_SCH_LCID_DTCH: + // check if LCID is valid at current time. + if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len)) { + return 0; + } struct timespec time_request; clock_gettime(CLOCK_REALTIME, &time_request); @@ -471,24 +472,26 @@ int nr_process_mac_pdu(module_id_t module_idP, mac_len); UE_info->mac_stats[UE_id].lc_bytes_rx[rx_lcid] += mac_len; - mac_rlc_data_ind(module_idP, - UE_info->rnti[UE_id], - module_idP, - frameP, - ENB_FLAG_YES, - MBMS_FLAG_NO, - rx_lcid, - (char *)(pduP + mac_subheader_len), - mac_len, - 1, - NULL); + mac_rlc_data_ind(module_idP, + UE_info->rnti[UE_id], + module_idP, + frameP, + ENB_FLAG_YES, + MBMS_FLAG_NO, + rx_lcid, + (char *)(pduP + mac_subheader_len), + mac_len, + 1, + NULL); - /* Updated estimated buffer when receiving data */ - if (sched_ctrl->estimated_ul_buffer >= mac_len) - sched_ctrl->estimated_ul_buffer -= mac_len; - else - sched_ctrl->estimated_ul_buffer = 0; - break; + /* Updated estimated buffer when receiving data */ + if (sched_ctrl->estimated_ul_buffer >= mac_len) { + sched_ctrl->estimated_ul_buffer -= mac_len; + } else { + sched_ctrl->estimated_ul_buffer = 0; + } + + break; default: LOG_E(NR_MAC, "Received unknown MAC header (LCID = 0x%02x)\n", rx_lcid); From 73a1e92249c7dac925b98dca27955989b2d2d902 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 3 May 2022 12:09:19 +0100 Subject: [PATCH 085/267] Fix memory leaks --- openair1/PHY/INIT/nr_init_ue.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index e56de7d4db..941b59c8ed 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -523,6 +523,10 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) } free_and_zero(ue->nr_csi_rs_info->noise_power); free_and_zero(ue->nr_csi_rs_info->rank_indicator); + free_and_zero(ue->nr_csi_rs_info->i1); + free_and_zero(ue->nr_csi_rs_info->i2); + free_and_zero(ue->nr_csi_rs_info->precoded_sinr_dB); + free_and_zero(ue->nr_csi_rs_info->cqi); free_and_zero(ue->nr_csi_rs_info->nr_gold_csi_rs); free_and_zero(ue->nr_csi_rs_info->csi_rs_generated_signal); free_and_zero(ue->nr_csi_rs_info->csi_rs_received_signal); From 952a216b92433e06c3c725263e187fd51799241c Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Mon, 2 May 2022 11:37:19 +0100 Subject: [PATCH 086/267] Remove sib1_tda from configuration files to use default value --- targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf | 1 - targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf | 1 - .../CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf | 1 - .../GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf | 1 - .../GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf | 1 - .../CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf | 1 - .../GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf | 1 - 7 files changed, 7 deletions(-) diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf index c07a0db649..92d1ce432c 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf @@ -48,7 +48,6 @@ gNBs = pdsch_AntennaPorts = 1; pusch_AntennaPorts = 1; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf index 256d724f3f..f95bdf91ae 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf @@ -38,7 +38,6 @@ gNBs = ssb_SubcarrierOffset = 0; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf index 726e43d7ad..74f6c34f57 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf @@ -37,7 +37,6 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - sib1_tda = 0; servingCellConfigCommon = ( { #spCellConfigCommon diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf index 7e2db64aaa..d124c5692f 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf @@ -34,7 +34,6 @@ gNBs = ssb_SubcarrierOffset = 0; min_rxtxtime = 6; - sib1_tda = 0; do_SRS = 1; pdcch_ConfigSIB1 = ( diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf index cab801525b..ff64fe718a 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf @@ -36,7 +36,6 @@ gNBs = pdsch_AntennaPorts = 1; pusch_AntennaPorts = 1; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf index 950e9c1d38..1bc6de3bfe 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf @@ -35,7 +35,6 @@ gNBs = ssb_SubcarrierOffset = 0; pdsch_AntennaPorts_N1 = 2; pusch_AntennaPorts = 2; - sib1_tda = 0; do_SRS = 1; ul_prbblacklist = "51,52,53,54" diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf index 1dc903b811..a0cee6f9ca 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf @@ -34,7 +34,6 @@ gNBs = ssb_SubcarrierOffset = 0; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { From 39ea2c936fd16f551cc7a32d5c3c0aaa73b82084 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 4 May 2022 15:05:23 +0100 Subject: [PATCH 087/267] Creation of config_srs() function --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 123 +++------------------------- openair2/RRC/NR/nr_rrc_config.c | 107 +++++++++++++++++++++++- openair2/RRC/NR/nr_rrc_config.h | 4 + 3 files changed, 121 insertions(+), 113 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 9252a23596..c0676814f7 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -395,7 +395,6 @@ uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier, NR_BWP_DownlinkCommon_t *initialDownlinkBWP=&ServCellCom->downlinkConfigCommon.initialDownlinkBWP; initialDownlinkBWP->genericParameters= configuration->scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; - for(int i = 0; i< configuration->scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.count; i++) { asn1cSequenceAdd(ServCellCom->downlinkConfigCommon.frequencyInfoDL.frequencyBandList.list, @@ -403,7 +402,6 @@ uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier, nrMultiBandInfo->freqBandIndicatorNR = configuration->scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[i]; } - int scs_scaling0 = 1<<(configuration->scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.subcarrierSpacing); int scs_scaling = scs_scaling0; int scs_scaling2 = scs_scaling0; @@ -512,7 +510,6 @@ uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier, ss7->searchSpaceType->choice.common=calloc(1,sizeof(*ss7->searchSpaceType->choice.common)); ss7->searchSpaceType->choice.common->dci_Format0_0_AndFormat1_0 = calloc(1,sizeof(*ss7->searchSpaceType->choice.common->dci_Format0_0_AndFormat1_0)); - asn1cCallocOne(initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->searchSpaceSIB1, 0); asn1cCallocOne(initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->searchSpaceOtherSystemInformation, 7); asn1cCallocOne(initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->pagingSearchSpace, 5); @@ -980,36 +977,11 @@ uint8_t do_RRCReject(uint8_t Mod_id, return((enc_rval.encoded+7)/8); } -// TODO: Implement to b_SRS = 1 and b_SRS = 2 -long rrc_get_max_nr_csrs(uint8_t max_rbs, long b_SRS) { - - if(b_SRS>0) { - LOG_E(NR_RRC,"rrc_get_max_nr_csrs(): Not implemented yet for b_SRS>0\n"); - return 0; // This c_srs is always valid - } - - const uint16_t m_SRS[64] = { 4, 8, 12, 16, 16, 20, 24, 24, 28, 32, 36, 40, 48, 48, 52, 56, 60, 64, 72, 72, 76, 80, 88, - 96, 96, 104, 112, 120, 120, 120, 128, 128, 128, 132, 136, 144, 144, 144, 144, 152, 160, - 160, 160, 168, 176, 184, 192, 192, 192, 192, 208, 216, 224, 240, 240, 240, 240, 256, 256, - 256, 264, 272, 272, 272 }; - - long c_srs = 0; - uint16_t m = 4; - for(int c = 1; c<64; c++) { - if(m_SRS[c]>m && m_SRS[c]tp_pi2BPSK=NULL; initialUplinkBWP->srs_Config = calloc(1,sizeof(*initialUplinkBWP->srs_Config)); - initialUplinkBWP->srs_Config->present = NR_SetupRelease_SRS_Config_PR_setup; - NR_SRS_Config_t *srs_Config = calloc(1,sizeof(*srs_Config)); - initialUplinkBWP->srs_Config->choice.setup=srs_Config; - srs_Config->srs_ResourceSetToReleaseList=NULL; - srs_Config->srs_ResourceSetToAddModList=calloc(1,sizeof(*srs_Config->srs_ResourceSetToAddModList)); - NR_SRS_ResourceSet_t *srs_resset0=calloc(1,sizeof(*srs_resset0)); - srs_resset0->srs_ResourceSetId = 0; - srs_resset0->srs_ResourceIdList=calloc(1,sizeof(*srs_resset0->srs_ResourceIdList)); - NR_SRS_ResourceId_t *srs_resset0_id=calloc(1,sizeof(*srs_resset0_id)); - *srs_resset0_id=0; - ASN_SEQUENCE_ADD(&srs_resset0->srs_ResourceIdList->list,srs_resset0_id); - srs_Config->srs_ResourceToReleaseList=NULL; - - if (configuration->do_SRS) { - srs_resset0->resourceType.present = NR_SRS_ResourceSet__resourceType_PR_periodic; - srs_resset0->resourceType.choice.periodic = calloc(1,sizeof(*srs_resset0->resourceType.choice.periodic)); - srs_resset0->resourceType.choice.periodic->associatedCSI_RS = NULL; - } else { - srs_resset0->resourceType.present = NR_SRS_ResourceSet__resourceType_PR_aperiodic; - srs_resset0->resourceType.choice.aperiodic = calloc(1,sizeof(*srs_resset0->resourceType.choice.aperiodic)); - srs_resset0->resourceType.choice.aperiodic->aperiodicSRS_ResourceTrigger=1; - srs_resset0->resourceType.choice.aperiodic->csi_RS=NULL; - srs_resset0->resourceType.choice.aperiodic->slotOffset= calloc(1,sizeof(*srs_resset0->resourceType.choice.aperiodic->slotOffset)); - *srs_resset0->resourceType.choice.aperiodic->slotOffset=2; - srs_resset0->resourceType.choice.aperiodic->ext1=NULL; - } - - srs_resset0->usage=NR_SRS_ResourceSet__usage_codebook; - srs_resset0->alpha = calloc(1,sizeof(*srs_resset0->alpha)); - *srs_resset0->alpha = NR_Alpha_alpha1; - srs_resset0->p0=calloc(1,sizeof(*srs_resset0->p0)); - *srs_resset0->p0=-80; - srs_resset0->pathlossReferenceRS=NULL; - srs_resset0->srs_PowerControlAdjustmentStates=NULL; - ASN_SEQUENCE_ADD(&srs_Config->srs_ResourceSetToAddModList->list,srs_resset0); - srs_Config->srs_ResourceToReleaseList=NULL; - srs_Config->srs_ResourceToAddModList=calloc(1,sizeof(*srs_Config->srs_ResourceToAddModList)); - NR_SRS_Resource_t *srs_res0=calloc(1,sizeof(*srs_res0)); - srs_res0->srs_ResourceId=0; - srs_res0->nrofSRS_Ports=NR_SRS_Resource__nrofSRS_Ports_port1; - srs_res0->ptrs_PortIndex=NULL; - srs_res0->transmissionComb.present=NR_SRS_Resource__transmissionComb_PR_n2; - srs_res0->transmissionComb.choice.n2=calloc(1,sizeof(*srs_res0->transmissionComb.choice.n2)); - srs_res0->transmissionComb.choice.n2->combOffset_n2=0; - srs_res0->transmissionComb.choice.n2->cyclicShift_n2=0; - srs_res0->resourceMapping.startPosition = 2 + uid%2; - srs_res0->resourceMapping.nrofSymbols=NR_SRS_Resource__resourceMapping__nrofSymbols_n1; - srs_res0->resourceMapping.repetitionFactor=NR_SRS_Resource__resourceMapping__repetitionFactor_n1; - srs_res0->freqDomainPosition=0; - srs_res0->freqDomainShift=0; - srs_res0->freqHopping.b_SRS=0; - srs_res0->freqHopping.b_hop=0; - srs_res0->freqHopping.c_SRS = rrc_get_max_nr_csrs( - NRRIV2BW(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, 275), - srs_res0->freqHopping.b_SRS); - srs_res0->groupOrSequenceHopping=NR_SRS_Resource__groupOrSequenceHopping_neither; - - if (configuration->do_SRS) { - srs_res0->resourceType.present= NR_SRS_Resource__resourceType_PR_periodic; - srs_res0->resourceType.choice.periodic=calloc(1,sizeof(*srs_res0->resourceType.choice.periodic)); - srs_res0->resourceType.choice.periodic->periodicityAndOffset_p.present = NR_SRS_PeriodicityAndOffset_PR_sl160; - srs_res0->resourceType.choice.periodic->periodicityAndOffset_p.choice.sl160 = 17 + (uid>1)*10; // 17/17/.../147/157 are mixed slots - } else { - srs_res0->resourceType.present= NR_SRS_Resource__resourceType_PR_aperiodic; - srs_res0->resourceType.choice.aperiodic=calloc(1,sizeof(*srs_res0->resourceType.choice.aperiodic)); - } - - srs_res0->sequenceId=40; - srs_res0->spatialRelationInfo=calloc(1,sizeof(*srs_res0->spatialRelationInfo)); - srs_res0->spatialRelationInfo->servingCellId=NULL; - srs_res0->spatialRelationInfo->referenceSignal.present=NR_SRS_SpatialRelationInfo__referenceSignal_PR_csi_RS_Index; - srs_res0->spatialRelationInfo->referenceSignal.choice.csi_RS_Index=0; - ASN_SEQUENCE_ADD(&srs_Config->srs_ResourceToAddModList->list,srs_res0); + config_srs(initialUplinkBWP->srs_Config, scc, uid, configuration->do_SRS); // configure Scheduling request // 40 slot period @@ -1325,13 +1225,13 @@ void fill_initial_SpCellConfig(int uid, bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->maxLength=NULL; bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition)); - *bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = NR_DMRS_DownlinkConfig__dmrs_AdditionalPosition_pos1; - bwp_Dedicated->pdsch_Config->choice.setup->resourceAllocation = NR_PDSCH_Config__resourceAllocation_resourceAllocationType1; - bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.present = NR_PDSCH_Config__prb_BundlingType_PR_staticBundling; - bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling = calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling)); - bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize = - calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize)); - *bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize = NR_PDSCH_Config__prb_BundlingType__staticBundling__bundleSize_wideband; + *bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = NR_DMRS_DownlinkConfig__dmrs_AdditionalPosition_pos1; + bwp_Dedicated->pdsch_Config->choice.setup->resourceAllocation = NR_PDSCH_Config__resourceAllocation_resourceAllocationType1; + bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.present = NR_PDSCH_Config__prb_BundlingType_PR_staticBundling; + bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling = calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling)); + bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize = + calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize)); + *bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize = NR_PDSCH_Config__prb_BundlingType__staticBundling__bundleSize_wideband; bwp_Dedicated->pdsch_Config->choice.setup->tci_StatesToAddModList=calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->tci_StatesToAddModList)); NR_TCI_State_t *tcic; @@ -1351,6 +1251,7 @@ void fill_initial_SpCellConfig(int uid, NR_PDSCH_ServingCellConfig_t *pdsch_servingcellconfig = calloc(1,sizeof(*pdsch_servingcellconfig)); SpCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->present = NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup; SpCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup = pdsch_servingcellconfig; + pdsch_servingcellconfig->codeBlockGroupTransmission = NULL; pdsch_servingcellconfig->xOverhead = NULL; pdsch_servingcellconfig->nrofHARQ_ProcessesForPDSCH = calloc(1, sizeof(*pdsch_servingcellconfig->nrofHARQ_ProcessesForPDSCH)); @@ -1452,7 +1353,6 @@ void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGr ASN_SEQUENCE_ADD(&ue_context_mastercellGroup->rlc_BearerToAddModList->list, rlc_BearerConfig_drb); } - void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_UE_NR_Capability_t *uecap, const gNB_RrcConfigurationReq* configuration) { @@ -1476,7 +1376,6 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, } } - void fill_initial_cellGroupConfig(int uid, NR_CellGroupConfig_t *cellGroupConfig, NR_ServingCellConfigCommon_t *scc, diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 54fb5a168b..5bcdf86a95 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -81,7 +81,6 @@ void set_csirs_periodicity(NR_NZP_CSI_RS_Resource_t *nzpcsi0, int uid, int nb_sl } } - void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, NR_CSI_MeasConfig_t *csi_MeasConfig, int uid, @@ -170,6 +169,112 @@ void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, csi_MeasConfig->nzp_CSI_RS_ResourceToReleaseList = NULL; } +// TODO: Implement to b_SRS = 1 and b_SRS = 2 +long rrc_get_max_nr_csrs(uint8_t max_rbs, long b_SRS) { + + if(b_SRS>0) { + LOG_E(NR_RRC,"rrc_get_max_nr_csrs(): Not implemented yet for b_SRS>0\n"); + return 0; // This c_srs is always valid + } + + const uint16_t m_SRS[64] = { 4, 8, 12, 16, 16, 20, 24, 24, 28, 32, 36, 40, 48, 48, 52, 56, 60, 64, 72, 72, 76, 80, 88, + 96, 96, 104, 112, 120, 120, 120, 128, 128, 128, 132, 136, 144, 144, 144, 144, 152, 160, + 160, 160, 168, 176, 184, 192, 192, 192, 192, 208, 216, 224, 240, 240, 240, 240, 256, 256, + 256, 264, 272, 272, 272 }; + + long c_srs = 0; + uint16_t m = 4; + for(int c = 1; c<64; c++) { + if(m_SRS[c]>m && m_SRS[c]present = NR_SetupRelease_SRS_Config_PR_setup; + setup_release_srs_Config->choice.setup = calloc(1,sizeof(*setup_release_srs_Config->choice.setup)); + + NR_SRS_Config_t *srs_Config = setup_release_srs_Config->choice.setup; + + srs_Config->srs_ResourceSetToReleaseList = NULL; + + srs_Config->srs_ResourceSetToAddModList = calloc(1,sizeof(*srs_Config->srs_ResourceSetToAddModList)); + NR_SRS_ResourceSet_t *srs_resset0 = calloc(1,sizeof(*srs_resset0)); + srs_resset0->srs_ResourceSetId = 0; + srs_resset0->srs_ResourceIdList = calloc(1,sizeof(*srs_resset0->srs_ResourceIdList)); + NR_SRS_ResourceId_t *srs_resset0_id = calloc(1,sizeof(*srs_resset0_id)); + *srs_resset0_id = 0; + ASN_SEQUENCE_ADD(&srs_resset0->srs_ResourceIdList->list, srs_resset0_id); + srs_Config->srs_ResourceToReleaseList=NULL; + if (do_srs) { + srs_resset0->resourceType.present = NR_SRS_ResourceSet__resourceType_PR_periodic; + srs_resset0->resourceType.choice.periodic = calloc(1,sizeof(*srs_resset0->resourceType.choice.periodic)); + srs_resset0->resourceType.choice.periodic->associatedCSI_RS = NULL; + } else { + srs_resset0->resourceType.present = NR_SRS_ResourceSet__resourceType_PR_aperiodic; + srs_resset0->resourceType.choice.aperiodic = calloc(1,sizeof(*srs_resset0->resourceType.choice.aperiodic)); + srs_resset0->resourceType.choice.aperiodic->aperiodicSRS_ResourceTrigger=1; + srs_resset0->resourceType.choice.aperiodic->csi_RS=NULL; + srs_resset0->resourceType.choice.aperiodic->slotOffset = calloc(1,sizeof(*srs_resset0->resourceType.choice.aperiodic->slotOffset)); + *srs_resset0->resourceType.choice.aperiodic->slotOffset = 2; + srs_resset0->resourceType.choice.aperiodic->ext1 = NULL; + } + srs_resset0->usage=NR_SRS_ResourceSet__usage_codebook; + srs_resset0->alpha = calloc(1,sizeof(*srs_resset0->alpha)); + *srs_resset0->alpha = NR_Alpha_alpha1; + srs_resset0->p0 = calloc(1,sizeof(*srs_resset0->p0)); + *srs_resset0->p0 =-80; + srs_resset0->pathlossReferenceRS = NULL; + srs_resset0->srs_PowerControlAdjustmentStates = NULL; + ASN_SEQUENCE_ADD(&srs_Config->srs_ResourceSetToAddModList->list,srs_resset0); + + srs_Config->srs_ResourceToReleaseList = NULL; + + srs_Config->srs_ResourceToAddModList = calloc(1,sizeof(*srs_Config->srs_ResourceToAddModList)); + NR_SRS_Resource_t *srs_res0=calloc(1,sizeof(*srs_res0)); + srs_res0->srs_ResourceId = 0; + srs_res0->nrofSRS_Ports = NR_SRS_Resource__nrofSRS_Ports_port1; + srs_res0->ptrs_PortIndex = NULL; + srs_res0->transmissionComb.present = NR_SRS_Resource__transmissionComb_PR_n2; + srs_res0->transmissionComb.choice.n2 = calloc(1,sizeof(*srs_res0->transmissionComb.choice.n2)); + srs_res0->transmissionComb.choice.n2->combOffset_n2 = 0; + srs_res0->transmissionComb.choice.n2->cyclicShift_n2 = 0; + srs_res0->resourceMapping.startPosition = 2 + uid%2; + srs_res0->resourceMapping.nrofSymbols = NR_SRS_Resource__resourceMapping__nrofSymbols_n1; + srs_res0->resourceMapping.repetitionFactor = NR_SRS_Resource__resourceMapping__repetitionFactor_n1; + srs_res0->freqDomainPosition = 0; + srs_res0->freqDomainShift = 0; + srs_res0->freqHopping.b_SRS = 0; + srs_res0->freqHopping.b_hop = 0; + srs_res0->freqHopping.c_SRS = rrc_get_max_nr_csrs( + NRRIV2BW(servingcellconfigcommon->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, 275), + srs_res0->freqHopping.b_SRS); + srs_res0->groupOrSequenceHopping = NR_SRS_Resource__groupOrSequenceHopping_neither; + if (do_srs) { + srs_res0->resourceType.present = NR_SRS_Resource__resourceType_PR_periodic; + srs_res0->resourceType.choice.periodic = calloc(1,sizeof(*srs_res0->resourceType.choice.periodic)); + srs_res0->resourceType.choice.periodic->periodicityAndOffset_p.present = NR_SRS_PeriodicityAndOffset_PR_sl160; + srs_res0->resourceType.choice.periodic->periodicityAndOffset_p.choice.sl160 = 17 + (uid>1)*10; // 17/17/.../147/157 are mixed slots + } else { + srs_res0->resourceType.present = NR_SRS_Resource__resourceType_PR_aperiodic; + srs_res0->resourceType.choice.aperiodic = calloc(1,sizeof(*srs_res0->resourceType.choice.aperiodic)); + } + srs_res0->sequenceId = 40; + srs_res0->spatialRelationInfo = calloc(1,sizeof(*srs_res0->spatialRelationInfo)); + srs_res0->spatialRelationInfo->servingCellId = NULL; + srs_res0->spatialRelationInfo->referenceSignal.present = NR_SRS_SpatialRelationInfo__referenceSignal_PR_csi_RS_Index; + srs_res0->spatialRelationInfo->referenceSignal.choice.csi_RS_Index = 0; + ASN_SEQUENCE_ADD(&srs_Config->srs_ResourceToAddModList->list,srs_res0); +} + void prepare_sim_uecap(NR_UE_NR_Capability_t *cap, NR_ServingCellConfigCommon_t *scc, int numerology, diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index 7a0fe892fd..ff71f73333 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -119,6 +119,10 @@ void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, int num_dl_antenna_ports, int curr_bwp, int do_csirs); +void config_srs(NR_SetupRelease_SRS_Config_t *setup_release_srs_Config, + NR_ServingCellConfigCommon_t *servingcellconfigcommon, + int uid, + int do_srs); void set_dl_mcs_table(int scs, NR_UE_NR_Capability_t *cap, NR_BWP_DownlinkDedicated_t *bwp_Dedicated, NR_ServingCellConfigCommon_t *scc); From 70cfd057ec317f6d3cc7b791e1f6156f2ea10ebb Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 4 May 2022 15:09:59 +0100 Subject: [PATCH 088/267] Add do_SRS flag in gnb.sa.band78.fr1.106PRB.usrpb210.conf --- .../GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf index a0cee6f9ca..22f02f66e4 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf @@ -34,6 +34,7 @@ gNBs = ssb_SubcarrierOffset = 0; min_rxtxtime = 6; + do_SRS = 1; pdcch_ConfigSIB1 = ( { From 2fb8d96f1153bc229668e127218e01872de32d14 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 4 May 2022 16:25:15 +0100 Subject: [PATCH 089/267] Move SRS config to update_cellGroupConfig() --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 21 ++++++++++++++++++++- openair2/RRC/NR/MESSAGES/asn1_msg.h | 1 + openair2/RRC/NR/nr_rrc_config.c | 29 ++++++++++++++++++++++++----- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index c0676814f7..3e38c772da 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1098,8 +1098,9 @@ void fill_initial_SpCellConfig(int uid, pusch_Config->uci_OnPUSCH=NULL; pusch_Config->tp_pi2BPSK=NULL; + // We are using do_srs = 0 here because the periodic SRS will only be enabled in update_cellGroupConfig() if do_srs == 1 initialUplinkBWP->srs_Config = calloc(1,sizeof(*initialUplinkBWP->srs_Config)); - config_srs(initialUplinkBWP->srs_Config, scc, uid, configuration->do_SRS); + config_srs(initialUplinkBWP->srs_Config, scc, uid, 0); // configure Scheduling request // 40 slot period @@ -1354,6 +1355,7 @@ void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGr } void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, + int uid, NR_UE_NR_Capability_t *uecap, const gNB_RrcConfigurationReq* configuration) { @@ -1362,6 +1364,22 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_ServingCellConfigCommon_t *scc = configuration->scc; + if (configuration && + configuration->do_SRS && + SpCellConfig && + SpCellConfig->spCellConfigDedicated && + SpCellConfig->spCellConfigDedicated->uplinkConfig && + SpCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { + if (!SpCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->srs_Config) { + SpCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->srs_Config = + calloc(1,sizeof(*SpCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->srs_Config)); + } + config_srs(SpCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->srs_Config, + scc, + uid, + configuration->do_SRS); + } + NR_BWP_DownlinkDedicated_t *bwp_Dedicated = SpCellConfig->spCellConfigDedicated->initialDownlinkBWP; set_dl_mcs_table(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.subcarrierSpacing, configuration->force_256qam_off ? NULL : uecap, bwp_Dedicated, scc); @@ -1850,6 +1868,7 @@ int16_t do_RRCReconfiguration( if(cellGroupConfig!=NULL){ update_cellGroupConfig(cellGroupConfig, + ue_context_pP->local_uid, ue_context_pP->ue_context.UE_Capability_nr, configuration); diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index aeef5f93a7..f056088da8 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -112,6 +112,7 @@ void fill_initial_cellGroupConfig(int uid, const gNB_RrcConfigurationReq *configuration); void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, + int uid, NR_UE_NR_Capability_t *uecap, const gNB_RrcConfigurationReq *configuration); diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 5bcdf86a95..2e44a8022e 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -200,9 +200,27 @@ void config_srs(NR_SetupRelease_SRS_Config_t *setup_release_srs_Config, int do_srs) { setup_release_srs_Config->present = NR_SetupRelease_SRS_Config_PR_setup; - setup_release_srs_Config->choice.setup = calloc(1,sizeof(*setup_release_srs_Config->choice.setup)); - NR_SRS_Config_t *srs_Config = setup_release_srs_Config->choice.setup; + NR_SRS_Config_t *srs_Config; + if (setup_release_srs_Config->choice.setup) { + srs_Config = setup_release_srs_Config->choice.setup; + if (srs_Config->srs_ResourceSetToReleaseList) { + free(srs_Config->srs_ResourceSetToReleaseList); + } + if (srs_Config->srs_ResourceSetToAddModList) { + free(srs_Config->srs_ResourceSetToAddModList); + } + if (srs_Config->srs_ResourceToReleaseList) { + free(srs_Config->srs_ResourceToReleaseList); + } + if (srs_Config->srs_ResourceToAddModList) { + free(srs_Config->srs_ResourceToAddModList); + } + free(srs_Config); + } + + setup_release_srs_Config->choice.setup = calloc(1,sizeof(*setup_release_srs_Config->choice.setup)); + srs_Config = setup_release_srs_Config->choice.setup; srs_Config->srs_ResourceSetToReleaseList = NULL; @@ -254,9 +272,10 @@ void config_srs(NR_SetupRelease_SRS_Config_t *setup_release_srs_Config, srs_res0->freqDomainShift = 0; srs_res0->freqHopping.b_SRS = 0; srs_res0->freqHopping.b_hop = 0; - srs_res0->freqHopping.c_SRS = rrc_get_max_nr_csrs( - NRRIV2BW(servingcellconfigcommon->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, 275), - srs_res0->freqHopping.b_SRS); + srs_res0->freqHopping.c_SRS = servingcellconfigcommon ? + rrc_get_max_nr_csrs( + NRRIV2BW(servingcellconfigcommon->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, 275), + srs_res0->freqHopping.b_SRS) : 0; srs_res0->groupOrSequenceHopping = NR_SRS_Resource__groupOrSequenceHopping_neither; if (do_srs) { srs_res0->resourceType.present = NR_SRS_Resource__resourceType_PR_periodic; From b106913dc0c72a8c276067892e95e81ba6269956 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 5 May 2022 18:10:08 +0100 Subject: [PATCH 090/267] Send SRS measurements (still empty) from PHY to MAC --- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 13 +++++++ .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 12 +++++++ openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 12 ++++++- openair2/NR_PHY_INTERFACE/NR_IF_Module.c | 36 +++++++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 46816d0373..c071127717 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -829,6 +829,19 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { T(T_GNB_PHY_UL_TIME_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), T_BUFFER(gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted[0], gNB->frame_parms.ofdm_symbol_size*sizeof(int32_t))); + uint16_t num_srs = gNB->UL_INFO.srs_ind.number_of_pdus; + gNB->UL_INFO.srs_ind.pdu_list = &gNB->srs_pdu_list[0]; + gNB->UL_INFO.srs_ind.sfn = frame_rx; + gNB->UL_INFO.srs_ind.slot = slot_rx; + //gNB->srs_pdu_list[num_srs].handle; + gNB->srs_pdu_list[num_srs].rnti = srs_pdu->rnti; + //gNB->srs_pdu_list[num_srs].timing_advance; + gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; + //gNB->srs_pdu_list[num_srs].wide_band_snr; + //gNB->srs_pdu_list[num_srs].num_reported_symbols; + //gNB->srs_pdu_list[num_srs].reported_symbol_list; + gNB->UL_INFO.srs_ind.number_of_pdus += 1; + srs->active = 0; } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 72061bb9ba..b3a241af0b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -879,6 +879,18 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, } } +void handle_nr_srs_measurements(const module_id_t module_id, + const frame_t frame, + const sub_frame_t slot, + const rnti_t rnti, + const uint16_t timing_advance, + const uint8_t num_symbols, + const uint8_t wide_band_snr, + const uint8_t num_reported_symbols, + nfapi_nr_srs_indication_reported_symbol_t* reported_symbol_list) { + LOG_I(NR_MAC, "(%d.%d) Received SRS indication for rnti: 0x%04x\n", frame, slot, rnti); +} + long get_K2(NR_ServingCellConfigCommon_t *scc, NR_ServingCellConfigCommonSIB_t *scc_sib1, NR_BWP_Uplink_t *ubwp, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 399033abd0..9b299eb1a3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -482,9 +482,19 @@ void handle_nr_ul_harq(const int CC_idP, sub_frame_t slot, const nfapi_nr_crc_t *crc_pdu); +void handle_nr_srs_measurements(const module_id_t module_id, + const frame_t frame, + const sub_frame_t slot, + const rnti_t rnti, + const uint16_t timing_advance, + const uint8_t num_symbols, + const uint8_t wide_band_snr, + const uint8_t num_reported_symbols, + nfapi_nr_srs_indication_reported_symbol_t* reported_symbol_list); + int16_t ssb_index_from_prach(module_id_t module_idP, frame_t frameP, - sub_frame_t slotP, + sub_frame_t slotP, uint16_t preamble_index, uint8_t freq_index, uint8_t symbol); diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c index 2654988557..4b8edd526f 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c @@ -217,6 +217,41 @@ void handle_nr_ulsch(NR_UL_IND_t *UL_info) UL_info->crc_ind.number_crcs = 0; } +void handle_nr_srs(NR_UL_IND_t *UL_info) { + + if(NFAPI_MODE == NFAPI_MODE_PNF) { + if (UL_info->srs_ind.number_of_pdus > 0) { + LOG_D(PHY,"PNF Sending UL_info->srs_ind.number_of_pdus: %d, SFN/SF:%d.%d \n", + UL_info->srs_ind.number_of_pdus, UL_info->frame, UL_info->slot); + oai_nfapi_nr_srs_indication(&UL_info->srs_ind); + UL_info->srs_ind.number_of_pdus = 0; + } + return; + } + + const module_id_t module_id = UL_info->module_id; + const frame_t frame = UL_info->srs_ind.sfn; + const sub_frame_t slot = UL_info->srs_ind.slot; + int num_srs = UL_info->srs_ind.number_of_pdus; + nfapi_nr_srs_indication_pdu_t *srs_list = UL_info->srs_ind.pdu_list; + + for (int i = 0; i < num_srs; i++) { + const nfapi_nr_srs_indication_pdu_t *srs_ind = &srs_list[i]; + LOG_D(NR_PHY, "(%d.%d) UL_info->srs_ind.pdu_list[%d].rnti: 0x%04x\n", frame, slot, i, srs_ind->rnti); + handle_nr_srs_measurements(module_id, + frame, + slot, + srs_ind->rnti, + srs_ind->timing_advance, + srs_ind->num_symbols, + srs_ind->wide_band_snr, + srs_ind->num_reported_symbols, + srs_ind->reported_symbol_list); + } + + UL_info->srs_ind.number_of_pdus = 0; +} + static void free_unqueued_nfapi_indications(nfapi_nr_rach_indication_t *rach_ind, nfapi_nr_uci_indication_t *uci_ind, nfapi_nr_rx_data_indication_t *rx_ind, @@ -436,6 +471,7 @@ void NR_UL_indication(NR_UL_IND_t *UL_info) { // clear UL DCI prior to handling ULSCH mac->UL_dci_req[CC_id].numPdus = 0; handle_nr_ulsch(UL_info); + handle_nr_srs(UL_info); if (get_softmodem_params()->emulate_l1) { free_unqueued_nfapi_indications(rach_ind, uci_ind, rx_ind, crc_ind); From dce83a05089e225706fe8380ae924ae1bf8d3420 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 5 May 2022 19:49:06 +0100 Subject: [PATCH 091/267] Add comments in FAPI for SRS indication --- .../nfapi/public_inc/nfapi_nr_interface_scf.h | 47 ++++++++----------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index c3a173758c..0326bd20b1 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -1665,41 +1665,34 @@ typedef struct } nfapi_nr_uci_indication_t; -//3.4.10 srs_indication -//table 3-73 -typedef struct -{ - uint8_t rb_snr; -}nfapi_nr_srs_indication_reported_symbol_resource_block_t; +/// 5G PHY FAPI Specification: SRS indication - Section 3.4.10, Table 3-73 -typedef struct -{ - uint16_t num_rbs; +typedef struct { + uint8_t rb_snr; // SNR value in dB. Value: 0 -> 255 representing -64 dB to 63 dB with a step size 0.5 dB, 0xff will be set if this field is invalid. +} nfapi_nr_srs_indication_reported_symbol_resource_block_t; + +typedef struct { + uint16_t num_rbs; // Number of PRBs to be reported for this SRS PDU. Value: 0 -> 272. nfapi_nr_srs_indication_reported_symbol_resource_block_t* rb_list; -}nfapi_nr_srs_indication_reported_symbol_t; +} nfapi_nr_srs_indication_reported_symbol_t; -#define NFAPI_NR_SRS_IND_MAX_PDU 100 -typedef struct -{ - uint32_t handle; - uint16_t rnti; - uint16_t timing_advance; - uint8_t num_symbols; - uint8_t wide_band_snr; - uint8_t num_reported_symbols; +typedef struct { + uint32_t handle; // The handle passed to the PHY in the the UL_TTI.request SRS PDU. + uint16_t rnti; // The RNTI passed to the PHY in the UL_TTI.request SRS PDU. Value: 1 -> 65535. + uint16_t timing_advance; // Timing advance TA measured for the UE [TS 38.213, Section 4.2]. NTA_new = NTA_old + (TA − 31) * 16 * 64 / (2^u). Value: 0 -> 63. 0xffff should be set if this field is invalid. + uint8_t num_symbols; // Number of symbols for SRS. Value: 1 -> 4. If a PHY does not report for individual symbols then this parameter should be set to 1. + uint8_t wide_band_snr; // SNR value in dB measured within configured SRS bandwidth on each symbol. Value: 0 -> 255 representing -64 dB to 63 dB with a step size 0.5 dB. 0xff will be set if this field is invalid. + uint8_t num_reported_symbols; // Number of symbols reported in this message. This allows PHY to report individual symbols or aggregated symbols where this field will be set to 1. Value: 1 -> 4. nfapi_nr_srs_indication_reported_symbol_t* reported_symbol_list; +} nfapi_nr_srs_indication_pdu_t; -}nfapi_nr_srs_indication_pdu_t; - -typedef struct -{ +typedef struct { nfapi_p7_message_header_t header; - uint16_t sfn; - uint16_t slot; - uint8_t number_of_pdus; + uint16_t sfn; // SFN. Value: 0 -> 1023 + uint16_t slot; // Slot. Value: 0 -> 159 + uint8_t number_of_pdus; // Number of PDUs included in this message. Value: 0 -> 255 nfapi_nr_srs_indication_pdu_t* pdu_list; - } nfapi_nr_srs_indication_t; From dcf4fd1db2270e1780680712e905f964a83d44ee Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Fri, 6 May 2022 19:07:59 +0100 Subject: [PATCH 092/267] Compute the noise power per RB --- openair1/PHY/INIT/nr_init.c | 1 + .../NR_ESTIMATION/nr_ul_channel_estimation.c | 45 +++++++++++++++++++ openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 1 + openair1/PHY/defs_nr_common.h | 1 + openair1/SCHED_NR/phy_procedures_nr_gNB.c | 1 + 5 files changed, 49 insertions(+) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 9ffc0f75ad..64bbdfa487 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -618,6 +618,7 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, gNB->nr_srs_info[id] = (nr_srs_info_t *)malloc16_clear(sizeof(nr_srs_info_t)); gNB->nr_srs_info[id]->sc_list = (uint16_t *) malloc16_clear(6*fp->N_RB_UL*sizeof(uint16_t)); gNB->nr_srs_info[id]->srs_generated_signal = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); + gNB->nr_srs_info[id]->noise_power_per_rb = (uint32_t*)malloc16_clear(fp->N_RB_UL*sizeof(uint32_t)); gNB->nr_srs_info[id]->noise_power = (uint32_t*)malloc16_clear(sizeof(uint32_t)); gNB->nr_srs_info[id]->srs_received_signal = (int32_t **)malloc16(Prx*sizeof(int32_t*)); gNB->nr_srs_info[id]->srs_ls_estimated_channel = (int32_t **)malloc16(Prx*sizeof(int32_t*)); diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 4a6f8ef9af..ffdf07860d 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -1099,6 +1099,7 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, int32_t **srs_estimated_channel_freq, int32_t **srs_estimated_channel_time, int32_t **srs_estimated_channel_time_shifted, + uint32_t *noise_power_per_rb, uint32_t *noise_power) { if(nr_srs_info->sc_list_length == 0) { @@ -1216,6 +1217,50 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, (gNB->frame_parms.ofdm_symbol_size>>1)*sizeof(int32_t)); } + // Compute noise power + + uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start*12; + uint8_t srs_symbols_per_rb = srs_pdu->comb_size == 0 ? 6 : 3; + uint8_t n_noise_estimates = frame_parms->nb_antennas_rx*srs_symbols_per_rb; + uint8_t count_estimates = 0; + uint64_t sum_re = 0; + uint64_t sum_re2 = 0; + uint64_t sum_im = 0; + uint64_t sum_im2 = 0; + + for (int sc_idx = 0; sc_idx < nr_srs_info->sc_list_length; sc_idx++) { + + int subcarrier0 = nr_srs_info->sc_list[sc_idx]-subcarrier_offset; + if(subcarrier0 < 0) { + subcarrier0 = subcarrier0 + frame_parms->ofdm_symbol_size; + } + int rb = subcarrier0/NR_NB_SC_PER_RB; + + for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) { + + sum_re = sum_re + noise_real[ant*nr_srs_info->sc_list_length+sc_idx]; + sum_re2 = sum_re2 + noise_real[ant*nr_srs_info->sc_list_length+sc_idx]*noise_real[ant*nr_srs_info->sc_list_length+sc_idx]; + sum_im = sum_im + noise_imag[ant*nr_srs_info->sc_list_length+sc_idx]; + sum_im2 = sum_im2 + noise_imag[ant*nr_srs_info->sc_list_length+sc_idx]*noise_imag[ant*nr_srs_info->sc_list_length+sc_idx]; + + count_estimates++; + if (count_estimates == n_noise_estimates) { + noise_power_per_rb[rb] = sum_re2/n_noise_estimates - (sum_re/n_noise_estimates)*(sum_re/n_noise_estimates) + + sum_im2/n_noise_estimates - (sum_im/n_noise_estimates)*(sum_im/n_noise_estimates); + count_estimates = 0; + sum_re = 0; + sum_re2 = 0; + sum_im = 0; + sum_im2 = 0; + +#ifdef SRS_DEBUG + LOG_I(NR_PHY,"noise_power_per_rb[%i] = %i\n", rb, noise_power_per_rb[rb]); +#endif + + } + } + } + *noise_power = calc_power(noise_real,frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length) + calc_power(noise_imag,frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length); diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index a01106adb5..9c7d67b25d 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -73,5 +73,6 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, int32_t **srs_estimated_channel_freq, int32_t **srs_estimated_channel_time, int32_t **srs_estimated_channel_time_shifted, + uint32_t *noise_power_per_rb, uint32_t *noise_power); #endif diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index b24abd7de3..80842eef38 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -244,6 +244,7 @@ typedef struct { int32_t **srs_estimated_channel_freq; int32_t **srs_estimated_channel_time; int32_t **srs_estimated_channel_time_shifted; + uint32_t *noise_power_per_rb; uint32_t *noise_power; } nr_srs_info_t; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index c9f4cf7b33..aa75cc64ef 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -834,6 +834,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->nr_srs_info[i]->srs_estimated_channel_freq, gNB->nr_srs_info[i]->srs_estimated_channel_time, gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted, + gNB->nr_srs_info[i]->noise_power_per_rb, gNB->nr_srs_info[i]->noise_power); T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), From ab6d7afd09b02963ba345c983acef44acfdf8322 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Mon, 9 May 2022 15:54:20 +0100 Subject: [PATCH 093/267] Compute the SNR per RB using the SRS --- openair1/PHY/INIT/nr_init.c | 2 + .../NR_ESTIMATION/nr_ul_channel_estimation.c | 37 ++++++++++++++----- openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 4 +- openair1/PHY/defs_nr_common.h | 2 + openair1/SCHED_NR/phy_procedures_nr_gNB.c | 4 +- 5 files changed, 38 insertions(+), 11 deletions(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 64bbdfa487..21ebcc1405 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -618,8 +618,10 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, gNB->nr_srs_info[id] = (nr_srs_info_t *)malloc16_clear(sizeof(nr_srs_info_t)); gNB->nr_srs_info[id]->sc_list = (uint16_t *) malloc16_clear(6*fp->N_RB_UL*sizeof(uint16_t)); gNB->nr_srs_info[id]->srs_generated_signal = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); + gNB->nr_srs_info[id]->signal_power = (uint32_t*)malloc16_clear(sizeof(uint32_t)); gNB->nr_srs_info[id]->noise_power_per_rb = (uint32_t*)malloc16_clear(fp->N_RB_UL*sizeof(uint32_t)); gNB->nr_srs_info[id]->noise_power = (uint32_t*)malloc16_clear(sizeof(uint32_t)); + gNB->nr_srs_info[id]->snr_per_rb = (int8_t*)malloc16_clear(fp->N_RB_UL*sizeof(int8_t)); gNB->nr_srs_info[id]->srs_received_signal = (int32_t **)malloc16(Prx*sizeof(int32_t*)); gNB->nr_srs_info[id]->srs_ls_estimated_channel = (int32_t **)malloc16(Prx*sizeof(int32_t*)); gNB->nr_srs_info[id]->srs_estimated_channel_freq = (int32_t **)malloc16(Prx*sizeof(int32_t*)); diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index ffdf07860d..8db33e3e18 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -1079,9 +1079,9 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, }//Antenna loop } -uint32_t calc_power(uint16_t *x, uint32_t size) { - uint64_t sum_x = 0; - uint64_t sum_x2 = 0; +uint32_t calc_power(const int16_t *x, uint32_t size) { + int64_t sum_x = 0; + int64_t sum_x2 = 0; for(int k = 0; ksc_list_length == 0) { LOG_E(NR_PHY, "(%d.%d) nr_srs_info was not generated yet!\n", frame, slot); @@ -1110,8 +1112,10 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; int32_t **srs_ls_estimated_channel = nr_srs_info->srs_ls_estimated_channel; - uint16_t noise_real[frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length]; - uint16_t noise_imag[frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length]; + int16_t ch_real[frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length]; + int16_t ch_imag[frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length]; + int16_t noise_real[frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length]; + int16_t noise_imag[frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length]; int16_t ls_estimated[2]; @@ -1199,8 +1203,10 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, // Compute noise for(int sc_idx = 0; sc_idx < nr_srs_info->sc_list_length; sc_idx++) { - noise_real[ant*nr_srs_info->sc_list_length + sc_idx] = abs((int16_t)((srs_ls_estimated_channel[ant][nr_srs_info->sc_list[sc_idx]]-srs_estimated_channel_freq[ant][nr_srs_info->sc_list[sc_idx]]) & 0xFFFF)); - noise_imag[ant*nr_srs_info->sc_list_length + sc_idx] = abs((int16_t)(((srs_ls_estimated_channel[ant][nr_srs_info->sc_list[sc_idx]]-srs_estimated_channel_freq[ant][nr_srs_info->sc_list[sc_idx]]) >> 16) & 0xFFFF)); + ch_real[ant*nr_srs_info->sc_list_length + sc_idx] = (int16_t)(srs_estimated_channel_freq[ant][nr_srs_info->sc_list[sc_idx]] & 0xFFFF); + ch_imag[ant*nr_srs_info->sc_list_length + sc_idx] = (int16_t)((srs_estimated_channel_freq[ant][nr_srs_info->sc_list[sc_idx]] >> 16) & 0xFFFF); + noise_real[ant*nr_srs_info->sc_list_length + sc_idx] = abs((int16_t)(srs_ls_estimated_channel[ant][nr_srs_info->sc_list[sc_idx]] & 0xFFFF) - ch_real[ant*nr_srs_info->sc_list_length + sc_idx]); + noise_imag[ant*nr_srs_info->sc_list_length + sc_idx] = abs((int16_t)((srs_ls_estimated_channel[ant][nr_srs_info->sc_list[sc_idx]] >> 16) & 0xFFFF) - ch_imag[ant*nr_srs_info->sc_list_length + sc_idx]); } // Convert to time domain @@ -1217,8 +1223,20 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, (gNB->frame_parms.ofdm_symbol_size>>1)*sizeof(int32_t)); } + // Compute signal power + *signal_power = calc_power(ch_real,frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length) + + calc_power(ch_imag,frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length); + +#ifdef SRS_DEBUG + LOG_I(NR_PHY,"signal_power = %u\n", *signal_power); +#endif + // Compute noise power + uint8_t signal_power_bits = log2_approx(*signal_power); + uint8_t factor_bits = signal_power_bits < 32 ? 32 - signal_power_bits : 0; // 32 due to input of dB_fixed(uint32_t x) + int32_t factor_dB = dB_fixed(1<first_carrier_offset + srs_pdu->bwp_start*12; uint8_t srs_symbols_per_rb = srs_pdu->comb_size == 0 ? 6 : 3; uint8_t n_noise_estimates = frame_parms->nb_antennas_rx*srs_symbols_per_rb; @@ -1247,6 +1265,7 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, if (count_estimates == n_noise_estimates) { noise_power_per_rb[rb] = sum_re2/n_noise_estimates - (sum_re/n_noise_estimates)*(sum_re/n_noise_estimates) + sum_im2/n_noise_estimates - (sum_im/n_noise_estimates)*(sum_im/n_noise_estimates); + snr_per_rb[rb] = dB_fixed((int32_t)((*signal_power<nr_srs_info[i]->srs_estimated_channel_freq, gNB->nr_srs_info[i]->srs_estimated_channel_time, gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted, + gNB->nr_srs_info[i]->signal_power, gNB->nr_srs_info[i]->noise_power_per_rb, - gNB->nr_srs_info[i]->noise_power); + gNB->nr_srs_info[i]->noise_power, + gNB->nr_srs_info[i]->snr_per_rb); T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), T_BUFFER(gNB->nr_srs_info[i]->srs_estimated_channel_freq[0], gNB->frame_parms.ofdm_symbol_size*sizeof(int32_t))); From a037987b474e25f2f0011eabe149228e689ddd38 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 9 May 2022 18:28:56 +0200 Subject: [PATCH 094/267] remove ssb subcarrier offset from config file --- ci-scripts/conf_files/benetel-5g.conf | 2 -- ...sci_gnb.band78.sa.fr1.106PRB.usrpn310.conf | 1 - .../episci_rcc.band78.tm1.106PRB.nfapi.conf | 1 - ...oxy_gnb.band78.sa.fr1.106PRB.usrpn310.conf | 1 - .../proxy_rcc.band78.tm1.106PRB.nfapi.conf | 1 - ci-scripts/conf_files/gNB_SA_CU.conf | 1 - ci-scripts/conf_files/gNB_SA_DU.conf | 1 - .../gNB_SA_n78_106PRB.2x2_usrpn310.conf | 1 - .../gNB_SA_n78_133PRB.2x2_usrpn310.conf | 1 - .../gnb.band261.tm1.32PRB.usrpn300.conf | 1 - .../gnb.band66.tm1.106PRB.usrpn300.conf | 1 - .../gnb.band78.nsa_2x2.106PRB.usrpn310.conf | 1 - ...and78.sa.fr1.106PRB.2x2.usrpn310.asue.conf | 1 - ...gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf | 1 - ...nd78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf | 1 - .../gnb.band78.sa.fr1.106PRB.usrpn310.conf | 1 - ...gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf | 1 - .../gnb.band78.tm1.106PRB.usrpn300.conf | 1 - .../gnb.band78.tm1.fr1.106PRB.usrpb210.conf | 1 - .../gnb.band78.tm1.fr1.106PRB.usrpn310.conf | 1 - .../gnb.sa.band66.fr1.106PRB.usrpn300.conf | 1 - .../gnb.sa.band78.fr1.24PRB.usrpb210.conf | 3 -- doc/testing_gnb_w_cots_ue_resources/gnb.conf | 2 -- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 17 ++-------- openair1/SIMULATION/NR_PHY/dlsim.c | 8 ++--- openair1/SIMULATION/NR_PHY/pbchsim.c | 2 +- openair1/SIMULATION/NR_PHY/ulsim.c | 4 +-- openair2/COMMON/rrc_messages_types.h | 1 - openair2/GNB_APP/gnb_config.c | 3 -- openair2/GNB_APP/gnb_paramdef.h | 29 ++++++++--------- openair2/LAYER2/NR_MAC_UE/config_ue.c | 4 ++- openair2/LAYER2/NR_MAC_gNB/config.c | 31 ++++++++----------- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 12 ------- openair2/RRC/NR/MESSAGES/asn1_msg.c | 21 ++++++++----- openair2/RRC/NR/rrc_gNB.c | 4 --- openair2/RRC/NR/rrc_gNB_nsa.c | 2 -- .../GENERIC-LTE-EPC/CONF/benetel-5g.conf | 1 - .../CONF/gnb.band257.tm1.32PRB.usrpn300.conf | 1 - .../CONF/gnb.band257.tm1.32PRB.usrpx300.conf | 1 - .../CONF/gnb.band257.tm1.66PRB.usrpn300.conf | 2 -- .../CONF/gnb.band261.tm1.32PRB.usrpn300.conf | 1 - .../CONF/gnb.band66.tm1.106PRB.usrpn300.conf | 1 - .../CONF/gnb.band66.tm1.106PRB.usrpx300.conf | 2 -- .../gnb.band78.106PRB.30kHz,usrpb2x0.conf | 1 - .../CONF/gnb.band78.106PRB.slave.conf | 1 - .../CONF/gnb.band78.slave.conf | 2 -- .../gnb.band78.tm1.106PRB.PTRS.usrpx300.conf | 2 -- .../CONF/gnb.band78.tm1.106PRB.usrpb210.conf | 2 -- .../CONF/gnb.band78.tm1.106PRB.usrpn300.conf | 2 -- .../CONF/gnb.band78.tm1.106PRB.usrpx300.conf | 2 -- .../CONF/gnb.band78.tm1.217PRB.usrpn300.conf | 2 -- .../CONF/gnb.band78.tm1.217PRB.usrpx300.conf | 1 - .../CONF/gnb.band78.tm1.24PRB.usrpb210.conf | 1 - .../CONF/gnb.band78.tm1.24PRB.usrpn300.conf | 1 - .../CONF/gnb.band78.tm1.24PRB.usrpx300.conf | 1 - .../CONF/gnb.band78.tm1.273PRB.usrpn300.conf | 1 - .../CONF/rcc.band78.tm1.106PRB.nfapi.conf | 1 - .../GENERIC-LTE-EPC/CONF/testing_gnb.conf | 2 -- .../CONF/testing_gnb_24PRB.conf | 2 -- .../CONF/testing_gnb_n310.conf | 2 -- .../CONF/testing_gnb_nsa_n310.conf | 1 - .../PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf | 1 - .../PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf | 1 - ...b.band78.tm1.106PRB.usrpn300.gtp-itti.conf | 1 - .../gnb.sa.band41.fr1.106PRB.usrpb210.conf | 2 -- .../gnb.sa.band66.fr1.106PRB.usrpn300.conf | 3 -- ...gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf | 1 - .../gnb.sa.band78.fr1.106PRB.usrpb210.conf | 1 - ...b.sa.band78.fr1.106PRB.usrpb210.sabox.conf | 1 - ...gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf | 1 - .../gnb.sa.band78.fr1.24PRB.usrpb210.conf | 3 -- 71 files changed, 52 insertions(+), 164 deletions(-) diff --git a/ci-scripts/conf_files/benetel-5g.conf b/ci-scripts/conf_files/benetel-5g.conf index 8f3b03fddc..3b872e56e9 100644 --- a/ci-scripts/conf_files/benetel-5g.conf +++ b/ci-scripts/conf_files/benetel-5g.conf @@ -21,8 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 31; //0; - servingCellConfigCommon = ( { #spCellConfigCommon diff --git a/ci-scripts/conf_files/episci/episci_gnb.band78.sa.fr1.106PRB.usrpn310.conf b/ci-scripts/conf_files/episci/episci_gnb.band78.sa.fr1.106PRB.usrpn310.conf index 51ffb1d5cd..a648db0efe 100644 --- a/ci-scripts/conf_files/episci/episci_gnb.band78.sa.fr1.106PRB.usrpn310.conf +++ b/ci-scripts/conf_files/episci/episci_gnb.band78.sa.fr1.106PRB.usrpn310.conf @@ -32,7 +32,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; min_rxtxtime = 6; pdcch_ConfigSIB1 = ( { diff --git a/ci-scripts/conf_files/episci/episci_rcc.band78.tm1.106PRB.nfapi.conf b/ci-scripts/conf_files/episci/episci_rcc.band78.tm1.106PRB.nfapi.conf index eac0b74633..0db6ac9036 100644 --- a/ci-scripts/conf_files/episci/episci_rcc.band78.tm1.106PRB.nfapi.conf +++ b/ci-scripts/conf_files/episci/episci_rcc.band78.tm1.106PRB.nfapi.conf @@ -21,7 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 31; //0; min_rxtxtime = 6; pdcch_ConfigSIB1 = ( diff --git a/ci-scripts/conf_files/episci/proxy_gnb.band78.sa.fr1.106PRB.usrpn310.conf b/ci-scripts/conf_files/episci/proxy_gnb.band78.sa.fr1.106PRB.usrpn310.conf index f80ce3751a..84cb18d435 100644 --- a/ci-scripts/conf_files/episci/proxy_gnb.band78.sa.fr1.106PRB.usrpn310.conf +++ b/ci-scripts/conf_files/episci/proxy_gnb.band78.sa.fr1.106PRB.usrpn310.conf @@ -32,7 +32,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; min_rxtxtime = 6; pdcch_ConfigSIB1 = ( diff --git a/ci-scripts/conf_files/episci/proxy_rcc.band78.tm1.106PRB.nfapi.conf b/ci-scripts/conf_files/episci/proxy_rcc.band78.tm1.106PRB.nfapi.conf index f61039ff17..270ad75845 100644 --- a/ci-scripts/conf_files/episci/proxy_rcc.band78.tm1.106PRB.nfapi.conf +++ b/ci-scripts/conf_files/episci/proxy_rcc.band78.tm1.106PRB.nfapi.conf @@ -21,7 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; min_rxtxtime = 6; servingCellConfigCommon = ( diff --git a/ci-scripts/conf_files/gNB_SA_CU.conf b/ci-scripts/conf_files/gNB_SA_CU.conf index 9d64ae1976..f6d3e8575a 100644 --- a/ci-scripts/conf_files/gNB_SA_CU.conf +++ b/ci-scripts/conf_files/gNB_SA_CU.conf @@ -44,7 +44,6 @@ gNBs = local_s_portd = 2152; remote_s_portc = 500; remote_s_portd = 2152; - ssb_SubcarrierOffset = 0; min_rxtxtime = 6; pdcch_ConfigSIB1 = ( diff --git a/ci-scripts/conf_files/gNB_SA_DU.conf b/ci-scripts/conf_files/gNB_SA_DU.conf index f95bdf91ae..4309c13dd3 100644 --- a/ci-scripts/conf_files/gNB_SA_DU.conf +++ b/ci-scripts/conf_files/gNB_SA_DU.conf @@ -36,7 +36,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; min_rxtxtime = 6; pdcch_ConfigSIB1 = ( diff --git a/ci-scripts/conf_files/gNB_SA_n78_106PRB.2x2_usrpn310.conf b/ci-scripts/conf_files/gNB_SA_n78_106PRB.2x2_usrpn310.conf index d6edc09286..06d9aed610 100644 --- a/ci-scripts/conf_files/gNB_SA_n78_106PRB.2x2_usrpn310.conf +++ b/ci-scripts/conf_files/gNB_SA_n78_106PRB.2x2_usrpn310.conf @@ -37,7 +37,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; pdsch_AntennaPorts_N1 = 2; pusch_AntennaPorts = 2; diff --git a/ci-scripts/conf_files/gNB_SA_n78_133PRB.2x2_usrpn310.conf b/ci-scripts/conf_files/gNB_SA_n78_133PRB.2x2_usrpn310.conf index 7f4b11c35d..8ff9d73e9a 100644 --- a/ci-scripts/conf_files/gNB_SA_n78_133PRB.2x2_usrpn310.conf +++ b/ci-scripts/conf_files/gNB_SA_n78_133PRB.2x2_usrpn310.conf @@ -38,7 +38,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; pdsch_AntennaPorts_N1 = 2; pusch_AntennaPorts = 2; diff --git a/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf b/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf index dcb3dd89b7..24ec8f17f8 100644 --- a/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf +++ b/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf @@ -21,7 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; min_rxtxtime = 6; servingCellConfigCommon = ( diff --git a/ci-scripts/conf_files/gnb.band66.tm1.106PRB.usrpn300.conf b/ci-scripts/conf_files/gnb.band66.tm1.106PRB.usrpn300.conf index 1019ec75ad..b3c7d7d1da 100644 --- a/ci-scripts/conf_files/gnb.band66.tm1.106PRB.usrpn300.conf +++ b/ci-scripts/conf_files/gnb.band66.tm1.106PRB.usrpn300.conf @@ -21,7 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; min_rxtxtime = 6; servingCellConfigCommon = ( diff --git a/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf index fa7c190538..0e68844050 100644 --- a/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.nsa_2x2.106PRB.usrpn310.conf @@ -19,7 +19,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 31; //0; pdsch_AntennaPorts_N1 = 2; pusch_AntennaPorts = 2; ul_prbblacklist = "51,52,53,54" diff --git a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.asue.conf b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.asue.conf index 5e6b3fb217..92c3a7a2e9 100644 --- a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.asue.conf +++ b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.asue.conf @@ -41,7 +41,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; pusch_AntennaPorts = 2; ul_prbblacklist = "51,52,53,54" do_SRS = 1; diff --git a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf index 8489008300..f2157e36d9 100644 --- a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf @@ -37,7 +37,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; pdsch_AntennaPorts_N1 = 2; pusch_AntennaPorts = 2; ul_prbblacklist = "51,52,53,54" diff --git a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf index 18ca7b5d1e..5bd8b26e05 100644 --- a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.ddsuu.2x2.usrpn310.conf @@ -37,7 +37,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; pusch_AntennaPorts = 2; ul_prbblacklist = "51,52,53,54" do_SRS = 1; diff --git a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.usrpn310.conf index 9e1f499f03..e1264bd069 100644 --- a/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.sa.fr1.106PRB.usrpn310.conf @@ -37,7 +37,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; #pusch_TargetSNRx10 = 200; #pucch_TargetSNRx10 = 200; ul_prbblacklist = "51,52,53,54" diff --git a/ci-scripts/conf_files/gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf index ce63578dd3..d22afe1c2f 100644 --- a/ci-scripts/conf_files/gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf @@ -37,7 +37,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; pdsch_AntennaPorts_N1 = 2; pusch_AntennaPorts = 2; #pusch_TargetSNRx10 = 200; diff --git a/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf b/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf index 0c75080398..c8349a43e3 100644 --- a/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf +++ b/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf @@ -21,7 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; min_rxtxtime = 6; servingCellConfigCommon = ( diff --git a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf index f3515d3882..cd3ab6278e 100644 --- a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf +++ b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf @@ -19,7 +19,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 31; //0; servingCellConfigCommon = ( { diff --git a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpn310.conf b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpn310.conf index 8f480d3757..371753eccc 100644 --- a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpn310.conf +++ b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpn310.conf @@ -20,7 +20,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 31; //0; min_rxtxtime = 6; servingCellConfigCommon = ( diff --git a/ci-scripts/conf_files/gnb.sa.band66.fr1.106PRB.usrpn300.conf b/ci-scripts/conf_files/gnb.sa.band66.fr1.106PRB.usrpn300.conf index b78ca916f3..197e1d211c 100644 --- a/ci-scripts/conf_files/gnb.sa.band66.fr1.106PRB.usrpn300.conf +++ b/ci-scripts/conf_files/gnb.sa.band66.fr1.106PRB.usrpn300.conf @@ -32,7 +32,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; min_rxtxtime = 6; pdcch_ConfigSIB1 = ( diff --git a/ci-scripts/conf_files/gnb.sa.band78.fr1.24PRB.usrpb210.conf b/ci-scripts/conf_files/gnb.sa.band78.fr1.24PRB.usrpb210.conf index bd3076a014..ad1471339a 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.fr1.24PRB.usrpb210.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.fr1.24PRB.usrpb210.conf @@ -32,9 +32,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts = 1; - pusch_AntennaPorts = 1; sib1_tda = 15; min_rxtxtime = 6; diff --git a/doc/testing_gnb_w_cots_ue_resources/gnb.conf b/doc/testing_gnb_w_cots_ue_resources/gnb.conf index c96d207445..206e1b4f02 100755 --- a/doc/testing_gnb_w_cots_ue_resources/gnb.conf +++ b/doc/testing_gnb_w_cots_ue_resources/gnb.conf @@ -21,8 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 31; //0; - pdsch_AntennaPorts = 1; servingCellConfigCommon = ( { diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index dca97bddf0..de8f4810ab 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -50,19 +50,6 @@ uint8_t SSB_Table[38]={0,2,4,6,8,10,12,14,254,254,16,18,20,22,24,26,28,30,254,25 extern uint8_t nfapi_mode; -void nr_set_ssb_first_subcarrier(nfapi_nr_config_request_scf_t *cfg, NR_DL_FRAME_PARMS *fp) { - - uint8_t sco = 0; - if (((fp->freq_range == nr_FR1) && (cfg->ssb_table.ssb_subcarrier_offset.value<24)) || - ((fp->freq_range == nr_FR2) && (cfg->ssb_table.ssb_subcarrier_offset.value<12)) ) { - if (fp->freq_range == nr_FR1) - sco = cfg->ssb_table.ssb_subcarrier_offset.value>>cfg->ssb_config.scs_common.value; - } - - fp->ssb_start_subcarrier = (12 * cfg->ssb_table.ssb_offset_point_a.value + sco); - LOG_D(PHY, "SSB first subcarrier %d (%d,%d)\n", fp->ssb_start_subcarrier,cfg->ssb_table.ssb_offset_point_a.value,sco); -} - void nr_common_signal_procedures (PHY_VARS_gNB *gNB,int frame,int slot,nfapi_nr_dl_tti_ssb_pdu ssb_pdu) { NR_DL_FRAME_PARMS *fp=&gNB->frame_parms; @@ -84,7 +71,9 @@ void nr_common_signal_procedures (PHY_VARS_gNB *gNB,int frame,int slot,nfapi_nr_ int ssb_start_symbol_abs = nr_get_ssb_start_symbol(fp,ssb_index); // computing the starting symbol for current ssb ssb_start_symbol = ssb_start_symbol_abs % fp->symbols_per_slot; // start symbol wrt slot - nr_set_ssb_first_subcarrier(cfg, fp); // setting the first subcarrier + // setting the first subcarrier + fp->ssb_start_subcarrier = (12 * cfg->ssb_table.ssb_offset_point_a.value + ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset); + LOG_D(PHY, "SSB first subcarrier %d (%d,%d)\n", fp->ssb_start_subcarrier,cfg->ssb_table.ssb_offset_point_a.value,ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset); LOG_D(PHY,"SS TX: frame %d, slot %d, start_symbol %d\n",frame,slot, ssb_start_symbol); nr_generate_pss(&txdataF[0][txdataF_offset], AMP, ssb_start_symbol, cfg, fp); diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index eff65fa606..7346382735 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -210,11 +210,9 @@ int nr_derive_key(int alg_type, uint8_t alg_id, } void config_common(int Mod_idP, - int ssb_SubcarrierOffset, rrc_pdsch_AntennaPorts_t pdsch_AntennaPorts, int pusch_AntennaPorts, - NR_ServingCellConfigCommon_t *scc - ); + NR_ServingCellConfigCommon_t *scc); int generate_dlsch_header(unsigned char *mac_header, unsigned char num_sdus, @@ -831,9 +829,9 @@ int main(int argc, char **argv) gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; // common configuration - rrc_mac_config_req_gNB(0,0, pdsch_AntennaPorts, n_tx, 0, 6, scc, NULL, NULL, 0, 0, NULL); + rrc_mac_config_req_gNB(0, pdsch_AntennaPorts, n_tx, 0, 6, scc, NULL, NULL, 0, 0, NULL); // UE dedicated configuration - rrc_mac_config_req_gNB(0,0, pdsch_AntennaPorts, n_tx, 0, 6, scc, NULL, NULL, 1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); + rrc_mac_config_req_gNB(0, pdsch_AntennaPorts, n_tx, 0, 6, scc, NULL, NULL, 1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); // reset preprocessor to the one of DLSIM after it has been set during // rrc_mac_config_req_gNB gNB_mac->pre_processor_dl = nr_dlsim_preprocessor; diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index 62f6b21528..7099eda90c 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -457,7 +457,7 @@ int main(int argc, char **argv) nr_phy_config_request_sim_pbchsim(gNB,N_RB_DL,N_RB_DL,mu,Nid_cell,SSB_positions); phy_init_nr_gNB(gNB,0,1); - nr_set_ssb_first_subcarrier(&gNB->gNB_config,frame_parms); + fp->ssb_start_subcarrier = 12 * gNB->gNB_config->ssb_table.ssb_offset_point_a.value uint8_t n_hf = 0; int cyclic_prefix_type = NFAPI_CP_NORMAL; diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index e70d08bdb3..e50671c280 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -756,9 +756,9 @@ int main(int argc, char **argv) gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; // common configuration - rrc_mac_config_req_gNB(0,0, conf.pdsch_AntennaPorts, n_rx, 0, 6, scc, &rrc.carrier.mib, rrc.carrier.siblock1, 0, 0, NULL); + rrc_mac_config_req_gNB(0, conf.pdsch_AntennaPorts, n_rx, 0, 6, scc, &rrc.carrier.mib, rrc.carrier.siblock1, 0, 0, NULL); // UE dedicated configuration - rrc_mac_config_req_gNB(0,0, conf.pdsch_AntennaPorts, n_rx, 0, 6, scc, &rrc.carrier.mib, rrc.carrier.siblock1, 1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); + rrc_mac_config_req_gNB(0, conf.pdsch_AntennaPorts, n_rx, 0, 6, scc, &rrc.carrier.mib, rrc.carrier.siblock1, 1, secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); frame_parms->nb_antennas_tx = n_tx; frame_parms->nb_antennas_rx = n_rx; nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h index 5b214cf95a..b0f0b72e0a 100644 --- a/openair2/COMMON/rrc_messages_types.h +++ b/openair2/COMMON/rrc_messages_types.h @@ -417,7 +417,6 @@ typedef struct NRRrcConfigurationReq_s { uint8_t num_plmn; NR_ServingCellConfigCommon_t *scc; NR_ServingCellConfig_t *scd; - int ssb_SubcarrierOffset; int sib1_tda; rrc_pdsch_AntennaPorts_t pdsch_AntennaPorts; int pusch_AntennaPorts; diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 62dc72a857..3ad460ae44 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1169,8 +1169,6 @@ void RCconfig_NRRRC(MessageDef *msg_p, uint32_t i, gNB_RRC_INST *rrc) { (NRRRC_CONFIGURATION_REQ (msg_p).mnc_digit_length[l] == 3),"BAD MNC DIGIT LENGTH %d", NRRRC_CONFIGURATION_REQ (msg_p).mnc_digit_length[l]); } - LOG_I(GNB_APP,"SSB SCO %d\n",*GNBParamList.paramarray[i][GNB_SSB_SUBCARRIEROFFSET_IDX].iptr); - NRRRC_CONFIGURATION_REQ (msg_p).ssb_SubcarrierOffset = *GNBParamList.paramarray[i][GNB_SSB_SUBCARRIEROFFSET_IDX].iptr; LOG_I(RRC,"pdsch_AntennaPorts N1 %d\n",*GNBParamList.paramarray[i][GNB_PDSCH_ANTENNAPORTS_N1_IDX].iptr); NRRRC_CONFIGURATION_REQ (msg_p).pdsch_AntennaPorts.N1 = *GNBParamList.paramarray[i][GNB_PDSCH_ANTENNAPORTS_N1_IDX].iptr; LOG_I(RRC,"pdsch_AntennaPorts N2 %d\n",*GNBParamList.paramarray[i][GNB_PDSCH_ANTENNAPORTS_N2_IDX].iptr); @@ -2055,7 +2053,6 @@ void configure_gnb_du_mac(int inst) { // LOG_I(GNB_APP,"Configuring MAC/L1 %d, carrier->sib2 %p\n", inst, &carrier->sib2->radioResourceConfigCommon); LOG_I(GNB_APP,"Configuring gNB DU MAC/L1 %d \n", inst); rrc_mac_config_req_gNB(rrc->module_id, - rrc->configuration.ssb_SubcarrierOffset, rrc->configuration.pdsch_AntennaPorts, rrc->configuration.pusch_AntennaPorts, rrc->configuration.sib1_tda, diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index 52dcbd3152..2ecc8f2e99 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -113,7 +113,6 @@ typedef enum { #define GNB_CONFIG_STRING_REMOTE_S_PORTC "remote_s_portc" #define GNB_CONFIG_STRING_LOCAL_S_PORTD "local_s_portd" #define GNB_CONFIG_STRING_REMOTE_S_PORTD "remote_s_portd" -#define GNB_CONFIG_STRING_SSBSUBCARRIEROFFSET "ssb_SubcarrierOffset" #define GNB_CONFIG_STRING_PDSCHANTENNAPORTS_N1 "pdsch_AntennaPorts_N1" #define GNB_CONFIG_STRING_PDSCHANTENNAPORTS_N2 "pdsch_AntennaPorts_N2" #define GNB_CONFIG_STRING_PDSCHANTENNAPORTS_XP "pdsch_AntennaPorts_XP" @@ -149,7 +148,6 @@ typedef enum { {GNB_CONFIG_STRING_REMOTE_S_PORTC, NULL, 0, uptr:NULL, defuintval:50000, TYPE_UINT, 0}, \ {GNB_CONFIG_STRING_LOCAL_S_PORTD, NULL, 0, uptr:NULL, defuintval:50001, TYPE_UINT, 0}, \ {GNB_CONFIG_STRING_REMOTE_S_PORTD, NULL, 0, uptr:NULL, defuintval:50001, TYPE_UINT, 0}, \ -{GNB_CONFIG_STRING_SSBSUBCARRIEROFFSET, NULL, 0, iptr:NULL, defintval:31, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_PDSCHANTENNAPORTS_N1, "horiz. log. antenna ports", 0, iptr:NULL, defintval:1, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_PDSCHANTENNAPORTS_N2, "vert. log. antenna ports", 0, iptr:NULL, defintval:1, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_PDSCHANTENNAPORTS_XP, "XP log. antenna ports", 0, iptr:NULL, defintval:1, TYPE_INT, 0}, \ @@ -179,20 +177,19 @@ typedef enum { #define GNB_REMOTE_S_PORTC_IDX 11 #define GNB_LOCAL_S_PORTD_IDX 12 #define GNB_REMOTE_S_PORTD_IDX 13 -#define GNB_SSB_SUBCARRIEROFFSET_IDX 14 -#define GNB_PDSCH_ANTENNAPORTS_N1_IDX 15 -#define GNB_PDSCH_ANTENNAPORTS_N2_IDX 16 -#define GNB_PDSCH_ANTENNAPORTS_XP_IDX 17 -#define GNB_PUSCH_ANTENNAPORTS_IDX 18 -#define GNB_SIB1_TDA_IDX 19 -#define GNB_DO_CSIRS_IDX 20 -#define GNB_DO_SRS_IDX 21 -#define GNB_NRCELLID_IDX 22 -#define GNB_MINRXTXTIME_IDX 23 -#define GNB_ULPRBBLACKLIST_IDX 24 -#define GNB_UMONDEFAULTDRB_IDX 25 -#define GNB_FORCE256QAMOFF_IDX 26 -#define GNB_ENABLE_SDAP_IDX 27 +#define GNB_PDSCH_ANTENNAPORTS_N1_IDX 14 +#define GNB_PDSCH_ANTENNAPORTS_N2_IDX 15 +#define GNB_PDSCH_ANTENNAPORTS_XP_IDX 16 +#define GNB_PUSCH_ANTENNAPORTS_IDX 17 +#define GNB_SIB1_TDA_IDX 18 +#define GNB_DO_CSIRS_IDX 19 +#define GNB_DO_SRS_IDX 20 +#define GNB_NRCELLID_IDX 21 +#define GNB_MINRXTXTIME_IDX 22 +#define GNB_ULPRBBLACKLIST_IDX 23 +#define GNB_UMONDEFAULTDRB_IDX 24 +#define GNB_FORCE256QAMOFF_IDX 25 +#define GNB_ENABLE_SDAP_IDX 26 #define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD} #define GNBPARAMS_CHECK { \ diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index bd693e4d88..34369d0861 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -343,7 +343,9 @@ void config_common_ue(NR_UE_MAC_INST_t *mac, uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); cfg->ssb_table.ssb_offset_point_a = absolute_diff/(12*scs_scaling) - 10; cfg->ssb_table.ssb_period = *scc->ssb_periodicityServingCell; - cfg->ssb_table.ssb_subcarrier_offset = mac->ssb_subcarrier_offset; + + // NSA -> take ssb offset from SSC + cfg->ssb_table.ssb_subcarrier_offset = absolute_diff%(12*scs_scaling); switch (scc->ssb_PositionsInBurst->present) { case 1 : diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 9dff368ccc..468d6faaee 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -160,7 +160,7 @@ void process_CellGroup(NR_CellGroupConfig_t *CellGroup, NR_UE_sched_ctrl_t *sche } -void config_common(int Mod_idP, int ssb_SubcarrierOffset, rrc_pdsch_AntennaPorts_t dl_antenna_ports_struct, int pusch_AntennaPorts, NR_ServingCellConfigCommon_t *scc) { +void config_common(int Mod_idP, rrc_pdsch_AntennaPorts_t dl_antenna_ports_struct, int pusch_AntennaPorts, NR_ServingCellConfigCommon_t *scc) { nfapi_nr_config_request_scf_t *cfg = &RC.nrmac[Mod_idP]->config[0]; RC.nrmac[Mod_idP]->common_channels[0].ServingCellConfigCommon = scc; @@ -342,26 +342,24 @@ void config_common(int Mod_idP, int ssb_SubcarrierOffset, rrc_pdsch_AntennaPorts if (scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA > 2016666) scs_scaling = scs_scaling>>2; uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); - uint16_t sco = absolute_diff%(12*scs_scaling); - // values of subcarrier offset larger than the limit only indicates CORESET for Type0-PDCCH CSS set is not present - int ssb_SubcarrierOffset_limit = 0; - int offset_scaling = 0; //15kHz - if(frequency_range == FR1) { - ssb_SubcarrierOffset_limit = 24; - if (ssb_SubcarrierOffsetssb_config.scs_common.value; - } else - ssb_SubcarrierOffset_limit = 12; - if (ssb_SubcarrierOffsetssb_SubcarrierOffset = absolute_diff%(12*scs_scaling); + int sco; + if(get_softmodem_params()->sa) { + sco = RC.nrmac[Mod_idP]->ssb_SubcarrierOffset; + if(frequency_range == FR1) + sco = sco<ssb_config.scs_common.value; + } + else + sco = 31; // no SIB1 + cfg->ssb_table.ssb_offset_point_a.value = absolute_diff/(12*scs_scaling) - 10; //absoluteFrequencySSB is the central frequency of SSB which is made by 20RBs in total cfg->ssb_table.ssb_offset_point_a.tl.tag = NFAPI_NR_CONFIG_SSB_OFFSET_POINT_A_TAG; cfg->num_tlv++; cfg->ssb_table.ssb_period.value = *scc->ssb_periodicityServingCell; cfg->ssb_table.ssb_period.tl.tag = NFAPI_NR_CONFIG_SSB_PERIOD_TAG; cfg->num_tlv++; - cfg->ssb_table.ssb_subcarrier_offset.value = ssb_SubcarrierOffset<ssb_table.ssb_subcarrier_offset.value = sco; cfg->ssb_table.ssb_subcarrier_offset.tl.tag = NFAPI_NR_CONFIG_SSB_SUBCARRIER_OFFSET_TAG; cfg->num_tlv++; @@ -473,7 +471,6 @@ int nr_mac_enable_ue_rrc_processing_timer(module_id_t Mod_idP, rnti_t rnti, NR_S } int rrc_mac_config_req_gNB(module_id_t Mod_idP, - int ssb_SubcarrierOffset, rrc_pdsch_AntennaPorts_t pdsch_AntennaPorts, int pusch_AntennaPorts, int sib1_tda, @@ -509,7 +506,6 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, LOG_I(NR_MAC,"Configuring common parameters from NR ServingCellConfig\n"); config_common(Mod_idP, - ssb_SubcarrierOffset, pdsch_AntennaPorts, pusch_AntennaPorts, scc); @@ -523,7 +519,6 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, printf("Waiting for PHY_config_req\n"); } } - RC.nrmac[Mod_idP]->ssb_SubcarrierOffset = ssb_SubcarrierOffset; RC.nrmac[Mod_idP]->minRXTXTIMEpdsch = minRXTXTIMEpdsch; NR_PHY_Config_t phycfg; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 9cb4dd88b2..5b5e6e1f7e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -41,7 +41,6 @@ void mac_top_init_gNB(void); void process_CellGroup(NR_CellGroupConfig_t *CellGroup, NR_UE_sched_ctrl_t *sched_ctrl); void config_common(int Mod_idP, - int ssb_SubcarrierOffset, rrc_pdsch_AntennaPorts_t pdsch_AntennaPorts, int pusch_AntennaPorts, NR_ServingCellConfigCommon_t *scc); @@ -52,7 +51,6 @@ int nr_mac_enable_ue_rrc_processing_timer(module_id_t Mod_idP, uint32_t rrc_reconfiguration_delay); int rrc_mac_config_req_gNB(module_id_t Mod_idP, - int ssb_SubcarrierOffset, rrc_pdsch_AntennaPorts_t pdsch_AntennaPorts, int pusch_AntennaPorts, int sib1_tda, @@ -433,16 +431,6 @@ int get_ulscs(nfapi_nr_config_request_t *cfg); int get_symbolsperslot(nfapi_nr_config_request_t *cfg); -void config_nr_mib(int Mod_idP, - int CC_idP, - int p_gNBP, - int subCarrierSpacingCommon, - uint32_t ssb_SubcarrierOffset, - int dmrs_TypeA_Position, - uint32_t pdcch_ConfigSIB1, - int cellBarred, - int intraFreqReselection); - int nr_write_ce_dlsch_pdu(module_id_t module_idP, const NR_UE_sched_ctrl_t *ue_sched_ctl, unsigned char *mac_pdu, diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 8e8959c597..5ef4e1c001 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -41,6 +41,7 @@ #include #include +#include "executables/softmodem-common.h" #include "LAYER2/nr_rlc/nr_rlc_oai_api.h" #include "asn1_msg.h" #include "../nr_rrc_proto.h" @@ -197,8 +198,7 @@ int xer_nr_sprint (char *string, size_t string_size, asn_TYPE_descriptor_t *td, uint8_t do_MIB_NR(gNB_RRC_INST *rrc,uint32_t frame) { asn_enc_rval_t enc_rval; - rrc_gNB_carrier_data_t *carrier = &rrc->carrier; - const gNB_RrcConfigurationReq *configuration = &rrc->configuration; + rrc_gNB_carrier_data_t *carrier = &rrc->carrier; NR_BCCH_BCH_Message_t *mib = &carrier->mib; NR_ServingCellConfigCommon_t *scc = carrier->servingcellconfigcommon; @@ -225,11 +225,18 @@ uint8_t do_MIB_NR(gNB_RRC_INST *rrc,uint32_t frame) { AssertFatal(scc->ssbSubcarrierSpacing != NULL, "scc->ssbSubcarrierSpacing is null\n"); int band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; frequency_range_t frequency_range = band<100?FR1:FR2; - int ssb_subcarrier_offset; - if(frequency_range == FR1) - ssb_subcarrier_offset = (configuration->ssb_SubcarrierOffset<24) ? (configuration->ssb_SubcarrierOffset<<*scc->ssbSubcarrierSpacing) : configuration->ssb_SubcarrierOffset; - else - ssb_subcarrier_offset = configuration->ssb_SubcarrierOffset; + int scs_scaling = 1<<*scc->ssbSubcarrierSpacing; + if (scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA < 600000) + scs_scaling = scs_scaling*3; + if (scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA > 2016666) + scs_scaling = scs_scaling>>2; + uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); + int ssb_subcarrier_offset = 31; // default value for NSA + if (get_softmodem_params()->sa) { + ssb_subcarrier_offset = absolute_diff%(12*scs_scaling); + if(frequency_range == FR1) + ssb_subcarrier_offset = ssb_subcarrier_offset<<*scc->ssbSubcarrierSpacing; + } mib->message.choice.mib->ssb_SubcarrierOffset = ssb_subcarrier_offset&15; /* diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index a0706509a7..8e1ed3d6a5 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -166,7 +166,6 @@ static void init_NR_SI(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration if (NODE_IS_MONOLITHIC(rrc->node_type)){ rrc_mac_config_req_gNB(rrc->module_id, - rrc->configuration.ssb_SubcarrierOffset, rrc->configuration.pdsch_AntennaPorts, rrc->configuration.pusch_AntennaPorts, rrc->configuration.sib1_tda, @@ -275,7 +274,6 @@ void apply_macrlc_config(gNB_RRC_INST *rrc, NR_CellGroupConfig_t *cgc = get_softmodem_params()->sa ? ue_context_pP->ue_context.masterCellGroup : NULL; rrc_mac_config_req_gNB(rrc->module_id, - rrc->configuration.ssb_SubcarrierOffset, rrc->configuration.pdsch_AntennaPorts, rrc->configuration.pusch_AntennaPorts, rrc->configuration.sib1_tda, @@ -463,7 +461,6 @@ rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest( PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP)); rrc_mac_config_req_gNB(rrc_instance_p->module_id, - rrc_instance_p->configuration.ssb_SubcarrierOffset, rrc_instance_p->configuration.pdsch_AntennaPorts, rrc_instance_p->configuration.pusch_AntennaPorts, rrc_instance_p->configuration.sib1_tda, @@ -1398,7 +1395,6 @@ rrc_gNB_process_RRCReconfigurationComplete( if (!NODE_IS_CU(RC.nrrrc[ctxt_pP->module_id]->node_type)) { rrc_mac_config_req_gNB(rrc->module_id, - rrc->configuration.ssb_SubcarrierOffset, rrc->configuration.pdsch_AntennaPorts, rrc->configuration.pusch_AntennaPorts, rrc->configuration.sib1_tda, diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index b482637dfd..cd094a6d05 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -344,7 +344,6 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ // configure MAC and RLC if (NODE_IS_DU(rrc->node_type)) { rrc_mac_config_req_gNB(rrc->module_id, - rrc->configuration.ssb_SubcarrierOffset, rrc->configuration.pdsch_AntennaPorts, rrc->configuration.pusch_AntennaPorts, rrc->configuration.sib1_tda, @@ -357,7 +356,6 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_ ue_context_p->ue_context.secondaryCellGroup); } else { rrc_mac_config_req_gNB(rrc->module_id, - rrc->configuration.ssb_SubcarrierOffset, rrc->configuration.pdsch_AntennaPorts, rrc->configuration.pusch_AntennaPorts, rrc->configuration.sib1_tda, diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/benetel-5g.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/benetel-5g.conf index d14267dcd8..c8e109d302 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/benetel-5g.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/benetel-5g.conf @@ -22,7 +22,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 31; //0; servingCellConfigCommon = ( { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpn300.conf index 52e4eec30e..a4c877a7ba 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpn300.conf @@ -21,7 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; servingCellConfigCommon = ( { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf index ab435c9686..e5478983cf 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf @@ -21,7 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; servingCellConfigCommon = ( { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf index a04e0e6123..efa0d3e2fa 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf @@ -21,8 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; - servingCellConfigCommon = ( { #spCellConfigCommon diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf index 426f9e782b..8a2ce9f63e 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf @@ -21,7 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; servingCellConfigCommon = ( { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpn300.conf index 216728577a..616f86a1cd 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpn300.conf @@ -21,7 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; servingCellConfigCommon = ( { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpx300.conf index 59d466656c..0818fe11d7 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpx300.conf @@ -21,8 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; - servingCellConfigCommon = ( { #spCellConfigCommon diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.30kHz,usrpb2x0.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.30kHz,usrpb2x0.conf index 2ae4df07d9..5c636af06c 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.30kHz,usrpb2x0.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.30kHz,usrpb2x0.conf @@ -21,7 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 31; servingCellConfigCommon = ( { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.slave.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.slave.conf index 21267870bd..812ac8dafb 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.slave.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.slave.conf @@ -21,7 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; servingCellConfigCommon = ( { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.slave.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.slave.conf index a0fd0bda9f..781384a789 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.slave.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.slave.conf @@ -20,8 +20,6 @@ gNBs = tr_s_preference = "local_mac" ////////// Physical parameters: - - ssb_SubcarrierOffset = 0; servingCellConfigCommon = ( { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.PTRS.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.PTRS.usrpx300.conf index 5c8f90d9b5..1450c45eee 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.PTRS.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.PTRS.usrpx300.conf @@ -21,8 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; - servingCellConfigCommon = ( { #spCellConfigCommon diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpb210.conf index 7bf3626870..562e2b16ab 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpb210.conf @@ -21,8 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; - servingCellConfigCommon = ( { #spCellConfigCommon diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf index 1773e1fb79..b7dc93497f 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf @@ -21,8 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; - servingCellConfigCommon = ( { #spCellConfigCommon diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpx300.conf index d0f394be16..10122b9eb2 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpx300.conf @@ -21,8 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; - servingCellConfigCommon = ( { #spCellConfigCommon diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf index 0438e61337..20d01c2a00 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf @@ -20,8 +20,6 @@ gNBs = tr_s_preference = "local_mac" ////////// Physical parameters: - - ssb_SubcarrierOffset = 0; servingCellConfigCommon = ( { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpx300.conf index 66c2151eb8..44f3889eec 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpx300.conf @@ -21,7 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; servingCellConfigCommon = ( { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpb210.conf index c6ea066fc4..fbafef81b4 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpb210.conf @@ -21,7 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; servingCellConfigCommon = ( { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpn300.conf index fcfe58a3c0..38d6ed3c61 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpn300.conf @@ -21,7 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; servingCellConfigCommon = ( { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpx300.conf index 2ad9757cb1..b7da7b17f4 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpx300.conf @@ -21,7 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; servingCellConfigCommon = ( { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.273PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.273PRB.usrpn300.conf index 44074f3fd9..9f78716bcc 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.273PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.273PRB.usrpn300.conf @@ -21,7 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; servingCellConfigCommon = ( { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band78.tm1.106PRB.nfapi.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band78.tm1.106PRB.nfapi.conf index 7ce150506f..1dcef89736 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band78.tm1.106PRB.nfapi.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band78.tm1.106PRB.nfapi.conf @@ -21,7 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; servingCellConfigCommon = ( { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf index 306e652eaa..9a3fe358a5 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf @@ -21,8 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 31; //0; - servingCellConfigCommon = ( { #spCellConfigCommon diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_24PRB.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_24PRB.conf index d08c0f14a0..9e1ae24d67 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_24PRB.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_24PRB.conf @@ -21,8 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 31; //0; - servingCellConfigCommon = ( { #spCellConfigCommon diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_n310.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_n310.conf index e3204db8fa..9ec28b93e7 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_n310.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_n310.conf @@ -20,8 +20,6 @@ gNBs = tr_s_preference = "local_mac" ////////// Physical parameters: - - ssb_SubcarrierOffset = 31; //0; servingCellConfigCommon = ( { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_nsa_n310.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_nsa_n310.conf index 030dc10226..35778ef705 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_nsa_n310.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_nsa_n310.conf @@ -21,7 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 31; //0; pusch_TargetSNRx10 = 200; pucch_TargetSNRx10 = 200; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf index 6aacd98c7f..a64a4c6022 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf @@ -44,7 +44,6 @@ gNBs = local_s_portd = 2152; remote_s_portc = 500; remote_s_portd = 2152; - ssb_SubcarrierOffset = 0; min_rxtxtime = 6; pdcch_ConfigSIB1 = ( diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf index f95bdf91ae..4309c13dd3 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf @@ -36,7 +36,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; min_rxtxtime = 6; pdcch_ConfigSIB1 = ( diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf index f91683897f..cb90889b52 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf @@ -36,7 +36,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; servingCellConfigCommon = ( { diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf index e645094e8b..b61708a6d8 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf @@ -28,8 +28,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; - min_rxtxtime = 2; do_SRS = 1; pdcch_ConfigSIB1 = ( diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf index ff64fe718a..6abf2c19cc 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf @@ -32,9 +32,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts = 1; - pusch_AntennaPorts = 1; min_rxtxtime = 6; pdcch_ConfigSIB1 = ( diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf index 2881a77d48..5249785c8e 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf @@ -28,7 +28,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; pdsch_AntennaPorts_N1 = 2; pusch_AntennaPorts = 2; do_SRS = 1; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf index e3024737ee..baf5c6d0ff 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf @@ -28,7 +28,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; min_rxtxtime = 2; pdcch_ConfigSIB1 = ( diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.sabox.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.sabox.conf index 8ca0c08876..6719a5534d 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.sabox.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.sabox.conf @@ -30,7 +30,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; pdcch_ConfigSIB1 = ( { diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf index b8d71015c1..1bd5117bdb 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf @@ -28,7 +28,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; pdsch_AntennaPorts_N1 = 1; pusch_AntennaPorts = 2; ul_prbblacklist = "79,80,81,82" diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.24PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.24PRB.usrpb210.conf index bd3076a014..ad1471339a 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.24PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.24PRB.usrpb210.conf @@ -32,9 +32,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts = 1; - pusch_AntennaPorts = 1; sib1_tda = 15; min_rxtxtime = 6; From d914817806a331335cf40dde50cfedf54cd57db2 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Mon, 9 May 2022 17:58:42 +0100 Subject: [PATCH 095/267] Fill srs_reported_symbol_list in SRS indication --- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 49 ++++++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index b342b87fa8..597b165f9e 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -45,6 +45,7 @@ #include "intertask_interface.h" //#define DEBUG_RXDATA +//#define SRS_IND_DEBUG uint8_t SSB_Table[38]={0,2,4,6,8,10,12,14,254,254,16,18,20,22,24,26,28,30,254,254,32,34,36,38,40,42,44,46,254,254,48,50,52,54,56,58,60,62}; @@ -624,6 +625,30 @@ void phy_procedures_gNB_common_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) } +int fill_srs_reported_symbol_list(nfapi_nr_srs_indication_reported_symbol_t* reported_symbol_list, + nfapi_nr_srs_pdu_t *srs_pdu, + int N_RB_UL, + const int8_t *snr_per_rb) { + + reported_symbol_list->num_rbs = srs_bandwidth_config[srs_pdu->config_index][srs_pdu->bandwidth_index][0]; + + if (!reported_symbol_list->rb_list) { + reported_symbol_list->rb_list = (nfapi_nr_srs_indication_reported_symbol_resource_block_t*) calloc(1, N_RB_UL*sizeof(nfapi_nr_srs_indication_reported_symbol_resource_block_t)); + } + + for(int rb = 0; rb < reported_symbol_list->num_rbs; rb++) { + if (snr_per_rb[rb] < -64) { + reported_symbol_list->rb_list[rb].rb_snr = 0; + } else if (snr_per_rb[rb] > 63) { + reported_symbol_list->rb_list[rb].rb_snr = 255; + } else { + reported_symbol_list->rb_list[rb].rb_snr = (snr_per_rb[rb] + 64)<<1; + } + } + + return 0; +} + int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { /* those variables to log T_GNB_PHY_PUCCH_PUSCH_IQ only when we try to decode */ int pucch_decode_done = 0; @@ -854,10 +879,30 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { //gNB->srs_pdu_list[num_srs].timing_advance; gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; //gNB->srs_pdu_list[num_srs].wide_band_snr; - //gNB->srs_pdu_list[num_srs].num_reported_symbols; - //gNB->srs_pdu_list[num_srs].reported_symbol_list; + gNB->srs_pdu_list[num_srs].num_reported_symbols = 1<num_symbols; + if(!gNB->srs_pdu_list[num_srs].reported_symbol_list) { + gNB->srs_pdu_list[num_srs].reported_symbol_list = (nfapi_nr_srs_indication_reported_symbol_t*) calloc(1, gNB->srs_pdu_list[num_srs].num_reported_symbols*sizeof(nfapi_nr_srs_indication_reported_symbol_t)); + } + fill_srs_reported_symbol_list(&gNB->srs_pdu_list[num_srs].reported_symbol_list[0], + srs_pdu, + gNB->frame_parms.N_RB_UL, + gNB->nr_srs_info[i]->snr_per_rb); + gNB->UL_INFO.srs_ind.number_of_pdus += 1; +#ifdef SRS_IND_DEBUG + LOG_I(NR_PHY, "gNB->UL_INFO.srs_ind.sfn = %i\n", gNB->UL_INFO.srs_ind.sfn); + LOG_I(NR_PHY, "gNB->UL_INFO.srs_ind.slot = %i\n", gNB->UL_INFO.srs_ind.slot); + LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].rnti = 0x%04x\n", num_srs, gNB->srs_pdu_list[num_srs].rnti); + LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].num_symbols = %i\n", num_srs, gNB->srs_pdu_list[num_srs].num_symbols); + LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].num_reported_symbols = %i\n", num_srs, gNB->srs_pdu_list[num_srs].num_reported_symbols); + LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].reported_symbol_list[0].num_rbs = %i\n", num_srs, gNB->srs_pdu_list[num_srs].reported_symbol_list[0].num_rbs); + for(int rb = 0; rb < gNB->srs_pdu_list[num_srs].reported_symbol_list[0].num_rbs; rb++) { + LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].reported_symbol_list[0].rb_list[%3i].rb_snr = %i\n", + num_srs, rb, gNB->srs_pdu_list[num_srs].reported_symbol_list[0].rb_list[rb].rb_snr); + } +#endif + srs->active = 0; } } From bdff42cf77e5a304f5337472b7a75c8758dceb75 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Mon, 9 May 2022 18:21:04 +0100 Subject: [PATCH 096/267] Compute and fill wide_band_snr field for SRS indication --- openair1/PHY/INIT/nr_init.c | 1 + openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c | 7 +++++-- openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 3 ++- openair1/PHY/defs_nr_common.h | 1 + openair1/SCHED_NR/phy_procedures_nr_gNB.c | 8 +++++--- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 21ebcc1405..1722dfb861 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -622,6 +622,7 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, gNB->nr_srs_info[id]->noise_power_per_rb = (uint32_t*)malloc16_clear(fp->N_RB_UL*sizeof(uint32_t)); gNB->nr_srs_info[id]->noise_power = (uint32_t*)malloc16_clear(sizeof(uint32_t)); gNB->nr_srs_info[id]->snr_per_rb = (int8_t*)malloc16_clear(fp->N_RB_UL*sizeof(int8_t)); + gNB->nr_srs_info[id]->snr = (int8_t*)malloc16_clear(sizeof(int8_t)); gNB->nr_srs_info[id]->srs_received_signal = (int32_t **)malloc16(Prx*sizeof(int32_t*)); gNB->nr_srs_info[id]->srs_ls_estimated_channel = (int32_t **)malloc16(Prx*sizeof(int32_t*)); gNB->nr_srs_info[id]->srs_estimated_channel_freq = (int32_t **)malloc16(Prx*sizeof(int32_t*)); diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 8db33e3e18..4ff9952077 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -1102,7 +1102,8 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, uint32_t *signal_power, uint32_t *noise_power_per_rb, uint32_t *noise_power, - int8_t *snr_per_rb) { + int8_t *snr_per_rb, + int8_t *snr) { if(nr_srs_info->sc_list_length == 0) { LOG_E(NR_PHY, "(%d.%d) nr_srs_info was not generated yet!\n", frame, slot); @@ -1283,6 +1284,8 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, *noise_power = calc_power(noise_real,frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length) + calc_power(noise_imag,frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length); + *snr = dB_fixed((int32_t)((*signal_power<first_carrier_offset + srs_pdu->bwp_start*12; uint8_t R = srs_pdu->comb_size == 0 ? 2 : 4; @@ -1312,7 +1315,7 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, } } - LOG_I(NR_PHY,"noise_power = %u\n", *noise_power); + LOG_I(NR_PHY,"noise_power = %u, SNR = %i dB\n", *noise_power, *snr); #endif return 0; diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index f7ac055dcc..38b6556948 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -76,5 +76,6 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, uint32_t *signal_power, uint32_t *noise_power_per_rb, uint32_t *noise_power, - int8_t *snr_per_rb); + int8_t *snr_per_rb, + int8_t *snr); #endif diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 4109b13831..a30baabd10 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -248,6 +248,7 @@ typedef struct { uint32_t *noise_power_per_rb; uint32_t *noise_power; int8_t *snr_per_rb; + int8_t *snr; } nr_srs_info_t; typedef struct NR_DL_FRAME_PARMS NR_DL_FRAME_PARMS; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 597b165f9e..b8aa108f10 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -862,7 +862,8 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->nr_srs_info[i]->signal_power, gNB->nr_srs_info[i]->noise_power_per_rb, gNB->nr_srs_info[i]->noise_power, - gNB->nr_srs_info[i]->snr_per_rb); + gNB->nr_srs_info[i]->snr_per_rb, + gNB->nr_srs_info[i]->snr); T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), T_BUFFER(gNB->nr_srs_info[i]->srs_estimated_channel_freq[0], gNB->frame_parms.ofdm_symbol_size*sizeof(int32_t))); @@ -874,11 +875,11 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->UL_INFO.srs_ind.pdu_list = &gNB->srs_pdu_list[0]; gNB->UL_INFO.srs_ind.sfn = frame_rx; gNB->UL_INFO.srs_ind.slot = slot_rx; - //gNB->srs_pdu_list[num_srs].handle; + gNB->srs_pdu_list[num_srs].handle = srs_pdu->handle; gNB->srs_pdu_list[num_srs].rnti = srs_pdu->rnti; //gNB->srs_pdu_list[num_srs].timing_advance; gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; - //gNB->srs_pdu_list[num_srs].wide_band_snr; + gNB->srs_pdu_list[num_srs].wide_band_snr = (*gNB->nr_srs_info[i]->snr + 64)<<1; gNB->srs_pdu_list[num_srs].num_reported_symbols = 1<num_symbols; if(!gNB->srs_pdu_list[num_srs].reported_symbol_list) { gNB->srs_pdu_list[num_srs].reported_symbol_list = (nfapi_nr_srs_indication_reported_symbol_t*) calloc(1, gNB->srs_pdu_list[num_srs].num_reported_symbols*sizeof(nfapi_nr_srs_indication_reported_symbol_t)); @@ -895,6 +896,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { LOG_I(NR_PHY, "gNB->UL_INFO.srs_ind.slot = %i\n", gNB->UL_INFO.srs_ind.slot); LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].rnti = 0x%04x\n", num_srs, gNB->srs_pdu_list[num_srs].rnti); LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].num_symbols = %i\n", num_srs, gNB->srs_pdu_list[num_srs].num_symbols); + LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].wide_band_snr = %i\n", num_srs, gNB->srs_pdu_list[num_srs].wide_band_snr); LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].num_reported_symbols = %i\n", num_srs, gNB->srs_pdu_list[num_srs].num_reported_symbols); LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].reported_symbol_list[0].num_rbs = %i\n", num_srs, gNB->srs_pdu_list[num_srs].reported_symbol_list[0].num_rbs); for(int rb = 0; rb < gNB->srs_pdu_list[num_srs].reported_symbol_list[0].num_rbs; rb++) { From 99b262d7647121cdaa786e9402d07eda88904ea2 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Mon, 9 May 2022 19:25:33 +0100 Subject: [PATCH 097/267] Compute and fill timing_advance field for SRS indication --- .../PHY/NR_ESTIMATION/nr_measurements_gNB.c | 43 +++++++++++++++++++ openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 3 ++ openair1/SCHED_NR/phy_procedures_nr_gNB.c | 3 +- 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index fb56322e54..a2ee62fbde 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -67,6 +67,49 @@ int nr_est_timing_advance_pusch(PHY_VARS_gNB* gNB, int UE_id) return max_pos - sync_pos; } +int nr_est_timing_advance_srs(NR_DL_FRAME_PARMS *frame_parms, + int32_t **srs_estimated_channel_time) { + int timing_advance = 0; + int max_val = 0; + + for (int i = 0; i < frame_parms->ofdm_symbol_size; i++) { + int temp = 0; + for (int aa = 0; aa < frame_parms->nb_antennas_rx; aa++) { + int Re = ((int16_t*)srs_estimated_channel_time[aa])[(i<<1)]; + int Im = ((int16_t*)srs_estimated_channel_time[aa])[1+(i<<1)]; + temp += (Re*Re/2) + (Im*Im/2); + } + if (temp > max_val) { + timing_advance = i; + max_val = temp; + } + } + + if (timing_advance > frame_parms->ofdm_symbol_size/2) { + timing_advance = timing_advance - frame_parms->ofdm_symbol_size; + } + + // Scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size + uint16_t bw_scaling = frame_parms->ofdm_symbol_size >> 11; + + // do some integer rounding to improve TA accuracy + int sync_pos_rounded; + if (timing_advance > 0) { + sync_pos_rounded = timing_advance + (bw_scaling >> 1) - 1; + } else { + sync_pos_rounded = timing_advance - (bw_scaling >> 1) + 1; + } + + int timing_advance_update = sync_pos_rounded / bw_scaling; + + // put timing advance command in 0..63 range + timing_advance_update += 31; + + if (timing_advance_update < 0) timing_advance_update = 0; + if (timing_advance_update > 63) timing_advance_update = 63; + + return timing_advance_update; +} void dump_nr_I0_stats(FILE *fd,PHY_VARS_gNB *gNB) { diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index 38b6556948..914b0d7385 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -55,6 +55,9 @@ void nr_gnb_measurements(PHY_VARS_gNB *gNB, uint8_t ulsch_id, unsigned char harq int nr_est_timing_advance_pusch(PHY_VARS_gNB* phy_vars_gNB, int UE_id); +int nr_est_timing_advance_srs(NR_DL_FRAME_PARMS *frame_parms, + int32_t **srs_estimated_channel_time); + void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, NR_DL_FRAME_PARMS *frame_parms, nfapi_nr_pusch_pdu_t *rel15_ul, diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index b8aa108f10..4e75090d4b 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -877,7 +877,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->UL_INFO.srs_ind.slot = slot_rx; gNB->srs_pdu_list[num_srs].handle = srs_pdu->handle; gNB->srs_pdu_list[num_srs].rnti = srs_pdu->rnti; - //gNB->srs_pdu_list[num_srs].timing_advance; + gNB->srs_pdu_list[num_srs].timing_advance = nr_est_timing_advance_srs(&gNB->frame_parms, gNB->nr_srs_info[i]->srs_estimated_channel_time); gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; gNB->srs_pdu_list[num_srs].wide_band_snr = (*gNB->nr_srs_info[i]->snr + 64)<<1; gNB->srs_pdu_list[num_srs].num_reported_symbols = 1<num_symbols; @@ -895,6 +895,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { LOG_I(NR_PHY, "gNB->UL_INFO.srs_ind.sfn = %i\n", gNB->UL_INFO.srs_ind.sfn); LOG_I(NR_PHY, "gNB->UL_INFO.srs_ind.slot = %i\n", gNB->UL_INFO.srs_ind.slot); LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].rnti = 0x%04x\n", num_srs, gNB->srs_pdu_list[num_srs].rnti); + LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].timing_advance = %i\n", num_srs, gNB->srs_pdu_list[num_srs].timing_advance); LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].num_symbols = %i\n", num_srs, gNB->srs_pdu_list[num_srs].num_symbols); LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].wide_band_snr = %i\n", num_srs, gNB->srs_pdu_list[num_srs].wide_band_snr); LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].num_reported_symbols = %i\n", num_srs, gNB->srs_pdu_list[num_srs].num_reported_symbols); From 3b165473741a73420920446a33b41cf38c03e592 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 10 May 2022 09:13:52 +0200 Subject: [PATCH 098/267] fix in pbchsim --- openair1/SIMULATION/NR_PHY/pbchsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index 7099eda90c..4e7d2a67e1 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -457,7 +457,7 @@ int main(int argc, char **argv) nr_phy_config_request_sim_pbchsim(gNB,N_RB_DL,N_RB_DL,mu,Nid_cell,SSB_positions); phy_init_nr_gNB(gNB,0,1); - fp->ssb_start_subcarrier = 12 * gNB->gNB_config->ssb_table.ssb_offset_point_a.value + frame_parms->ssb_start_subcarrier = 12 * gNB->gNB_config.ssb_table.ssb_offset_point_a.value; uint8_t n_hf = 0; int cyclic_prefix_type = NFAPI_CP_NORMAL; From 61a2f398db15e386981bd4e523f1f423049a8bcb Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 10 May 2022 10:43:24 +0100 Subject: [PATCH 099/267] Add LOGs of SRS indication in handle_nr_srs_measurements --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 03cb48e5da..e763548ea3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -37,6 +37,8 @@ #include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" +//#define SRS_IND_DEBUG + int get_dci_format(NR_UE_sched_ctrl_t *sched_ctrl) { int dci_format = sched_ctrl->search_space && sched_ctrl->search_space->searchSpaceType && @@ -887,7 +889,23 @@ void handle_nr_srs_measurements(const module_id_t module_id, const uint8_t wide_band_snr, const uint8_t num_reported_symbols, nfapi_nr_srs_indication_reported_symbol_t* reported_symbol_list) { + LOG_I(NR_MAC, "(%d.%d) Received SRS indication for rnti: 0x%04x\n", frame, slot, rnti); + +#ifdef SRS_IND_DEBUG + LOG_I(NR_MAC, "frame = %i\n", frame); + LOG_I(NR_MAC, "slot = %i\n", slot); + LOG_I(NR_MAC, "rnti = 0x%04x\n", rnti); + LOG_I(NR_MAC, "timing_advance = %i\n", timing_advance); + LOG_I(NR_MAC, "num_symbols = %i\n", num_symbols); + LOG_I(NR_MAC, "wide_band_snr = %i (%i dB)\n", wide_band_snr, (wide_band_snr>>1)-64); + LOG_I(NR_MAC, "num_reported_symbols = %i\n", num_reported_symbols); + LOG_I(NR_MAC, "reported_symbol_list[0].num_rbs = %i\n", reported_symbol_list[0].num_rbs); + for(int rb = 0; rb < reported_symbol_list[0].num_rbs; rb++) { + LOG_I(NR_MAC, "reported_symbol_list[0].rb_list[%3i].rb_snr = %i (%i dB)\n", + rb, reported_symbol_list[0].rb_list[rb].rb_snr, (reported_symbol_list[0].rb_list[rb].rb_snr>>1)-64); + } +#endif } long get_K2(NR_ServingCellConfigCommon_t *scc, From c7e8002d8d4a211c2d82ee3b62309457e46b95dd Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 10 May 2022 11:43:44 +0200 Subject: [PATCH 100/267] adding CI test with subcarrier offset in pbchsim --- cmake_targets/autotests/test_case_list.xml | 8 +++++--- openair1/SIMULATION/NR_PHY/pbchsim.c | 15 +++++++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index b55228bdc9..41e1bcd6b0 100755 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -1062,7 +1062,8 @@ (Test3: PBCH-only, 217 PRB), (Test4: PBCH and synchronization, 217 RPB), (Test5: PBCH-only, 273 PRB), - (Test6: PBCH and synchronization, 273 PRB) + (Test6: PBCH and synchronization, 273 PRB), + (Test7: PBCH and synchronization, 106PBR, SSB SC OFFSET 6) $OPENAIR_DIR/cmake_targets/build_oai --phy_simulators -c @@ -1074,8 +1075,9 @@ -s-11 -S-8 -n10 -R217 -s-11 -S-8 -n10 -o8000 -I -R217 -s-11 -S-8 -n10 -R273 - -s-11 -S-8 -n10 -o8000 -I -R273 - nr_pbchsim.test1 nr_pbchsim.test2 nr_pbchsim.test3 nr_pbchsim.test4 nr_pbchsim.test5 nr_pbchsim.test6 + -s-11 -S-8 -n10 -o8000 -I -R273 + -s-11 -S-8 -n10 -R106 -O6 + nr_pbchsim.test1 nr_pbchsim.test2 nr_pbchsim.test3 nr_pbchsim.test4 nr_pbchsim.test5 nr_pbchsim.test6 nr_pbchsim.test7 PBCH test OK segmentation fault|assertion|exiting|fatal 3 diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index 4e7d2a67e1..b4d81824e2 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -171,6 +171,7 @@ int main(int argc, char **argv) uint8_t transmission_mode = 1,n_tx=1,n_rx=1; uint16_t Nid_cell=0; uint64_t SSB_positions=0x01; + int ssb_subcarrier_offset = 0; channel_desc_t *gNB2UE; @@ -214,7 +215,7 @@ int main(int argc, char **argv) exit_fun("[NR_PBCHSIM] Error, configuration module init failed\n"); } - while ((c = getopt (argc, argv, "F:g:hIL:m:M:n:N:o:P:r:R:s:S:x:y:z:")) != -1) { + while ((c = getopt (argc, argv, "F:g:hIL:m:M:n:N:o:O:P:r:R:s:S:x:y:z:")) != -1) { switch (c) { /*case 'f': write_output_file=1; @@ -312,6 +313,10 @@ int main(int argc, char **argv) Nid_cell = atoi(optarg); break; + case 'O': + ssb_subcarrier_offset = atoi(optarg); + break; + case 'o': cfo = atof(optarg); #ifdef DEBUG_NR_PBCHSIM @@ -414,6 +419,7 @@ int main(int argc, char **argv) printf("-n Number of frames to simulate\n"); printf("-N Nid_cell\n"); printf("-o Carrier frequency offset in Hz\n"); + printf("-O SSB subcarrier offset\n"); //printf("-O oversampling factor (1,2,4,8,16)\n"); //printf("-p Use extended prefix mode\n"); printf("-P PBCH phase, allowed values 0-3\n"); @@ -457,7 +463,7 @@ int main(int argc, char **argv) nr_phy_config_request_sim_pbchsim(gNB,N_RB_DL,N_RB_DL,mu,Nid_cell,SSB_positions); phy_init_nr_gNB(gNB,0,1); - frame_parms->ssb_start_subcarrier = 12 * gNB->gNB_config.ssb_table.ssb_offset_point_a.value; + frame_parms->ssb_start_subcarrier = 12 * gNB->gNB_config.ssb_table.ssb_offset_point_a.value + ssb_subcarrier_offset; uint8_t n_hf = 0; int cyclic_prefix_type = NFAPI_CP_NORMAL; @@ -582,6 +588,7 @@ int main(int argc, char **argv) msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.bchPayload = 0x55dd33; msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.SsbBlockIndex = i; + msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset = ssb_subcarrier_offset; start_symbol = nr_get_ssb_start_symbol(frame_parms,i); int slot = start_symbol/14; @@ -724,8 +731,8 @@ int main(int argc, char **argv) if (ret<0) n_errors++; } else { - UE_nr_rxtx_proc_t proc={0}; - NR_UE_PDCCH_CONFIG phy_pdcch_config={0}; + UE_nr_rxtx_proc_t proc={0}; + NR_UE_PDCCH_CONFIG phy_pdcch_config={0}; UE->rx_offset=0; uint8_t ssb_index = 0; From 5ed67b85a78b4ff7be4dda5b2c93b8b3207bd24f Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 10 May 2022 13:03:41 +0100 Subject: [PATCH 101/267] Free allocated memory --- openair1/PHY/INIT/nr_init.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 1722dfb861..e2f549f12e 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -788,7 +788,11 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) } free_and_zero(gNB->nr_srs_info[id]->sc_list); free_and_zero(gNB->nr_srs_info[id]->srs_generated_signal); + free_and_zero(gNB->nr_srs_info[id]->signal_power); + free_and_zero(gNB->nr_srs_info[id]->noise_power_per_rb); free_and_zero(gNB->nr_srs_info[id]->noise_power); + free_and_zero(gNB->nr_srs_info[id]->snr_per_rb); + free_and_zero(gNB->nr_srs_info[id]->snr); free_and_zero(gNB->nr_srs_info[id]->srs_received_signal); free_and_zero(gNB->nr_srs_info[id]->srs_ls_estimated_channel); free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_freq); From 68be6f83e6dba23bed1a365696c31451c645c3ac Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 10 May 2022 13:59:36 +0200 Subject: [PATCH 102/267] randominit(): show used seed when using time() --- openair1/SIMULATION/TOOLS/rangen_double.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/SIMULATION/TOOLS/rangen_double.c b/openair1/SIMULATION/TOOLS/rangen_double.c index 82b1557a5b..0ba9e196b1 100644 --- a/openair1/SIMULATION/TOOLS/rangen_double.c +++ b/openair1/SIMULATION/TOOLS/rangen_double.c @@ -42,7 +42,6 @@ void randominit(unsigned seed_init) { int i; // this need to be integrated with the existing rng, like taus: navid - printf("Initializing random number generator, seed %x\n",seed_init); if (seed_init == 0) { srand((unsigned)time(NULL)); @@ -51,6 +50,7 @@ void randominit(unsigned seed_init) } else { seed = seed_init; } + printf("Initializing random number generator, seed %x\n",seed); if (seed % 2 == 0) seed += 1; /* seed and mod are relative prime */ From 08975e451fd9110ff6401589d45437c5cdb5115e Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 10 May 2022 14:03:24 +0100 Subject: [PATCH 103/267] Update the ul_prbblacklist based on SRS measurements and an ul_prbblack_SNR_threshold --- openair2/GNB_APP/MACRLC_nr_paramdef.h | 21 +++++++++++-------- openair2/GNB_APP/gnb_config.c | 1 + .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 14 ++++++++++++- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 4 +++- ...gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf | 1 + .../gnb.sa.band78.fr1.106PRB.usrpb210.conf | 1 + 6 files changed, 31 insertions(+), 11 deletions(-) diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index e634f077e2..3cc0396a3e 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -58,6 +58,7 @@ #define CONFIG_STRING_MACRLC_ULSCH_MAX_FRAME_INACTIVITY "ulsch_max_frame_inactivity" #define CONFIG_STRING_MACRLC_PUSCHTARGETSNRX10 "pusch_TargetSNRx10" #define CONFIG_STRING_MACRLC_PUCCHTARGETSNRX10 "pucch_TargetSNRx10" +#define CONFIG_STRING_MACRLC_UL_PRBBLACK_SNR_THRESHOLD "ul_prbblack_SNR_threshold" #define CONFIG_STRING_MACRLC_PUCCHFAILURETHRES "pucch_FailureThres" #define CONFIG_STRING_MACRLC_PUSCHFAILURETHRES "pusch_FailureThres" #define CONFIG_STRING_MACRLC_DL_BLER_TARGET_UPPER "dl_bler_target_upper" @@ -93,6 +94,7 @@ {CONFIG_STRING_MACRLC_ULSCH_MAX_FRAME_INACTIVITY, NULL, 0, uptr:NULL, defintval:10, TYPE_UINT, 0}, \ {CONFIG_STRING_MACRLC_PUSCHTARGETSNRX10, NULL, 0, iptr:NULL, defintval:200, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUCCHTARGETSNRX10, NULL, 0, iptr:NULL, defintval:150, TYPE_INT, 0}, \ +{CONFIG_STRING_MACRLC_UL_PRBBLACK_SNR_THRESHOLD, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUCCHFAILURETHRES, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUSCHFAILURETHRES, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_DL_BLER_TARGET_UPPER, "Upper threshold of BLER to decrease DL MCS", 0, dblptr:NULL, defdblval:0.15, TYPE_DOUBLE, 0}, \ @@ -123,14 +125,15 @@ #define MACRLC_ULSCH_MAX_FRAME_INACTIVITY 17 #define MACRLC_PUSCHTARGETSNRX10_IDX 18 #define MACRLC_PUCCHTARGETSNRX10_IDX 19 -#define MACRLC_PUCCHFAILURETHRES_IDX 20 -#define MACRLC_PUSCHFAILURETHRES_IDX 21 -#define MACRLC_DL_BLER_TARGET_UPPER_IDX 22 -#define MACRLC_DL_BLER_TARGET_LOWER_IDX 23 -#define MACRLC_DL_RD2_BLER_THRESHOLD_IDX 24 -#define MACRLC_DL_MAX_MCS_IDX 25 -#define MACRLC_HARQ_ROUND_MAX_IDX 26 -#define MACRLC_MIN_GRANT_PRB_IDX 27 -#define MACRLC_MIN_GRANT_MCS_IDX 28 +#define MACRLC_UL_PRBBLACK_SNR_THRESHOLD_IDX 20 +#define MACRLC_PUCCHFAILURETHRES_IDX 21 +#define MACRLC_PUSCHFAILURETHRES_IDX 22 +#define MACRLC_DL_BLER_TARGET_UPPER_IDX 23 +#define MACRLC_DL_BLER_TARGET_LOWER_IDX 24 +#define MACRLC_DL_RD2_BLER_THRESHOLD_IDX 25 +#define MACRLC_DL_MAX_MCS_IDX 26 +#define MACRLC_HARQ_ROUND_MAX_IDX 27 +#define MACRLC_MIN_GRANT_PRB_IDX 28 +#define MACRLC_MIN_GRANT_MCS_IDX 29 /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ #endif diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 62dc72a857..530725bb51 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -770,6 +770,7 @@ void RCconfig_nr_macrlc() { RC.nb_nr_mac_CC[j] = *(MacRLC_ParamList.paramarray[j][MACRLC_CC_IDX].iptr); RC.nrmac[j]->pusch_target_snrx10 = *(MacRLC_ParamList.paramarray[j][MACRLC_PUSCHTARGETSNRX10_IDX].iptr); RC.nrmac[j]->pucch_target_snrx10 = *(MacRLC_ParamList.paramarray[j][MACRLC_PUCCHTARGETSNRX10_IDX].iptr); + RC.nrmac[j]->ul_prbblack_SNR_threshold = *(MacRLC_ParamList.paramarray[j][MACRLC_UL_PRBBLACK_SNR_THRESHOLD_IDX].iptr); RC.nrmac[j]->pucch_failure_thres = *(MacRLC_ParamList.paramarray[j][MACRLC_PUCCHFAILURETHRES_IDX].iptr); RC.nrmac[j]->pusch_failure_thres = *(MacRLC_ParamList.paramarray[j][MACRLC_PUSCHFAILURETHRES_IDX].iptr); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index e763548ea3..39a6f52327 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -890,7 +890,7 @@ void handle_nr_srs_measurements(const module_id_t module_id, const uint8_t num_reported_symbols, nfapi_nr_srs_indication_reported_symbol_t* reported_symbol_list) { - LOG_I(NR_MAC, "(%d.%d) Received SRS indication for rnti: 0x%04x\n", frame, slot, rnti); + LOG_D(NR_MAC, "(%d.%d) Received SRS indication for rnti: 0x%04x\n", frame, slot, rnti); #ifdef SRS_IND_DEBUG LOG_I(NR_MAC, "frame = %i\n", frame); @@ -906,6 +906,18 @@ void handle_nr_srs_measurements(const module_id_t module_id, rb, reported_symbol_list[0].rb_list[rb].rb_snr, (reported_symbol_list[0].rb_list[rb].rb_snr>>1)-64); } #endif + + int ul_prbblack_SNR_threshold = RC.nrmac[module_id]->ul_prbblack_SNR_threshold; + uint16_t *ulprbbl = RC.nrmac[module_id]->ulprbbl; + + memset(ulprbbl, 0, reported_symbol_list[0].num_rbs*sizeof(uint16_t)); + for (int rb = 0; rb < reported_symbol_list[0].num_rbs; rb++) { + int snr = (reported_symbol_list[0].rb_list[rb].rb_snr>>1)-64; + if (snr < ul_prbblack_SNR_threshold) { + ulprbbl[rb] = 0x3FFF; // all symbols taken + } + LOG_D(NR_MAC, "ulprbbl[%3i] = 0x%x\n", rb, ulprbbl[rb]); + } } long get_K2(NR_ServingCellConfigCommon_t *scc, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index a2c77234c0..5ddeacf4ed 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -721,6 +721,8 @@ typedef struct gNB_MAC_INST_s { int pusch_target_snrx10; /// Pucch target SNR int pucch_target_snrx10; + /// SNR threshold needed to put or not a PRB in the black list + int ul_prbblack_SNR_threshold; /// PUCCH Failure threshold (compared to consecutive PUCCH DTX) int pucch_failure_thres; /// PUSCH Failure threshold (compared to consecutive PUSCH DTX) @@ -735,7 +737,7 @@ typedef struct gNB_MAC_INST_s { /// current PDU index (BCH,DLSCH) uint16_t pdu_index[NFAPI_CC_MAX]; int num_ulprbbl; - uint16_t ulprbbl[275]; + uint16_t ulprbbl[MAX_BWP_SIZE]; /// NFAPI Config Request Structure nfapi_nr_config_request_scf_t config[NFAPI_CC_MAX]; /// NFAPI DL Config Request Structure diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf index 2881a77d48..33c7353151 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf @@ -207,6 +207,7 @@ MACRLCs = ( tr_n_preference = "local_RRC"; #pusch_TargetSNRx10 = 150; #pucch_TargetSNRx10 = 200; + ul_prbblack_SNR_threshold = 10; ulsch_max_frame_inactivity = 0; } ); diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf index c83565e8bb..12feb0d4b0 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf @@ -205,6 +205,7 @@ MACRLCs = ( tr_n_preference = "local_RRC"; pusch_TargetSNRx10 = 150; pucch_TargetSNRx10 = 200; + ul_prbblack_SNR_threshold = 10; ulsch_max_frame_inactivity = 0; } ); From ba5bda5c6e25c3d4674394f32a753360249f8d32 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 10 May 2022 15:00:43 +0100 Subject: [PATCH 104/267] Fix bw_scaling --- openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index a2ee62fbde..403a96983c 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -90,7 +90,7 @@ int nr_est_timing_advance_srs(NR_DL_FRAME_PARMS *frame_parms, } // Scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size - uint16_t bw_scaling = frame_parms->ofdm_symbol_size >> 11; + uint16_t bw_scaling = frame_parms->ofdm_symbol_size >> 7; // do some integer rounding to improve TA accuracy int sync_pos_rounded; From 6d736db22d03d187becf16ddc4cda03ea3a6a0b7 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 18 May 2022 17:23:55 +0200 Subject: [PATCH 105/267] applying PUCCH harmonization to multiple BWP --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 116 +++---------------- openair2/RRC/NR/nr_rrc_config.c | 9 -- openair2/RRC/NR/nr_rrc_config.h | 1 - openair2/RRC/NR/rrc_gNB_reconfig.c | 174 +++++++--------------------- 4 files changed, 58 insertions(+), 242 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 82a0cd572f..d9e4658be2 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1265,6 +1265,8 @@ void fill_default_uplinkBWP(NR_BWP_Uplink_t *ubwp, ubwp->bwp_Common->genericParameters.cyclicPrefix = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.cyclicPrefix; } + int curr_bwp = NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth,MAX_BWP_SIZE); + ubwp->bwp_Common->rach_ConfigCommon = NULL; ubwp->bwp_Common->pusch_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon; ubwp->bwp_Common->pucch_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon; @@ -1277,109 +1279,17 @@ void fill_default_uplinkBWP(NR_BWP_Uplink_t *ubwp, ubwp->bwp_Dedicated->pucch_Config->present = NR_SetupRelease_PUCCH_Config_PR_setup; NR_PUCCH_Config_t *pucch_Config = calloc(1,sizeof(*pucch_Config)); ubwp->bwp_Dedicated->pucch_Config->choice.setup=pucch_Config; + pucch_Config->resourceSetToAddModList = calloc(1,sizeof(*pucch_Config->resourceSetToAddModList)); pucch_Config->resourceSetToReleaseList = NULL; - NR_PUCCH_ResourceSet_t *pucchresset0=calloc(1,sizeof(*pucchresset0)); - pucchresset0->pucch_ResourceSetId = 0; - NR_PUCCH_ResourceId_t *pucchres0id0=calloc(1,sizeof(*pucchres0id0)); - *pucchres0id0=ubwp->bwp_Id; // To uniquely identify each pucchresource lets derive it from the BWPId - ASN_SEQUENCE_ADD(&pucchresset0->resourceList.list,pucchres0id0); - pucchresset0->maxPayloadSize=NULL; - ASN_SEQUENCE_ADD(&pucch_Config->resourceSetToAddModList->list,pucchresset0); pucch_Config->resourceToAddModList = calloc(1,sizeof(*pucch_Config->resourceToAddModList)); pucch_Config->resourceToReleaseList = NULL; - int curr_bwp = NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth,MAX_BWP_SIZE); - NR_PUCCH_Resource_t *pucchres0=calloc(1,sizeof(*pucchres0)); - pucchres0->pucch_ResourceId=*pucchres0id0; - pucchres0->startingPRB=(8+uid) % curr_bwp; - pucchres0->intraSlotFrequencyHopping=NULL; - pucchres0->secondHopPRB=NULL; - pucchres0->format.present= NR_PUCCH_Resource__format_PR_format0; - pucchres0->format.choice.format0=calloc(1,sizeof(*pucchres0->format.choice.format0)); - pucchres0->format.choice.format0->initialCyclicShift=0; - pucchres0->format.choice.format0->nrofSymbols=1; - pucchres0->format.choice.format0->startingSymbolIndex=13; - ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres0); + config_pucch_resset0(pucch_Config, uid, curr_bwp, NULL); + config_pucch_resset1(pucch_Config, NULL); + set_pucch_power_config(pucch_Config, configuration->do_CSIRS); -/* - pucch_Config->format2=calloc(1,sizeof(*pucch_Config->format2)); - pucch_Config->format2->present=NR_SetupRelease_PUCCH_FormatConfig_PR_setup; - NR_PUCCH_FormatConfig_t *pucchfmt2 = calloc(1,sizeof(*pucchfmt2)); - pucch_Config->format2->choice.setup = pucchfmt2; - pucchfmt2->interslotFrequencyHopping=NULL; - pucchfmt2->additionalDMRS=NULL; - pucchfmt2->maxCodeRate=calloc(1,sizeof(*pucchfmt2->maxCodeRate)); - *pucchfmt2->maxCodeRate=NR_PUCCH_MaxCodeRate_zeroDot35; - pucchfmt2->nrofSlots=NULL; - pucchfmt2->pi2BPSK=NULL; - pucchfmt2->simultaneousHARQ_ACK_CSI=calloc(1,sizeof(*pucchfmt2->simultaneousHARQ_ACK_CSI)); - *pucchfmt2->simultaneousHARQ_ACK_CSI=NR_PUCCH_FormatConfig__simultaneousHARQ_ACK_CSI_true; -*/ - - // PUCCH config - Scheduling request configuration - pucch_Config->schedulingRequestResourceToAddModList = calloc(1,sizeof(*pucch_Config->schedulingRequestResourceToAddModList)); - NR_SchedulingRequestResourceConfig_t *schedulingRequestResourceConfig = calloc(1,sizeof(*schedulingRequestResourceConfig)); - schedulingRequestResourceConfig->schedulingRequestResourceId = 1; - schedulingRequestResourceConfig->schedulingRequestID = 0; - schedulingRequestResourceConfig->periodicityAndOffset = calloc(1,sizeof(*schedulingRequestResourceConfig->periodicityAndOffset)); - schedulingRequestResourceConfig->periodicityAndOffset->present = NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl40; // 40 slot period - // note: make sure that there is no issue here. Later choose the RNTI accordingly. - // Here we would be limited to 3 UEs on this resource (1 1/2 Frames 30 kHz SCS, 5 ms TDD periodicity => slots 7,8,9). - // This should be a temporary resource until the first RRCReconfiguration gives new pucch resources. - // Check for above configuration and exit for now if it is not the case - AssertFatal(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.subcarrierSpacing==NR_SubcarrierSpacing_kHz30, - "SCS != 30kHz\n"); - AssertFatal(scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity==NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms5, - "TDD period != 5ms : %ld\n",scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity); - schedulingRequestResourceConfig->periodicityAndOffset->choice.sl40 = 8; - schedulingRequestResourceConfig->resource = calloc(1,sizeof(*schedulingRequestResourceConfig->resource)); - *schedulingRequestResourceConfig->resource = *pucchres0id0; - ASN_SEQUENCE_ADD(&pucch_Config->schedulingRequestResourceToAddModList->list,schedulingRequestResourceConfig); - pucch_Config->schedulingRequestResourceToReleaseList=NULL; - - pucch_Config->multi_CSI_PUCCH_ResourceList=NULL; - pucch_Config->dl_DataToUL_ACK = calloc(1,sizeof(*pucch_Config->dl_DataToUL_ACK)); - long *delay[8]; - for (int i=0;i<8;i++) { - delay[i] = calloc(1,sizeof(*delay[i])); - AssertFatal(configuration->minRXTXTIME >=2 && configuration->minRXTXTIME <7, "check minRXTXTIME %d\n",configuration->minRXTXTIME); - *delay[i] = i+configuration->minRXTXTIME; - ASN_SEQUENCE_ADD(&pucch_Config->dl_DataToUL_ACK->list,delay[i]); - } - pucch_Config->spatialRelationInfoToAddModList = calloc(1,sizeof(*pucch_Config->spatialRelationInfoToAddModList)); - NR_PUCCH_SpatialRelationInfo_t *pucchspatial = calloc(1,sizeof(*pucchspatial)); - pucchspatial->pucch_SpatialRelationInfoId = 1; - pucchspatial->servingCellId = NULL; - if(configuration->do_CSIRS) { - pucchspatial->referenceSignal.present = NR_PUCCH_SpatialRelationInfo__referenceSignal_PR_csi_RS_Index; - pucchspatial->referenceSignal.choice.csi_RS_Index = 0; - } - else { - pucchspatial->referenceSignal.present = NR_PUCCH_SpatialRelationInfo__referenceSignal_PR_ssb_Index; - pucchspatial->referenceSignal.choice.ssb_Index = 0; - } - pucchspatial->pucch_PathlossReferenceRS_Id = 0; - pucchspatial->p0_PUCCH_Id = 1; - pucchspatial->closedLoopIndex = NR_PUCCH_SpatialRelationInfo__closedLoopIndex_i0; - ASN_SEQUENCE_ADD(&pucch_Config->spatialRelationInfoToAddModList->list,pucchspatial); - pucch_Config->spatialRelationInfoToReleaseList=NULL; - pucch_Config->pucch_PowerControl=calloc(1,sizeof(*pucch_Config->pucch_PowerControl)); - pucch_Config->pucch_PowerControl->deltaF_PUCCH_f0 = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->deltaF_PUCCH_f0)); - *pucch_Config->pucch_PowerControl->deltaF_PUCCH_f0 = 0; - pucch_Config->pucch_PowerControl->deltaF_PUCCH_f1 = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->deltaF_PUCCH_f1)); - *pucch_Config->pucch_PowerControl->deltaF_PUCCH_f1 = 0; - pucch_Config->pucch_PowerControl->deltaF_PUCCH_f2 = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->deltaF_PUCCH_f2)); - *pucch_Config->pucch_PowerControl->deltaF_PUCCH_f2 = 0; - pucch_Config->pucch_PowerControl->deltaF_PUCCH_f3 = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->deltaF_PUCCH_f3)); - *pucch_Config->pucch_PowerControl->deltaF_PUCCH_f3 = 0; - pucch_Config->pucch_PowerControl->deltaF_PUCCH_f4 = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->deltaF_PUCCH_f4)); - *pucch_Config->pucch_PowerControl->deltaF_PUCCH_f4 = 0; - pucch_Config->pucch_PowerControl->p0_Set = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->p0_Set)); - NR_P0_PUCCH_t *p00 = calloc(1,sizeof(*p00)); - p00->p0_PUCCH_Id=1; - p00->p0_PUCCH_Value = 0; - ASN_SEQUENCE_ADD(&pucch_Config->pucch_PowerControl->p0_Set->list,p00); - pucch_Config->pucch_PowerControl->pathlossReferenceRSs = NULL; + scheduling_request_config(scc, pucch_Config); + set_dl_DataToUL_ACK(pucch_Config, configuration->minRXTXTIME); // PUSCH config ubwp->bwp_Dedicated->pusch_Config = calloc(1,sizeof(*ubwp->bwp_Dedicated->pusch_Config)); @@ -1714,7 +1624,7 @@ void fill_initial_SpCellConfig(int uid, srs_res0->spatialRelationInfo->referenceSignal.choice.csi_RS_Index=0; ASN_SEQUENCE_ADD(&srs_Config->srs_ResourceToAddModList->list,srs_res0); - scheduling_request_config(scc, cellGroupConfig->mac_CellGroupConfig, pucch_Config); + scheduling_request_config(scc, pucch_Config); set_dl_DataToUL_ACK(pucch_Config, configuration->minRXTXTIME); @@ -2255,6 +2165,14 @@ void fill_initial_cellGroupConfig(int uid, mac_CellGroupConfig->phr_Config->choice.setup->phr_ProhibitTimer = NR_PHR_Config__phr_ProhibitTimer_sf10; mac_CellGroupConfig->phr_Config->choice.setup->phr_Tx_PowerFactorChange = NR_PHR_Config__phr_Tx_PowerFactorChange_dB1; + mac_CellGroupConfig->schedulingRequestConfig = calloc(1, sizeof(*mac_CellGroupConfig->schedulingRequestConfig)); + mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList = CALLOC(1,sizeof(*mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList)); + struct NR_SchedulingRequestToAddMod *schedulingrequestlist = CALLOC(1,sizeof(*schedulingrequestlist)); + schedulingrequestlist->schedulingRequestId = 0; + schedulingrequestlist->sr_ProhibitTimer = NULL; + schedulingrequestlist->sr_TransMax = NR_SchedulingRequestToAddMod__sr_TransMax_n64; + ASN_SEQUENCE_ADD(&(mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList->list),schedulingrequestlist); + cellGroupConfig->mac_CellGroupConfig = mac_CellGroupConfig; physicalCellGroupConfig = calloc(1,sizeof(*physicalCellGroupConfig)); diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index e1c62e18c1..eeb7fe9028 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -593,17 +593,8 @@ void set_SR_periodandoffset(NR_SchedulingRequestResourceConfig_t *schedulingRequ } void scheduling_request_config(NR_ServingCellConfigCommon_t *scc, - NR_MAC_CellGroupConfig_t *mac_CellGroupConfig, NR_PUCCH_Config_t *pucch_Config) { - mac_CellGroupConfig->schedulingRequestConfig = calloc(1, sizeof(*mac_CellGroupConfig->schedulingRequestConfig)); - mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList = CALLOC(1,sizeof(*mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList)); - struct NR_SchedulingRequestToAddMod *schedulingrequestlist = CALLOC(1,sizeof(*schedulingrequestlist)); - schedulingrequestlist->schedulingRequestId = 0; - schedulingrequestlist->sr_ProhibitTimer = NULL; - schedulingrequestlist->sr_TransMax = NR_SchedulingRequestToAddMod__sr_TransMax_n64; - ASN_SEQUENCE_ADD(&(mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList->list),schedulingrequestlist); - // format with <=2 bits in pucch resource set 0 NR_PUCCH_ResourceSet_t *pucchresset = pucch_Config->resourceSetToAddModList->list.array[0]; // assigning the 1st pucch resource in the set to scheduling request diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index 06e5eaef45..575f642290 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -120,7 +120,6 @@ void config_pucch_resset1(NR_PUCCH_Config_t *pucch_Config, NR_UE_NR_Capability_t void set_dl_DataToUL_ACK(NR_PUCCH_Config_t *pucch_Config, int min_feedback_time); void set_pucch_power_config(NR_PUCCH_Config_t *pucch_Config, int do_csirs); void scheduling_request_config(NR_ServingCellConfigCommon_t *scc, - NR_MAC_CellGroupConfig_t *mac_CellGroupConfig, NR_PUCCH_Config_t *pucch_Config); void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, NR_CSI_MeasConfig_t *csi_MeasConfig, diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index 830383e005..79f897ef9a 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -366,128 +366,26 @@ void fill_default_nsa_uplinkBWP(NR_BWP_Uplink_t *ubwp, /// BWP dedicated configuration - if (!ubwp->bwp_Dedicated) { + if (!ubwp->bwp_Dedicated) ubwp->bwp_Dedicated = calloc(1,sizeof(*ubwp->bwp_Dedicated)); - } + + int curr_bwp = NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth,275); + ubwp->bwp_Dedicated->pucch_Config = calloc(1,sizeof(*ubwp->bwp_Dedicated->pucch_Config)); ubwp->bwp_Dedicated->pucch_Config->present = NR_SetupRelease_PUCCH_Config_PR_setup; NR_PUCCH_Config_t *pucch_Config = calloc(1,sizeof(*pucch_Config)); ubwp->bwp_Dedicated->pucch_Config->choice.setup=pucch_Config; + pucch_Config->resourceSetToAddModList = calloc(1,sizeof(*pucch_Config->resourceSetToAddModList)); pucch_Config->resourceSetToReleaseList = NULL; - NR_PUCCH_ResourceSet_t *pucchresset0=calloc(1,sizeof(*pucchresset0)); - NR_PUCCH_ResourceSet_t *pucchresset1=calloc(1,sizeof(*pucchresset1)); - pucchresset0->pucch_ResourceSetId = 0; - NR_PUCCH_ResourceId_t *pucchresset0id0=calloc(1,sizeof(*pucchresset0id0)); - *pucchresset0id0=1; - ASN_SEQUENCE_ADD(&pucchresset0->resourceList.list,pucchresset0id0); - pucchresset0->maxPayloadSize=NULL; - ASN_SEQUENCE_ADD(&pucch_Config->resourceSetToAddModList->list,pucchresset0); - - pucchresset1->pucch_ResourceSetId = 1; - NR_PUCCH_ResourceId_t *pucchresset1id0=calloc(1,sizeof(*pucchresset1id0)); - *pucchresset1id0=2; - ASN_SEQUENCE_ADD(&pucchresset1->resourceList.list,pucchresset1id0); - pucchresset1->maxPayloadSize=NULL; - ASN_SEQUENCE_ADD(&pucch_Config->resourceSetToAddModList->list,pucchresset1); - pucch_Config->resourceToAddModList = calloc(1,sizeof(*pucch_Config->resourceToAddModList)); pucch_Config->resourceToReleaseList = NULL; - NR_PUCCH_Resource_t *pucchres0=calloc(1,sizeof(*pucchres0)); - NR_PUCCH_Resource_t *pucchres2=calloc(1,sizeof(*pucchres2)); + config_pucch_resset0(pucch_Config, uid, curr_bwp, NULL); + config_pucch_resset1(pucch_Config, NULL); + set_pucch_power_config(pucch_Config, configuration->do_CSIRS); - int curr_bwp = NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth,275); - - pucchres0->pucch_ResourceId=1; - pucchres0->startingPRB= (8 + uid) % curr_bwp; - pucchres0->intraSlotFrequencyHopping=NULL; - pucchres0->secondHopPRB=NULL; - pucchres0->format.present= NR_PUCCH_Resource__format_PR_format0; - pucchres0->format.choice.format0=calloc(1,sizeof(*pucchres0->format.choice.format0)); - pucchres0->format.choice.format0->initialCyclicShift=0; - pucchres0->format.choice.format0->nrofSymbols=1; - pucchres0->format.choice.format0->startingSymbolIndex=13; - ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres0); - - pucchres2->pucch_ResourceId=2; - pucchres2->startingPRB=0; - pucchres2->intraSlotFrequencyHopping=NULL; - pucchres2->secondHopPRB=NULL; - pucchres2->format.present= NR_PUCCH_Resource__format_PR_format2; - pucchres2->format.choice.format2=calloc(1,sizeof(*pucchres2->format.choice.format2)); - pucchres2->format.choice.format2->nrofPRBs=8; - pucchres2->format.choice.format2->nrofSymbols=1; - pucchres2->format.choice.format2->startingSymbolIndex=13; - ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres2); - - pucch_Config->format2=calloc(1,sizeof(*pucch_Config->format2)); - pucch_Config->format2->present=NR_SetupRelease_PUCCH_FormatConfig_PR_setup; - NR_PUCCH_FormatConfig_t *pucchfmt2 = calloc(1,sizeof(*pucchfmt2)); - pucch_Config->format2->choice.setup = pucchfmt2; - pucchfmt2->interslotFrequencyHopping=NULL; - pucchfmt2->additionalDMRS=NULL; - pucchfmt2->maxCodeRate=calloc(1,sizeof(*pucchfmt2->maxCodeRate)); - *pucchfmt2->maxCodeRate=NR_PUCCH_MaxCodeRate_zeroDot35; - pucchfmt2->nrofSlots=NULL; - pucchfmt2->pi2BPSK=NULL; - pucchfmt2->simultaneousHARQ_ACK_CSI=calloc(1,sizeof(*pucchfmt2->simultaneousHARQ_ACK_CSI)); - *pucchfmt2->simultaneousHARQ_ACK_CSI=NR_PUCCH_FormatConfig__simultaneousHARQ_ACK_CSI_true; - - // for scheduling requestresource - pucch_Config->schedulingRequestResourceToAddModList = calloc(1,sizeof(*pucch_Config->schedulingRequestResourceToAddModList)); - NR_SchedulingRequestResourceConfig_t *schedulingRequestResourceConfig = calloc(1,sizeof(*schedulingRequestResourceConfig)); - schedulingRequestResourceConfig->schedulingRequestResourceId = 1; - schedulingRequestResourceConfig->schedulingRequestID = 0; - schedulingRequestResourceConfig->periodicityAndOffset = calloc(1,sizeof(*schedulingRequestResourceConfig->periodicityAndOffset)); - schedulingRequestResourceConfig->periodicityAndOffset->present = NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl10; - schedulingRequestResourceConfig->periodicityAndOffset->choice.sl10 = 7; - schedulingRequestResourceConfig->resource = calloc(1,sizeof(*schedulingRequestResourceConfig->resource)); - *schedulingRequestResourceConfig->resource = 1; - ASN_SEQUENCE_ADD(&pucch_Config->schedulingRequestResourceToAddModList->list,schedulingRequestResourceConfig); - - pucch_Config->schedulingRequestResourceToReleaseList=NULL; - pucch_Config->multi_CSI_PUCCH_ResourceList=NULL; - pucch_Config->dl_DataToUL_ACK = calloc(1,sizeof(*pucch_Config->dl_DataToUL_ACK)); - long *delay[8]; - for (int i=0;i<8;i++) { - delay[i] = calloc(1,sizeof(*delay[i])); - *delay[i] = i + configuration->minRXTXTIME; - ASN_SEQUENCE_ADD(&pucch_Config->dl_DataToUL_ACK->list,delay[i]); - } - pucch_Config->spatialRelationInfoToAddModList = calloc(1,sizeof(*pucch_Config->spatialRelationInfoToAddModList)); - NR_PUCCH_SpatialRelationInfo_t *pucchspatial = calloc(1,sizeof(*pucchspatial)); - pucchspatial->pucch_SpatialRelationInfoId = 1; - pucchspatial->servingCellId = NULL; - if(configuration->do_CSIRS) { - pucchspatial->referenceSignal.present = NR_PUCCH_SpatialRelationInfo__referenceSignal_PR_csi_RS_Index; - pucchspatial->referenceSignal.choice.csi_RS_Index = 0; - } - else { - pucchspatial->referenceSignal.present = NR_PUCCH_SpatialRelationInfo__referenceSignal_PR_ssb_Index; - pucchspatial->referenceSignal.choice.ssb_Index = 0; - } - pucchspatial->pucch_PathlossReferenceRS_Id = 0; - pucchspatial->p0_PUCCH_Id = 1; - pucchspatial->closedLoopIndex = NR_PUCCH_SpatialRelationInfo__closedLoopIndex_i0; - ASN_SEQUENCE_ADD(&pucch_Config->spatialRelationInfoToAddModList->list,pucchspatial); - pucch_Config->spatialRelationInfoToReleaseList=NULL; - pucch_Config->pucch_PowerControl=calloc(1,sizeof(*pucch_Config->pucch_PowerControl)); - pucch_Config->pucch_PowerControl->deltaF_PUCCH_f0 = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->deltaF_PUCCH_f0)); - *pucch_Config->pucch_PowerControl->deltaF_PUCCH_f0 = 0; - pucch_Config->pucch_PowerControl->deltaF_PUCCH_f1 = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->deltaF_PUCCH_f1)); - *pucch_Config->pucch_PowerControl->deltaF_PUCCH_f1 = 0; - pucch_Config->pucch_PowerControl->deltaF_PUCCH_f2 = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->deltaF_PUCCH_f2)); - *pucch_Config->pucch_PowerControl->deltaF_PUCCH_f2 = 0; - pucch_Config->pucch_PowerControl->deltaF_PUCCH_f3 = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->deltaF_PUCCH_f3)); - *pucch_Config->pucch_PowerControl->deltaF_PUCCH_f3 = 0; - pucch_Config->pucch_PowerControl->deltaF_PUCCH_f4 = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->deltaF_PUCCH_f4)); - *pucch_Config->pucch_PowerControl->deltaF_PUCCH_f4 = 0; - pucch_Config->pucch_PowerControl->p0_Set = calloc(1,sizeof(*pucch_Config->pucch_PowerControl->p0_Set)); - NR_P0_PUCCH_t *p00 = calloc(1,sizeof(*p00)); - p00->p0_PUCCH_Id=1; - p00->p0_PUCCH_Value = 0; - ASN_SEQUENCE_ADD(&pucch_Config->pucch_PowerControl->p0_Set->list,p00); - pucch_Config->pucch_PowerControl->pathlossReferenceRSs = NULL; + scheduling_request_config(servingcellconfigcommon, pucch_Config); + set_dl_DataToUL_ACK(pucch_Config, configuration->minRXTXTIME); ubwp->bwp_Dedicated->pusch_Config = calloc(1,sizeof(*ubwp->bwp_Dedicated->pusch_Config)); ubwp->bwp_Dedicated->pusch_Config->present = NR_SetupRelease_PUSCH_Config_PR_setup; @@ -693,31 +591,33 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco secondaryCellGroup->rlc_BearerToAddModList = calloc(1,sizeof(*secondaryCellGroup->rlc_BearerToAddModList)); ASN_SEQUENCE_ADD(&secondaryCellGroup->rlc_BearerToAddModList->list, RLC_BearerConfig); - secondaryCellGroup->mac_CellGroupConfig=calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig)); - secondaryCellGroup->mac_CellGroupConfig->drx_Config = NULL; + NR_MAC_CellGroupConfig_t *mac_CellGroupConfig = secondaryCellGroup->mac_CellGroupConfig; - secondaryCellGroup->mac_CellGroupConfig->bsr_Config=calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig->bsr_Config)); - secondaryCellGroup->mac_CellGroupConfig->bsr_Config->periodicBSR_Timer = NR_BSR_Config__periodicBSR_Timer_sf10; - secondaryCellGroup->mac_CellGroupConfig->bsr_Config->retxBSR_Timer = NR_BSR_Config__retxBSR_Timer_sf160; - secondaryCellGroup->mac_CellGroupConfig->tag_Config=calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig->tag_Config)); - secondaryCellGroup->mac_CellGroupConfig->tag_Config->tag_ToReleaseList = NULL; - secondaryCellGroup->mac_CellGroupConfig->tag_Config->tag_ToAddModList = calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig->tag_Config->tag_ToAddModList)); + mac_CellGroupConfig=calloc(1,sizeof(*mac_CellGroupConfig)); + mac_CellGroupConfig->drx_Config = NULL; + + mac_CellGroupConfig->bsr_Config=calloc(1,sizeof(*mac_CellGroupConfig->bsr_Config)); + mac_CellGroupConfig->bsr_Config->periodicBSR_Timer = NR_BSR_Config__periodicBSR_Timer_sf10; + mac_CellGroupConfig->bsr_Config->retxBSR_Timer = NR_BSR_Config__retxBSR_Timer_sf160; + mac_CellGroupConfig->tag_Config=calloc(1,sizeof(*mac_CellGroupConfig->tag_Config)); + mac_CellGroupConfig->tag_Config->tag_ToReleaseList = NULL; + mac_CellGroupConfig->tag_Config->tag_ToAddModList = calloc(1,sizeof(*mac_CellGroupConfig->tag_Config->tag_ToAddModList)); struct NR_TAG *tag=calloc(1,sizeof(*tag)); tag->tag_Id = 0; tag->timeAlignmentTimer = NR_TimeAlignmentTimer_infinity; - ASN_SEQUENCE_ADD(&secondaryCellGroup->mac_CellGroupConfig->tag_Config->tag_ToAddModList->list,tag); - secondaryCellGroup->mac_CellGroupConfig->phr_Config = calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig->phr_Config)); - secondaryCellGroup->mac_CellGroupConfig->phr_Config->present = NR_SetupRelease_PHR_Config_PR_setup; - secondaryCellGroup->mac_CellGroupConfig->phr_Config->choice.setup = calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig->phr_Config->choice.setup)); - secondaryCellGroup->mac_CellGroupConfig->phr_Config->choice.setup->phr_PeriodicTimer = NR_PHR_Config__phr_PeriodicTimer_sf20; - secondaryCellGroup->mac_CellGroupConfig->phr_Config->choice.setup->phr_ProhibitTimer = NR_PHR_Config__phr_ProhibitTimer_sf0; - secondaryCellGroup->mac_CellGroupConfig->phr_Config->choice.setup->phr_Tx_PowerFactorChange = NR_PHR_Config__phr_Tx_PowerFactorChange_dB3; - secondaryCellGroup->mac_CellGroupConfig->phr_Config->choice.setup->multiplePHR=false; - secondaryCellGroup->mac_CellGroupConfig->phr_Config->choice.setup->dummy=false; - secondaryCellGroup->mac_CellGroupConfig->phr_Config->choice.setup->phr_Type2OtherCell = false; - secondaryCellGroup->mac_CellGroupConfig->phr_Config->choice.setup->phr_ModeOtherCG = NR_PHR_Config__phr_ModeOtherCG_real; - secondaryCellGroup->mac_CellGroupConfig->skipUplinkTxDynamic=false; - secondaryCellGroup->mac_CellGroupConfig->ext1 = NULL; + ASN_SEQUENCE_ADD(&mac_CellGroupConfig->tag_Config->tag_ToAddModList->list,tag); + mac_CellGroupConfig->phr_Config = calloc(1,sizeof(*mac_CellGroupConfig->phr_Config)); + mac_CellGroupConfig->phr_Config->present = NR_SetupRelease_PHR_Config_PR_setup; + mac_CellGroupConfig->phr_Config->choice.setup = calloc(1,sizeof(*mac_CellGroupConfig->phr_Config->choice.setup)); + mac_CellGroupConfig->phr_Config->choice.setup->phr_PeriodicTimer = NR_PHR_Config__phr_PeriodicTimer_sf20; + mac_CellGroupConfig->phr_Config->choice.setup->phr_ProhibitTimer = NR_PHR_Config__phr_ProhibitTimer_sf0; + mac_CellGroupConfig->phr_Config->choice.setup->phr_Tx_PowerFactorChange = NR_PHR_Config__phr_Tx_PowerFactorChange_dB3; + mac_CellGroupConfig->phr_Config->choice.setup->multiplePHR=false; + mac_CellGroupConfig->phr_Config->choice.setup->dummy=false; + mac_CellGroupConfig->phr_Config->choice.setup->phr_Type2OtherCell = false; + mac_CellGroupConfig->phr_Config->choice.setup->phr_ModeOtherCG = NR_PHR_Config__phr_ModeOtherCG_real; + mac_CellGroupConfig->skipUplinkTxDynamic=false; + mac_CellGroupConfig->ext1 = NULL; secondaryCellGroup->physicalCellGroupConfig = calloc(1,sizeof(*secondaryCellGroup->physicalCellGroupConfig)); secondaryCellGroup->physicalCellGroupConfig->harq_ACK_SpatialBundlingPUCCH=NULL; secondaryCellGroup->physicalCellGroupConfig->harq_ACK_SpatialBundlingPUSCH=NULL; @@ -1176,6 +1076,14 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToReleaseList= NULL; secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToReleaseList = NULL; + mac_CellGroupConfig->schedulingRequestConfig = calloc(1, sizeof(*mac_CellGroupConfig->schedulingRequestConfig)); + mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList = CALLOC(1,sizeof(*mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList)); + struct NR_SchedulingRequestToAddMod *schedulingrequestlist = CALLOC(1,sizeof(*schedulingrequestlist)); + schedulingrequestlist->schedulingRequestId = 0; + schedulingrequestlist->sr_ProhibitTimer = NULL; + schedulingrequestlist->sr_TransMax = NR_SchedulingRequestToAddMod__sr_TransMax_n64; + ASN_SEQUENCE_ADD(&(mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList->list),schedulingrequestlist); + secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig = calloc(1,sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig)); NR_PUSCH_ServingCellConfig_t *pusch_scc = calloc(1,sizeof(*pusch_scc)); secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->present = NR_SetupRelease_PUSCH_ServingCellConfig_PR_setup; From 7018b7c84110f953a12fb7061ce19ff7237031a5 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 19 May 2022 13:38:22 +0100 Subject: [PATCH 106/267] Fixes after merge --- openair2/LAYER2/NR_MAC_COMMON/nr_mac.h | 3 +++ openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h index 71e4f53279..58e435f3f1 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h @@ -541,6 +541,9 @@ typedef struct nr_csi_report { uint8_t nb_of_csi_ssb_report; L1_RSRP_bitlen_t CSI_report_bitlen; CSI_Meas_bitlen_t csi_meas_bitlen; + int codebook_mode; + int N1; + int N2; } nr_csi_report_t; #endif /*__LAYER2_MAC_H__ */ diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index 67e4557975..b4e52ef96c 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -4543,6 +4543,8 @@ void compute_pmi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, if(codebookConfig->codebookType.choice.type1->subType.present == NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel) { if(codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_two) { + csi_report->N1 = 1; + csi_report->N2 = 1; if (i==0) csi_report->csi_meas_bitlen.pmi_x2_bitlen[i]=2; if (i==1) @@ -4552,6 +4554,9 @@ void compute_pmi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, int n1,n2,o1,o2,x1,x2; get_n1n2_o1o2_singlepanel(&n1,&n2,&o1,&o2,codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->nrOfAntennaPorts.choice.moreThanTwo); get_x1x2_bitlen_singlepanel(n1,n2,o1,o2,&x1,&x2,i+1,codebookConfig->codebookType.choice.type1->codebookMode); + csi_report->N1 = n1; + csi_report->N2 = n2; + csi_report->codebook_mode = codebookConfig->codebookType.choice.type1->codebookMode; csi_report->csi_meas_bitlen.pmi_x1_bitlen[i]=x1; csi_report->csi_meas_bitlen.pmi_x2_bitlen[i]=x2; } From 9150dc8c50c7433cdf2f9aabe63c1181c0a6176d Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 19 May 2022 14:48:45 +0200 Subject: [PATCH 107/267] applying review comment --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index d9e4658be2..8444544ede 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1810,7 +1810,7 @@ void fill_initial_SpCellConfig(int uid, csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB = calloc(1,sizeof(*csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB)); csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList = calloc(1,sizeof(*csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList)); NR_CSI_SSB_ResourceSetId_t *ssbres00 = calloc(1,sizeof(*ssbres00)); - *ssbres00 = 0; + *ssbres00 = 0; ASN_SEQUENCE_ADD(&csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list,ssbres00); csires1->bwp_Id = 0; csires1->resourceType = NR_CSI_ResourceConfig__resourceType_periodic; @@ -1830,8 +1830,8 @@ void fill_initial_SpCellConfig(int uid, } NR_PUCCH_CSI_Resource_t *pucchcsires1 = calloc(1,sizeof(*pucchcsires1)); - pucchcsires1->uplinkBandwidthPartId=0; - pucchcsires1->pucch_Resource=1; + pucchcsires1->uplinkBandwidthPartId = 0; + pucchcsires1->pucch_Resource = *pucch_Config->resourceSetToAddModList->list.array[1]->resourceList.list.array[0]; csi_MeasConfig->csi_ReportConfigToAddModList = calloc(1,sizeof(*csi_MeasConfig->csi_ReportConfigToAddModList)); csi_MeasConfig->csi_ReportConfigToReleaseList = NULL; if (pdsch_AntennaPorts > 1) { From fcfc7a90e87e476ded76f8211192bdd13622e0a3 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 20 May 2022 13:56:12 +0200 Subject: [PATCH 108/267] fix for asan assertion --- openair1/PHY/INIT/nr_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index c7638bab0f..c68d782939 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -544,8 +544,8 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, gNB->nr_gold_pdsch_dmrs = (uint32_t ****)malloc16(fp->slots_per_frame*sizeof(uint32_t ***)); uint32_t ****pdsch_dmrs = gNB->nr_gold_pdsch_dmrs; - // ceil(((NB_RB*6(k)*2(QPSK)/32) // 3 RE *2(QPSK) - int pdsch_dmrs_init_length = ((fp->N_RB_DL*12)>>5)+1; + // ceil(((NB_RB*12(k)*2(QPSK)/32) // 3 RE *2(QPSK) + int pdsch_dmrs_init_length = ((fp->N_RB_DL*24)>>5)+1; for (int slot=0; slotslots_per_frame; slot++) { pdsch_dmrs[slot] = (uint32_t ***)malloc16(fp->symbols_per_slot*sizeof(uint32_t **)); AssertFatal(pdsch_dmrs[slot]!=NULL, "NR init: pdsch_dmrs for slot %d - malloc failed\n", slot); From a724c1febcc222641fb5e73b6d5fc823aa2bdadb Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 20 May 2022 15:09:25 +0200 Subject: [PATCH 109/267] starting timer for msg4 at transmission --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 18 ++++-------------- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 2 +- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 9ac9f0d880..15800326d6 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1961,6 +1961,10 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra harq->round = 0; harq->ndi ^= 1; } else { + const NR_ServingCellConfig_t *servingCellConfig = ra->CellGroup ? ra->CellGroup->spCellConfig->spCellConfigDedicated : NULL; + uint32_t delay_ms = servingCellConfig && servingCellConfig->downlinkBWP_ToAddModList ? NR_RRC_SETUP_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_SETUP_DELAY_MS; + sched_ctrl->rrc_processing_timer = (delay_ms << genericParameters->subcarrierSpacing); + LOG_I(NR_MAC, "(%d.%d) Activating RRC processing timer for UE %d with %d ms\n", frameP, slotP, UE_id, delay_ms); ra->state = WAIT_Msg4_ACK; LOG_D(NR_MAC,"[gNB %d][RAPROC] Frame %d, Subframe %d: RA state %d\n", module_idP, frameP, slotP, ra->state); } @@ -1985,20 +1989,6 @@ void nr_check_Msg4_Ack(module_id_t module_id, int CC_id, frame_t frame, sub_fram LOG_I(NR_MAC, "(ue %i, rnti 0x%04x) Received Ack of RA-Msg4. CBRA procedure succeeded!\n", UE_id, ra->rnti); UE_info->active[UE_id] = true; UE_info->Msg4_ACKed[UE_id] = true; - - // Pause scheduling according to: - // 3GPP TS 38.331 Section 12 Table 12.1-1: UE performance requirements for RRC procedures for UEs - const NR_COMMON_channels_t *common_channels = &RC.nrmac[module_id]->common_channels[0]; - const NR_SIB1_t *sib1 = common_channels->sib1 ? common_channels->sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - const NR_ServingCellConfig_t *servingCellConfig = UE_info->CellGroup[UE_id] ? UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated : NULL; - NR_BWP_t *genericParameters = get_dl_bwp_genericParameters(sched_ctrl->active_bwp, - common_channels->ServingCellConfigCommon, - sib1); - uint32_t delay_ms = servingCellConfig && servingCellConfig->downlinkBWP_ToAddModList ? - NR_RRC_SETUP_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_SETUP_DELAY_MS; - - sched_ctrl->rrc_processing_timer = (delay_ms << genericParameters->subcarrierSpacing); - LOG_I(NR_MAC, "(%d.%d) Activating RRC processing timer for UE %d with %d ms\n", frame, slot, UE_id, delay_ms); } else { LOG_I(NR_MAC, "(ue %i, rnti 0x%04x) RA Procedure failed at Msg4!\n", UE_id, ra->rnti); } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index a29aa8018c..5439a66170 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -1909,7 +1909,7 @@ void nr_sr_reporting(int Mod_idP, frame_t SFN, sub_frame_t slot) for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; - if (sched_ctrl->ul_failure==1) continue; + if (sched_ctrl->ul_failure==1 || sched_ctrl->rrc_processing_timer>0) continue; NR_PUCCH_Config_t *pucch_Config = NULL; if (sched_ctrl->active_ubwp) { pucch_Config = sched_ctrl->active_ubwp->bwp_Dedicated->pucch_Config->choice.setup; From 4eac17e1c8f720b9cdb29062d9dc1eeacc1197c4 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Fri, 20 May 2022 20:51:22 +0100 Subject: [PATCH 110/267] Fix in RI computation --- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 33 +++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 25c0d06008..12068210cb 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -340,7 +340,7 @@ int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, uint8_t *rank_indicator) { NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; - int16_t cond_dB_threshold = 0; + int16_t cond_dB_threshold = 5; int count = 0; *rank_indicator = 0; @@ -357,6 +357,8 @@ int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, * | conjch01 conjch11 | | ch10 ch11 | | conjch01*ch00+conjch11*ch10 conjch01*ch01+conjch11*ch11 | */ + uint8_t sum_shift = 1; // log2(2x2) = 2, which is a shift of 1 bit + for(uint16_t port_tx_conjch = 0; port_tx_conjch < nr_csi_rs_info->N_ports; port_tx_conjch++) { for(uint16_t port_tx_ch = 0; port_tx_ch < nr_csi_rs_info->N_ports; port_tx_ch++) { memset(nr_csi_rs_info->csi_rs_estimated_A_MF[port_tx_conjch][port_tx_ch],0,NR_MAX_OFDM_SYMBOL_SIZE*sizeof(int32_t)); @@ -413,11 +415,33 @@ int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, &nr_csi_rs_info->csi_rs_estimated_numer_fin[k], 1); +#ifdef NR_CSIRS_DEBUG + for(uint16_t port_tx_conjch = 0; port_tx_conjch < nr_csi_rs_info->N_ports; port_tx_conjch++) { + for(uint16_t port_tx_ch = 0; port_tx_ch < nr_csi_rs_info->N_ports; port_tx_ch++) { + int16_t *csi_rs_estimated_A_MF = (int16_t *) &nr_csi_rs_info->csi_rs_estimated_A_MF[port_tx_conjch][port_tx_ch][k]; + LOG_I(NR_PHY, "(%i) csi_rs_estimated_A_MF[%i][%i] = (%i, %i)\n", + k, port_tx_conjch, port_tx_ch, csi_rs_estimated_A_MF[0], csi_rs_estimated_A_MF[1]); + int16_t *csi_rs_estimated_A_MF_sq = (int16_t *) &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[port_tx_conjch][port_tx_ch][k]; + LOG_I(NR_PHY, "(%i) csi_rs_estimated_A_MF_sq[%i][%i] = (%i, %i)\n", + k, port_tx_conjch, port_tx_ch, csi_rs_estimated_A_MF_sq[0], csi_rs_estimated_A_MF_sq[1]); + } + } + LOG_I(NR_PHY, "(%i) csi_rs_estimated_determ_fin = %i\n", k, nr_csi_rs_info->csi_rs_estimated_determ_fin[k]); + LOG_I(NR_PHY, "(%i) csi_rs_estimated_numer_fin = %i\n", k, nr_csi_rs_info->csi_rs_estimated_numer_fin[k]>>sum_shift); +#endif + // compute the conditional number for (int sc_idx=0; sc_idx < NR_NB_SC_PER_RB; sc_idx++) { int8_t csi_rs_estimated_denum_db = dB_fixed(nr_csi_rs_info->csi_rs_estimated_determ_fin[k + sc_idx]); - int8_t csi_rs_estimated_numer_db = dB_fixed(nr_csi_rs_info->csi_rs_estimated_numer_fin[k + sc_idx]); + int8_t csi_rs_estimated_numer_db = dB_fixed(nr_csi_rs_info->csi_rs_estimated_numer_fin[k + sc_idx]>>sum_shift); int8_t cond_db = csi_rs_estimated_numer_db - csi_rs_estimated_denum_db; + +#ifdef NR_CSIRS_DEBUG + LOG_I(NR_PHY, "csi_rs_estimated_denum_db = %i\n", csi_rs_estimated_denum_db); + LOG_I(NR_PHY, "csi_rs_estimated_numer_db = %i\n", csi_rs_estimated_numer_db); + LOG_I(NR_PHY, "cond_db = %i\n", cond_db); +#endif + if (cond_db < cond_dB_threshold) { count++; } else { @@ -431,6 +455,11 @@ int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, *rank_indicator = 1; } +#ifdef NR_CSIRS_DEBUG + LOG_I(NR_PHY, "count = %i\n", count); + LOG_I(NR_PHY, "rank = %i\n", (*rank_indicator)+1); +#endif + return 0; } From c67d3659f148052038d3001b9612edddb9878373 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Fri, 20 May 2022 21:12:06 +0100 Subject: [PATCH 111/267] Fix precoded_sinr_dB computation for rank = 2 --- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 12068210cb..5a05e256e2 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -553,7 +553,7 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, *precoded_sinr_dB = dB_fixed(tested_precoded_sinr[i2[0]]); } else { i2[0] = tested_precoded_sinr[0]+tested_precoded_sinr[2] > tested_precoded_sinr[1]+tested_precoded_sinr[3] ? 0 : 1; - *precoded_sinr_dB = dB_fixed((tested_precoded_sinr[i2[0]] + tested_precoded_sinr[i2[0]+2]))>>1; + *precoded_sinr_dB = dB_fixed((tested_precoded_sinr[i2[0]] + tested_precoded_sinr[i2[0]+2])>>1); } } else { From 23dab34e7c7a77db1458aa03d4ddb9b9d8f0ea43 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Sat, 21 May 2022 01:15:26 +0100 Subject: [PATCH 112/267] Fix CSI bitlen for rank = 2 --- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 32 ++++++++++++++++ openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h | 2 + openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 6 +-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 38 +------------------ 4 files changed, 38 insertions(+), 40 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index b4e52ef96c..7d27528a35 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -4698,4 +4698,36 @@ void compute_csi_bitlen(NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report_t *cs AssertFatal(1==0,"Not yet supported CSI report quantity type"); } } +} + +uint16_t nr_get_csi_bitlen(nr_csi_report_t *csi_report_template, uint8_t csi_report_id) { + + uint16_t csi_bitlen = 0; + uint16_t max_bitlen = 0; + L1_RSRP_bitlen_t *CSI_report_bitlen = NULL; + CSI_Meas_bitlen_t *csi_meas_bitlen = NULL; + + if (csi_report_template[csi_report_id].reportQuantity_type == NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP || + csi_report_template[csi_report_id].reportQuantity_type == NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP) { + CSI_report_bitlen = &(csi_report_template[csi_report_id].CSI_report_bitlen); // This might need to be moodif for Aperiodic CSI-RS measurements + csi_bitlen += ((CSI_report_bitlen->cri_ssbri_bitlen * CSI_report_bitlen->nb_ssbri_cri) + + CSI_report_bitlen->rsrp_bitlen +(CSI_report_bitlen->diff_rsrp_bitlen * + (CSI_report_bitlen->nb_ssbri_cri -1 ))); + } else { + csi_meas_bitlen = &(csi_report_template[csi_report_id].csi_meas_bitlen); //This might need to be moodif for Aperiodic CSI-RS measurements + uint16_t temp_bitlen; + for (int i=0; i<8; i++) { + temp_bitlen = (csi_meas_bitlen->cri_bitlen+ + csi_meas_bitlen->ri_bitlen+ + csi_meas_bitlen->li_bitlen[i]+ + csi_meas_bitlen->cqi_bitlen[i]+ + csi_meas_bitlen->pmi_x1_bitlen[i]+ + csi_meas_bitlen->pmi_x2_bitlen[i]); + if(temp_bitlen>max_bitlen) + max_bitlen = temp_bitlen; + } + csi_bitlen += max_bitlen; + } + + return csi_bitlen; } \ No newline at end of file diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index 982e683e0c..f626328ad8 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -245,4 +245,6 @@ void compute_cqi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, void compute_csi_bitlen(NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report_t *csi_report_template); +uint16_t nr_get_csi_bitlen(nr_csi_report_t *csi_report_template, uint8_t csi_report_id); + #endif diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index e7d188bd0a..1e73df7d76 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2650,17 +2650,17 @@ uint8_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, nr_csi_report_t *csi_report = &mac->csi_report_template[csi_reportconfig->reportConfigId]; compute_csi_bitlen(csi_MeasConfig, mac->csi_report_template); + n_bits = nr_get_csi_bitlen(mac->csi_report_template, csi_reportconfig->reportConfigId); int cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; int ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; int pmi_x1_bitlen = csi_report->csi_meas_bitlen.pmi_x1_bitlen[*mac->csirs_measurements.rank_indicator]; int pmi_x2_bitlen = csi_report->csi_meas_bitlen.pmi_x2_bitlen[*mac->csirs_measurements.rank_indicator]; int cqi_bitlen = csi_report->csi_meas_bitlen.cqi_bitlen[*mac->csirs_measurements.rank_indicator]; - - n_bits = cri_bitlen + ri_bitlen + pmi_x1_bitlen + pmi_x2_bitlen + cqi_bitlen; + int padding_bitlen = n_bits - (cri_bitlen + ri_bitlen + pmi_x1_bitlen + pmi_x2_bitlen + cqi_bitlen); // TODO: Improvements will be needed to cri_bitlen>0 and pmi_x1_bitlen>0 - temp_payload = (*mac->csirs_measurements.rank_indicator<<(cri_bitlen+cqi_bitlen+pmi_x2_bitlen+pmi_x1_bitlen)) | + temp_payload = (*mac->csirs_measurements.rank_indicator<<(cri_bitlen+cqi_bitlen+pmi_x2_bitlen+padding_bitlen+pmi_x1_bitlen)) | (*mac->csirs_measurements.i1<<(cri_bitlen+cqi_bitlen+pmi_x2_bitlen)) | (*mac->csirs_measurements.i2<<(cri_bitlen+cqi_bitlen)) | (*mac->csirs_measurements.cqi<UE_info; - L1_RSRP_bitlen_t * CSI_report_bitlen = NULL; - CSI_Meas_bitlen_t * csi_meas_bitlen = NULL; - - if (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP==UE_info->csi_report_template[UE_id][csi_report_id].reportQuantity_type|| - NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP==UE_info->csi_report_template[UE_id][csi_report_id].reportQuantity_type){ - CSI_report_bitlen = &(UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen); //This might need to be moodif for Aperiodic CSI-RS measurements - csi_bitlen+= ((CSI_report_bitlen->cri_ssbri_bitlen * CSI_report_bitlen->nb_ssbri_cri) + - CSI_report_bitlen->rsrp_bitlen +(CSI_report_bitlen->diff_rsrp_bitlen * - (CSI_report_bitlen->nb_ssbri_cri -1 ))); - } else{ - csi_meas_bitlen = &(UE_info->csi_report_template[UE_id][csi_report_id].csi_meas_bitlen); //This might need to be moodif for Aperiodic CSI-RS measurements - uint16_t temp_bitlen; - for (int i=0; i<8; i++) { - temp_bitlen = (csi_meas_bitlen->cri_bitlen+ - csi_meas_bitlen->ri_bitlen+ - csi_meas_bitlen->li_bitlen[i]+ - csi_meas_bitlen->cqi_bitlen[i]+ - csi_meas_bitlen->pmi_x1_bitlen[i]+ - csi_meas_bitlen->pmi_x2_bitlen[i]); - if(temp_bitlen>max_bitlen) - max_bitlen = temp_bitlen; - } - csi_bitlen += max_bitlen; - } - - return csi_bitlen; -} - - void nr_csi_meas_reporting(int Mod_idP, frame_t frame, sub_frame_t slot) { @@ -275,7 +239,7 @@ void nr_csi_meas_reporting(int Mod_idP, curr_pucch->ul_slot = sched_slot; curr_pucch->resource_indicator = res_index; curr_pucch->csi_bits += - nr_get_csi_bitlen(Mod_idP,UE_id,csi_report_id); + nr_get_csi_bitlen(UE_info->csi_report_template[UE_id], csi_report_id); const NR_SIB1_t *sib1 = RC.nrmac[Mod_idP]->common_channels[0].sib1 ? RC.nrmac[Mod_idP]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, From 8bc5f273bda7819c037993aacb1ec18cb3cb1952 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Sat, 21 May 2022 01:24:02 +0100 Subject: [PATCH 113/267] Improve log --- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 1e73df7d76..9d3804f309 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2542,7 +2542,7 @@ uint8_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac, case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI: case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI: case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI: - LOG_E(NR_MAC,"Measurement report based on CSI-RS not available\n"); + LOG_E(NR_MAC,"Measurement report %d based on CSI-RS is not available\n", csi_reportconfig->reportQuantity.present); break; default: AssertFatal(1==0,"Invalid CSI report quantity type %d\n",csi_reportconfig->reportQuantity.present); From 9e2086c77c4ce562fcd22fcd4c379927ac9a0c46 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 18 May 2022 12:51:18 +0100 Subject: [PATCH 114/267] Fix warning after merge --- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 1e019a4744..906a5d2d6c 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -840,12 +840,13 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, mappingtype, add_pos, dmrslength, pusch_config_pdu->start_symbol_index, mac->scc ? mac->scc->dmrs_TypeA_Position : mac->mib->dmrs_TypeA_Position); - if ((mac->ULbwp[ul_bwp_id-1] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled)) + if ((mac->ULbwp[ul_bwp_id-1] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled)) { if (*dci_format != NR_UL_DCI_FORMAT_0_1) { pusch_config_pdu->num_dmrs_cdm_grps_no_data = 1; } - else if (*dci_format == NR_UL_DCI_FORMAT_0_0 || (mac->ULbwp[ul_bwp_id-1] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled)) + } else if (*dci_format == NR_UL_DCI_FORMAT_0_0 || (mac->ULbwp[ul_bwp_id-1] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled)) { pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; + } // Num PRB Overhead from PUSCH-ServingCellConfig if (mac->cg && From 0eeb174253f93847e5990adf2ea210345ec28eed Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Mon, 23 May 2022 11:43:32 +0100 Subject: [PATCH 115/267] Add wideband SNR based on SRS in MAC stats --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 15 +++++++++++++-- openair2/LAYER2/NR_MAC_gNB/main.c | 5 +++-- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 1 + 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 7c61eb3b5a..38e6ca0d6f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -907,8 +907,19 @@ void handle_nr_srs_measurements(const module_id_t module_id, } #endif - int ul_prbblack_SNR_threshold = RC.nrmac[module_id]->ul_prbblack_SNR_threshold; - uint16_t *ulprbbl = RC.nrmac[module_id]->ulprbbl; + const int UE_id = find_nr_UE_id(module_id,rnti); + if (UE_id < 0) { + LOG_W(NR_MAC, "Could not find UE for RNTI 0x%04x\n", rnti); + return; + } + + gNB_MAC_INST *nr_mac = RC.nrmac[module_id]; + NR_UE_info_t *UE_info = &nr_mac->UE_info; + NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id]; + stats->srs_wide_band_snr = (wide_band_snr>>1)-64; + + int ul_prbblack_SNR_threshold = nr_mac->ul_prbblack_SNR_threshold; + uint16_t *ulprbbl = nr_mac->ulprbbl; memset(ulprbbl, 0, reported_symbol_list[0].num_rbs*sizeof(uint16_t)); for (int rb = 0; rb < reported_symbol_list[0].num_rbs; rb++) { diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index e047494b52..b7bf30f056 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -84,7 +84,7 @@ void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen, bool reset_rsrp const NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id]; const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0; - stroff+=sprintf(output+stroff,"UE ID %d RNTI %04x (%d/%d) PH %d dB PCMAX %d dBm, average RSRP %d (%d meas)\n", + stroff+=sprintf(output+stroff,"UE ID %d RNTI %04x (%d/%d) PH %d dB PCMAX %d dBm, average RSRP %d (%d meas), UL-SNR %d dB\n", UE_id, UE_info->rnti[UE_id], num++, @@ -92,7 +92,8 @@ void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen, bool reset_rsrp sched_ctrl->ph, sched_ctrl->pcmax, avg_rsrp, - stats->num_rsrp_meas); + stats->num_rsrp_meas, + stats->srs_wide_band_snr); stroff+=sprintf(output+stroff,"UE %d: CQI %d, RI %d, PMI (%d,%d)\n", UE_id, UE_info->UE_sched_ctrl[UE_id].CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index b2b6d3d516..4e896c2f49 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -690,6 +690,7 @@ typedef struct { uint32_t pucch0_DTX; int cumul_rsrp; uint8_t num_rsrp_meas; + int8_t srs_wide_band_snr; } NR_mac_stats_t; From 5092eca8cbd6d0d5e877593a37f9f4e99289e3ab Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Mon, 23 May 2022 13:30:38 +0100 Subject: [PATCH 116/267] Some robustness improvements --- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 5 +++ openair1/PHY/NR_TRANSPORT/srs_rx.c | 13 +++++- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 42 +++++++++++-------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c | 3 +- 4 files changed, 43 insertions(+), 20 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index be2d03d0db..70a06d4727 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -1089,6 +1089,11 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, LOG_I(NR_PHY,"signal_power = %u\n", *signal_power); #endif + if (*signal_power == 0) { + LOG_W(NR_PHY, "Received SRS signal power is 0\n"); + return -1; + } + // Compute noise power uint8_t signal_power_bits = log2_approx(*signal_power); diff --git a/openair1/PHY/NR_TRANSPORT/srs_rx.c b/openair1/PHY/NR_TRANSPORT/srs_rx.c index 2d7aefdee0..ffcd7362f3 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -113,6 +113,7 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, uint64_t symbol_offset = (n_symbols+l0)*frame_parms->ofdm_symbol_size; int32_t *rx_signal; + bool no_srs_signal = true; for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) { memset(srs_received_signal[ant], 0, frame_parms->ofdm_symbol_size*sizeof(int32_t)); @@ -121,6 +122,10 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, for(int sc_idx = 0; sc_idx < nr_srs_info->sc_list_length; sc_idx++) { srs_received_signal[ant][nr_srs_info->sc_list[sc_idx]] = rx_signal[nr_srs_info->sc_list[sc_idx]]; + if (rx_signal[nr_srs_info->sc_list[sc_idx]] != 0) { + no_srs_signal = false; + } + #ifdef SRS_DEBUG uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start*12; int subcarrier_log = nr_srs_info->sc_list[sc_idx]-subcarrier_offset; @@ -140,5 +145,11 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, #endif } } - return 0; + + if (no_srs_signal) { + LOG_W(NR_PHY, "No SRS signal\n"); + return -1; + } else { + return 0; + } } \ No newline at end of file diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 84370f2509..a8e5f84d9c 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -636,7 +636,8 @@ void phy_procedures_gNB_common_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) int fill_srs_reported_symbol_list(nfapi_nr_srs_indication_reported_symbol_t* reported_symbol_list, nfapi_nr_srs_pdu_t *srs_pdu, int N_RB_UL, - const int8_t *snr_per_rb) { + const int8_t *snr_per_rb, + int srs_est) { reported_symbol_list->num_rbs = srs_bandwidth_config[srs_pdu->config_index][srs_pdu->bandwidth_index][0]; @@ -645,10 +646,12 @@ int fill_srs_reported_symbol_list(nfapi_nr_srs_indication_reported_symbol_t* rep } for(int rb = 0; rb < reported_symbol_list->num_rbs; rb++) { - if (snr_per_rb[rb] < -64) { + if (srs_est<0) { + reported_symbol_list->rb_list[rb].rb_snr = 0xFF; + } else if (snr_per_rb[rb] < -64) { reported_symbol_list->rb_list[rb].rb_snr = 0; } else if (snr_per_rb[rb] > 63) { - reported_symbol_list->rb_list[rb].rb_snr = 255; + reported_symbol_list->rb_list[rb].rb_snr = 0xFE; } else { reported_symbol_list->rb_list[rb].rb_snr = (snr_per_rb[rb] + 64)<<1; } @@ -858,20 +861,22 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { generate_srs_nr(srs_pdu, &gNB->frame_parms, gNB->nr_srs_info[i]->srs_generated_signal, gNB->nr_srs_info[i], AMP, frame_rx, slot_rx); } - nr_get_srs_signal(gNB,frame_rx,slot_rx,srs_pdu, gNB->nr_srs_info[i], gNB->nr_srs_info[i]->srs_received_signal); + int srs_est = nr_get_srs_signal(gNB,frame_rx,slot_rx,srs_pdu, gNB->nr_srs_info[i], gNB->nr_srs_info[i]->srs_received_signal); - nr_srs_channel_estimation(gNB,frame_rx,slot_rx,srs_pdu, - gNB->nr_srs_info[i], - gNB->nr_srs_info[i]->srs_generated_signal, - gNB->nr_srs_info[i]->srs_received_signal, - gNB->nr_srs_info[i]->srs_estimated_channel_freq, - gNB->nr_srs_info[i]->srs_estimated_channel_time, - gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted, - gNB->nr_srs_info[i]->signal_power, - gNB->nr_srs_info[i]->noise_power_per_rb, - gNB->nr_srs_info[i]->noise_power, - gNB->nr_srs_info[i]->snr_per_rb, - gNB->nr_srs_info[i]->snr); + if (srs_est >= 0) { + nr_srs_channel_estimation(gNB,frame_rx,slot_rx,srs_pdu, + gNB->nr_srs_info[i], + gNB->nr_srs_info[i]->srs_generated_signal, + gNB->nr_srs_info[i]->srs_received_signal, + gNB->nr_srs_info[i]->srs_estimated_channel_freq, + gNB->nr_srs_info[i]->srs_estimated_channel_time, + gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted, + gNB->nr_srs_info[i]->signal_power, + gNB->nr_srs_info[i]->noise_power_per_rb, + gNB->nr_srs_info[i]->noise_power, + gNB->nr_srs_info[i]->snr_per_rb, + gNB->nr_srs_info[i]->snr); + } T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), T_BUFFER(gNB->nr_srs_info[i]->srs_estimated_channel_freq[0], gNB->frame_parms.ofdm_symbol_size*sizeof(int32_t))); @@ -887,7 +892,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->srs_pdu_list[num_srs].rnti = srs_pdu->rnti; gNB->srs_pdu_list[num_srs].timing_advance = nr_est_timing_advance_srs(&gNB->frame_parms, gNB->nr_srs_info[i]->srs_estimated_channel_time); gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; - gNB->srs_pdu_list[num_srs].wide_band_snr = (*gNB->nr_srs_info[i]->snr + 64)<<1; + gNB->srs_pdu_list[num_srs].wide_band_snr = srs_est >= 0 ? (*gNB->nr_srs_info[i]->snr + 64)<<1 : 0xFF; // 0xFF will be set if this field is invalid gNB->srs_pdu_list[num_srs].num_reported_symbols = 1<num_symbols; if(!gNB->srs_pdu_list[num_srs].reported_symbol_list) { gNB->srs_pdu_list[num_srs].reported_symbol_list = (nfapi_nr_srs_indication_reported_symbol_t*) calloc(1, gNB->srs_pdu_list[num_srs].num_reported_symbols*sizeof(nfapi_nr_srs_indication_reported_symbol_t)); @@ -895,7 +900,8 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { fill_srs_reported_symbol_list(&gNB->srs_pdu_list[num_srs].reported_symbol_list[0], srs_pdu, gNB->frame_parms.N_RB_UL, - gNB->nr_srs_info[i]->snr_per_rb); + gNB->nr_srs_info[i]->snr_per_rb, + srs_est); gNB->UL_INFO.srs_ind.number_of_pdus += 1; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index 8680cc25d1..35b2c4b167 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -125,7 +125,8 @@ void nr_schedule_srs(int module_id, frame_t frame) { sched_ctrl->sched_srs.slot = -1; sched_ctrl->sched_srs.srs_scheduled = false; - if(!UE_info->Msg4_ACKed[UE_id] || sched_ctrl->rrc_processing_timer > 0) { + if((sched_ctrl->ul_failure == 1 && get_softmodem_params()->phy_test==0) || + !UE_info->Msg4_ACKed[UE_id] || sched_ctrl->rrc_processing_timer > 0) { continue; } From af95f834f1f03d7cef7fa9690344431d79513e10 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 25 May 2022 10:36:30 +0100 Subject: [PATCH 117/267] Fix scheduling SRS reception at gNB when there is Dedicated BWPs --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index 35b2c4b167..18b723ccc0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -41,15 +41,16 @@ void nr_configure_srs(nfapi_nr_srs_pdu_t *srs_pdu, int module_id, int CC_id, int NR_UE_info_t *UE_info = &nrmac->UE_info; NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; - NR_BWP_t ubwp = sched_ctrl->active_ubwp ? - sched_ctrl->active_ubwp->bwp_Common->genericParameters : - scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; + const NR_SIB1_t *sib1 = nrmac->common_channels[0].sib1 ? nrmac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; + NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, + scc, + sib1); srs_pdu->rnti = UE_info->rnti[UE_id]; srs_pdu->handle = 0; - srs_pdu->bwp_size = NRRIV2BW(ubwp.locationAndBandwidth, MAX_BWP_SIZE);; - srs_pdu->bwp_start = NRRIV2PRBOFFSET(ubwp.locationAndBandwidth, MAX_BWP_SIZE);; - srs_pdu->subcarrier_spacing = ubwp.subcarrierSpacing; + srs_pdu->bwp_size = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE);; + srs_pdu->bwp_start = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE);; + srs_pdu->subcarrier_spacing = genericParameters->subcarrierSpacing; srs_pdu->cyclic_prefix = 0; srs_pdu->num_ant_ports = srs_resource->nrofSRS_Ports; srs_pdu->num_symbols = srs_resource->resourceMapping.nrofSymbols; @@ -131,13 +132,20 @@ void nr_schedule_srs(int module_id, frame_t frame) { } NR_SRS_Config_t *srs_config = NULL; - if (cg && - cg->spCellConfig && - cg->spCellConfig->spCellConfigDedicated && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { + if (sched_ctrl->active_ubwp) { + if (sched_ctrl->active_ubwp->bwp_Dedicated && + sched_ctrl->active_ubwp->bwp_Dedicated->srs_Config) { + srs_config = sched_ctrl->active_ubwp->bwp_Dedicated->srs_Config->choice.setup; + } + } else if (cg && + cg->spCellConfig && + cg->spCellConfig->spCellConfigDedicated && + cg->spCellConfig->spCellConfigDedicated->uplinkConfig && + cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { srs_config = cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->srs_Config->choice.setup; - } else { + } + + if (!srs_config) { continue; } @@ -167,14 +175,15 @@ void nr_schedule_srs(int module_id, frame_t frame) { continue; } - NR_BWP_t ubwp = sched_ctrl->active_ubwp ? - sched_ctrl->active_ubwp->bwp_Common->genericParameters : - scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; + const NR_SIB1_t *sib1 = nrmac->common_channels[0].sib1 ? nrmac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; + NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, + scc, + sib1); uint16_t period = srs_period[srs_resource->resourceType.choice.periodic->periodicityAndOffset_p.present]; uint16_t offset = get_nr_srs_offset(srs_resource->resourceType.choice.periodic->periodicityAndOffset_p); - int n_slots_frame = nr_slots_per_frame[ubwp.subcarrierSpacing]; + int n_slots_frame = nr_slots_per_frame[genericParameters->subcarrierSpacing]; // Check if UE will transmit the SRS in this frame if ( ((frame - offset/n_slots_frame)*n_slots_frame)%period == 0) { From 8d02c2c0fcecc100002e5d627ec71956248112be Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 25 May 2022 11:06:55 +0100 Subject: [PATCH 118/267] Fix scheduling SRS transmission at UE when there is Dedicated BWPs --- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 906a5d2d6c..b394d18cb8 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -929,15 +929,23 @@ bool nr_ue_periodic_srs_scheduling(module_id_t mod_id, frame_t frame, slot_t slo bool srs_scheduled = false; NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id); + NR_BWP_Id_t ul_bwp_id = mac->UL_BWP_Id; NR_SRS_Config_t *srs_config = NULL; - if (mac->cg && - mac->cg->spCellConfig && - mac->cg->spCellConfig->spCellConfigDedicated && - mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig && - mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { + if (ul_bwp_id > 0 && mac->ULbwp[ul_bwp_id-1]) { + if (mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated && + mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->srs_Config) { + srs_config = mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->srs_Config->choice.setup; + } + } else if (mac->cg && + mac->cg->spCellConfig && + mac->cg->spCellConfig->spCellConfigDedicated && + mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig && + mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { srs_config = mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->srs_Config->choice.setup; - } else { + } + + if (!srs_config) { return false; } @@ -965,7 +973,6 @@ bool nr_ue_periodic_srs_scheduling(module_id_t mod_id, frame_t frame, slot_t slo continue; } - NR_BWP_Id_t ul_bwp_id = mac->UL_BWP_Id; NR_BWP_t ubwp = ul_bwp_id > 0 && mac->ULbwp[ul_bwp_id-1] ? mac->ULbwp[ul_bwp_id-1]->bwp_Common->genericParameters : mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.genericParameters; From 264eebfb3f4d25cbdb10a7201d2b32fff574172d Mon Sep 17 00:00:00 2001 From: rmagueta Date: Fri, 27 May 2022 11:54:53 +0100 Subject: [PATCH 119/267] Fix build after merge --- openair2/GNB_APP/MACRLC_nr_paramdef.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index 1f57087194..22b83f4064 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -130,18 +130,18 @@ #define MACRLC_ULSCH_MAX_FRAME_INACTIVITY 17 #define MACRLC_PUSCHTARGETSNRX10_IDX 18 #define MACRLC_PUCCHTARGETSNRX10_IDX 19 -#define MACRLC_UL_PRBBLACK_SNR_THRESHOLD_IDX -#define MACRLC_PUCCHFAILURETHRES_IDX 20 -#define MACRLC_PUSCHFAILURETHRES_IDX 21 -#define MACRLC_DL_BLER_TARGET_UPPER_IDX 22 -#define MACRLC_DL_BLER_TARGET_LOWER_IDX 23 -#define MACRLC_DL_MAX_MCS_IDX 24 -#define MACRLC_UL_BLER_TARGET_UPPER_IDX 25 -#define MACRLC_UL_BLER_TARGET_LOWER_IDX 26 -#define MACRLC_UL_MAX_MCS_IDX 27 -#define MACRLC_HARQ_ROUND_MAX_IDX 28 -#define MACRLC_MIN_GRANT_PRB_IDX 29 -#define MACRLC_MIN_GRANT_MCS_IDX 30 +#define MACRLC_UL_PRBBLACK_SNR_THRESHOLD_IDX 20 +#define MACRLC_PUCCHFAILURETHRES_IDX 21 +#define MACRLC_PUSCHFAILURETHRES_IDX 22 +#define MACRLC_DL_BLER_TARGET_UPPER_IDX 23 +#define MACRLC_DL_BLER_TARGET_LOWER_IDX 24 +#define MACRLC_DL_MAX_MCS_IDX 25 +#define MACRLC_UL_BLER_TARGET_UPPER_IDX 26 +#define MACRLC_UL_BLER_TARGET_LOWER_IDX 27 +#define MACRLC_UL_MAX_MCS_IDX 28 +#define MACRLC_HARQ_ROUND_MAX_IDX 29 +#define MACRLC_MIN_GRANT_PRB_IDX 30 +#define MACRLC_MIN_GRANT_MCS_IDX 31 /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ #endif From 91189bd4f83ef736c17c99538324e4e80113154a Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 1 Jun 2022 14:30:45 +0100 Subject: [PATCH 120/267] Fixes after merge --- openair2/LAYER2/NR_MAC_gNB/config.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 19845c708b..7dda0ab5eb 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -694,7 +694,7 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, CellGroup->spCellConfig->spCellConfigDedicated && CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig && CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup) { - compute_csi_bitlen(CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup, UE); + compute_csi_bitlen(CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup, UE->csi_report_template); } } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index cdd754cc03..4ce4180fa5 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2418,7 +2418,7 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf CellGroup->spCellConfig->spCellConfigDedicated && CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig && CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup) { - compute_csi_bitlen(CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup, UE); + compute_csi_bitlen(CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup, UE->csi_report_template); } NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index ef9f1b9c63..76c49b8257 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -235,7 +235,7 @@ void nr_csi_meas_reporting(int Mod_idP, curr_pucch->frame = frame; curr_pucch->ul_slot = sched_slot; curr_pucch->resource_indicator = res_index; - curr_pucch->csi_bits += nr_get_csi_bitlen(UE,csi_report_id); + curr_pucch->csi_bits += nr_get_csi_bitlen(UE->csi_report_template, csi_report_id); const NR_SIB1_t *sib1 = RC.nrmac[Mod_idP]->common_channels[0].sib1 ? RC.nrmac[Mod_idP]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, From b96df49e15c311e78fcc78a762853668f0acfed0 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 1 Jun 2022 17:09:08 +0200 Subject: [PATCH 121/267] postpone initialization of UL_tti_req_ahead to when sl_ahead is available --- openair1/PHY/INIT/nr_init_ru.c | 2 +- openair2/LAYER2/NR_MAC_gNB/config.c | 15 +-------------- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 3 +++ .../LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 16 ++++++++++++++++ openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 2 ++ openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 1 + 6 files changed, 24 insertions(+), 15 deletions(-) diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index 0e7c29800a..6aa42b1b10 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -60,7 +60,7 @@ int nr_phy_init_RU(RU_t *ru) { for (i=0; inb_tx; i++) { // Allocate 10 subframes of I/Q TX signal data (time) if not - ru->common.txdata[i] = (int32_t*)malloc16_clear( ru->sf_extension + (fp->samples_per_frame*sizeof(int32_t) )); + ru->common.txdata[i] = (int32_t*)malloc16_clear((ru->sf_extension + fp->samples_per_frame)*sizeof(int32_t)); LOG_I(PHY,"[INIT] common.txdata[%d] = %p (%lu bytes,sf_extension %d)\n",i,ru->common.txdata[i], (ru->sf_extension + fp->samples_per_frame)*sizeof(int32_t),ru->sf_extension); ru->common.txdata[i] = &ru->common.txdata[i][ru->sf_extension]; diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 0e55b519ab..9273a24aa0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -462,8 +462,7 @@ int nr_mac_enable_ue_rrc_processing_timer(module_id_t Mod_idP, rnti_t rnti, NR_S return -1; } NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl; - const uint16_t sf_ahead = 6/(0x01<0); - const uint16_t sl_ahead = sf_ahead * (0x01<if_inst->sl_ahead; sched_ctrl->rrc_processing_timer = (rrc_reconfiguration_delay<rnti, rrc_reconfiguration_delay); @@ -486,19 +485,7 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, if (scc != NULL ) { AssertFatal((scc->ssb_PositionsInBurst->present > 0) && (scc->ssb_PositionsInBurst->present < 4), "SSB Bitmap type %d is not valid\n",scc->ssb_PositionsInBurst->present); - /* dimension UL_tti_req_ahead for number of slots in frame */ const int n = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; - RC.nrmac[Mod_idP]->UL_tti_req_ahead[0] = calloc(n, sizeof(nfapi_nr_ul_tti_request_t)); - AssertFatal(RC.nrmac[Mod_idP]->UL_tti_req_ahead[0], - "could not allocate memory for RC.nrmac[]->UL_tti_req_ahead[]\n"); - /* fill in slot/frame numbers: slot is fixed, frame will be updated by scheduler - * consider that scheduler runs sl_ahead: the first sl_ahead slots are - * already "in the past" and thus we put frame 1 instead of 0! */ - for (int i = 0; i < n; ++i) { - nfapi_nr_ul_tti_request_t *req = &RC.nrmac[Mod_idP]->UL_tti_req_ahead[0][i]; - req->SFN = i < (RC.nrmac[Mod_idP]->if_inst->sl_ahead-1); - req->Slot = i; - } RC.nrmac[Mod_idP]->common_channels[0].vrb_map_UL = calloc(n * MAX_BWP_SIZE, sizeof(uint16_t)); AssertFatal(RC.nrmac[Mod_idP]->common_channels[0].vrb_map_UL, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index d7e2c78c35..25a307e804 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -68,6 +68,9 @@ void clear_nr_nfapi_information(gNB_MAC_INST * gNB, NR_ServingCellConfigCommon_t *scc = gNB->common_channels->ServingCellConfigCommon; const int num_slots = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; + if(gNB->init_UL_tti_req_ahead == false) + UL_tti_req_ahead_initialization(gNB, scc, num_slots); + nfapi_nr_dl_tti_request_t *DL_req = &gNB->DL_req[0]; nfapi_nr_dl_tti_pdcch_pdu_rel15_t **pdcch = (nfapi_nr_dl_tti_pdcch_pdu_rel15_t **)gNB->pdcch_pdu_idx[CC_idP]; nfapi_nr_ul_tti_request_t *future_ul_tti_req = diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 65d2ce09c5..eb0397866d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2996,3 +2996,19 @@ void schedule_nr_bwp_switch(module_id_t module_id, } } } + +void UL_tti_req_ahead_initialization(gNB_MAC_INST * gNB, NR_ServingCellConfigCommon_t *scc, int n) { + + gNB->UL_tti_req_ahead[0] = calloc(n, sizeof(nfapi_nr_ul_tti_request_t)); + AssertFatal(gNB->UL_tti_req_ahead[0], + "could not allocate memory for RC.nrmac[]->UL_tti_req_ahead[]\n"); + /* fill in slot/frame numbers: slot is fixed, frame will be updated by scheduler + * consider that scheduler runs sl_ahead: the first sl_ahead slots are + * already "in the past" and thus we put frame 1 instead of 0! */ + for (int i = 0; i < n; ++i) { + nfapi_nr_ul_tti_request_t *req = &gNB->UL_tti_req_ahead[0][i]; + req->SFN = i < (gNB->if_inst->sl_ahead-1); + req->Slot = i; + } + gNB->init_UL_tti_req_ahead = true; +} diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index f3dd5208d6..4fb51cd00b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -532,6 +532,8 @@ int get_mcs_from_bler(const NR_bler_options_t *bler_options, int max_mcs, frame_t frame); +void UL_tti_req_ahead_initialization(gNB_MAC_INST * gNB, NR_ServingCellConfigCommon_t *scc, int n); + void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t frameP, sub_frame_t slotP); void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen, bool reset_rsrp); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 974d6dff4a..63bf7b0595 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -850,6 +850,7 @@ typedef struct gNB_MAC_INST_s { uint8_t harq_round_max; uint8_t min_grant_prb; uint8_t min_grant_mcs; + bool init_UL_tti_req_ahead; } gNB_MAC_INST; #endif /*__LAYER2_NR_MAC_GNB_H__ */ From 616927c04d993820cefc25fb5276c22bf7a19837 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 1 Jun 2022 17:22:59 +0100 Subject: [PATCH 122/267] Fixes after merge --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 5571d27597..ad7db304bf 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -789,15 +789,14 @@ void handle_nr_srs_measurements(const module_id_t module_id, } #endif - const int UE_id = find_nr_UE_id(module_id,rnti); - if (UE_id < 0) { + NR_UE_info_t* UE = find_nr_UE(&RC.nrmac[module_id]->UE_info, rnti); + if (!UE) { LOG_W(NR_MAC, "Could not find UE for RNTI 0x%04x\n", rnti); return; } gNB_MAC_INST *nr_mac = RC.nrmac[module_id]; - NR_UE_info_t *UE_info = &nr_mac->UE_info; - NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id]; + NR_mac_stats_t *stats = &UE->mac_stats; stats->srs_wide_band_snr = (wide_band_snr>>1)-64; int ul_prbblack_SNR_threshold = nr_mac->ul_prbblack_SNR_threshold; From b5583d47de5c63a2759fb2ba4ee3d69a3b97deab Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 6 Jun 2022 11:52:12 +0200 Subject: [PATCH 123/267] temporary workaround for RRC passing CG to MAC (forced encoding of message at MAC) --- openair1/PHY/INIT/nr_init.c | 4 +-- openair2/LAYER2/NR_MAC_gNB/config.c | 18 ++++++++++++- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 10 +++++++- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 ++ openair2/RRC/NR/rrc_gNB.c | 25 ++++++++++--------- 5 files changed, 43 insertions(+), 16 deletions(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 9a57009578..8ab978614e 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -544,8 +544,8 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, gNB->nr_gold_pdsch_dmrs = (uint32_t ****)malloc16(fp->slots_per_frame*sizeof(uint32_t ***)); uint32_t ****pdsch_dmrs = gNB->nr_gold_pdsch_dmrs; - // ceil(((NB_RB*6(k)*2(QPSK)/32) // 3 RE *2(QPSK) - int pdsch_dmrs_init_length = ((fp->N_RB_DL*12)>>5)+1; + // ceil(((NB_RB*12(k)*2(QPSK)/32) // 3 RE *2(QPSK) + int pdsch_dmrs_init_length = ((fp->N_RB_DL*24)>>5)+1; for (int slot=0; slotslots_per_frame; slot++) { pdsch_dmrs[slot] = (uint32_t ***)malloc16(fp->symbols_per_slot*sizeof(uint32_t **)); AssertFatal(pdsch_dmrs[slot]!=NULL, "NR init: pdsch_dmrs for slot %d - malloc failed\n", slot); diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 0e55b519ab..95ccc9a4d4 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -654,7 +654,23 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, } int target_ss; - UE->CellGroup = CellGroup; + /* copy CellGroup by calling asn1c encode + this is a temporary hack to avoid the gNB having + a pointer to RRC CellGroup structure + (otherwise it would be applied to early) + TODO remove once we have a proper implementation */ + UE->enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, + NULL, + (void *)CellGroup, + UE->cg_buf, + 32768); + + if(UE->enc_rval.encoded == -1) { + LOG_E(NR_MAC, "ASN1 message CellGroupConfig encoding failed (%s, %lu)!\n", + UE->enc_rval.failed_type->name, UE->enc_rval.encoded); + exit(1); + } + LOG_I(NR_MAC,"Modified rnti %04x with CellGroup\n",rnti); process_CellGroup(CellGroup,&UE->UE_sched_ctrl); NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 65d2ce09c5..afc37d8d8a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2903,7 +2903,15 @@ void nr_mac_update_timers(module_id_t module_id, LOG_I(NR_MAC, "(%d.%d) De-activating RRC processing timer for UE %04x\n", frame, slot, UE->rnti); const NR_SIB1_t *sib1 = RC.nrmac[module_id]->common_channels[0].sib1 ? RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - NR_CellGroupConfig_t *cg = UE->CellGroup; + + NR_CellGroupConfig_t *cg = NULL; + uper_decode(NULL, + &asn_DEF_NR_CellGroupConfig, //might be added prefix later + (void **)&cg, + (uint8_t *)UE->cg_buf, + (UE->enc_rval.encoded+7)/8, 0, 0); + UE->CellGroup = cg; + NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon; const NR_ServingCellConfig_t *spCellConfigDedicated = cg && cg->spCellConfig ? cg->spCellConfig->spCellConfigDedicated : NULL; diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 974d6dff4a..1d0d9750e6 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -710,6 +710,8 @@ typedef struct { NR_UE_sched_ctrl_t UE_sched_ctrl; NR_mac_stats_t mac_stats; NR_CellGroupConfig_t *CellGroup; + char cg_buf[32768]; /* arbitrary size */ + asn_enc_rval_t enc_rval; /// CCE indexing int m; // UE selected beam index diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index f5879a0c49..d8c26114c2 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -734,6 +734,19 @@ rrc_gNB_generate_defaultRRCReconfiguration( NULL, ue_p->masterCellGroup); + rrc_mac_config_req_gNB(rrc->module_id, + rrc->configuration.ssb_SubcarrierOffset, + rrc->configuration.pdsch_AntennaPorts, + rrc->configuration.pusch_AntennaPorts, + rrc->configuration.sib1_tda, + rrc->configuration.minRXTXTIME, + NULL, + NULL, + NULL, + 0, + ue_p->rnti, + ue_p->masterCellGroup); + free(ue_context_pP->ue_context.nas_pdu.buffer); LOG_DUMPMSG(NR_RRC, DEBUG_RRC,(char *)buffer, size, "[MSG] RRC Reconfiguration\n"); @@ -1430,18 +1443,6 @@ rrc_gNB_process_RRCReconfigurationComplete( /* Refresh SRBs/DRBs */ if (!NODE_IS_CU(RC.nrrrc[ctxt_pP->module_id]->node_type)) { - rrc_mac_config_req_gNB(rrc->module_id, - rrc->configuration.ssb_SubcarrierOffset, - rrc->configuration.pdsch_AntennaPorts, - rrc->configuration.pusch_AntennaPorts, - rrc->configuration.sib1_tda, - rrc->configuration.minRXTXTIME, - NULL, - NULL, - NULL, - 0, - ue_context_pP->ue_context.rnti, - ue_context_pP->ue_context.masterCellGroup); LOG_D(NR_RRC,"Configuring RLC DRBs/SRBs for UE %x\n",ue_context_pP->ue_context.rnti); nr_rrc_rlc_config_asn1_req(ctxt_pP, SRB_configList, // NULL, From 4d4f7dd616193153034fe1644ce6c12bfadc8c23 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 7 Jun 2022 12:11:37 +0200 Subject: [PATCH 124/267] initial commit for MAC UE BWP structure (bwp id) --- openair1/PHY/INIT/nr_init_ru.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 8 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 8 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 190 ++++++++++-------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 10 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 6 +- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 7 +- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 6 + 8 files changed, 129 insertions(+), 108 deletions(-) diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index 0e7c29800a..6aa42b1b10 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -60,7 +60,7 @@ int nr_phy_init_RU(RU_t *ru) { for (i=0; inb_tx; i++) { // Allocate 10 subframes of I/Q TX signal data (time) if not - ru->common.txdata[i] = (int32_t*)malloc16_clear( ru->sf_extension + (fp->samples_per_frame*sizeof(int32_t) )); + ru->common.txdata[i] = (int32_t*)malloc16_clear((ru->sf_extension + fp->samples_per_frame)*sizeof(int32_t)); LOG_I(PHY,"[INIT] common.txdata[%d] = %p (%lu bytes,sf_extension %d)\n",i,ru->common.txdata[i], (ru->sf_extension + fp->samples_per_frame)*sizeof(int32_t),ru->sf_extension); ru->common.txdata[i] = &ru->common.txdata[i][ru->sf_extension]; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 302685bfaf..76becbfcef 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1305,7 +1305,6 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra // look up the PDCCH PDU for this CC, BWP, and CORESET. If it does not exist, create it. This is especially // important if we have multiple RAs, and the DLSCH has to reuse them, so we need to mark them - const int bwpid = bwp ? bwp->bwp_Id : 0; const int coresetid = coreset->controlResourceSetId; nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = nr_mac->pdcch_pdu_idx[CC_id][coresetid]; if (!pdcch_pdu_rel15) { @@ -1479,7 +1478,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra NR_DL_DCI_FORMAT_1_0, NR_RNTI_RA, BWPSize, - bwpid, + ra->dl_bwp_id, coresetid, nr_mac->cset0_bwp_size); @@ -1488,7 +1487,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra // Program UL processing for Msg3 NR_BWP_Uplink_t *ubwp = ra->CellGroup ? - ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra->dl_bwp_id-1] : + ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra->ul_bwp_id-1] : NULL; nr_get_Msg3alloc(module_idP, CC_id, scc, ubwp, slotP, frameP, ra, nr_mac->tdd_beam_association); nr_add_msg3(module_idP, CC_id, frameP, slotP, ra, (uint8_t *) &tx_req->TLVs[0].value.direct[0]); @@ -1764,7 +1763,6 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra // look up the PDCCH PDU for this CC, BWP, and CORESET. If it does not exist, create it. This is especially // important if we have multiple RAs, and the DLSCH has to reuse them, so we need to mark them - const int bwpid = bwp ? bwp->bwp_Id : 0; const int coresetid = coreset->controlResourceSetId; nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = nr_mac->pdcch_pdu_idx[CC_id][coresetid]; if (!pdcch_pdu_rel15) { @@ -1895,7 +1893,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra NR_DL_DCI_FORMAT_1_0, NR_RNTI_TC, pdsch_pdu_rel15->BWPSize, - bwpid, + ra->dl_bwp_id, coresetid, nr_mac->cset0_bwp_size); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 95834e84c5..51dd6d4a8d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -902,6 +902,7 @@ nr_pp_impl_dl nr_init_fr1_dlsch_preprocessor(module_id_t module_id, int CC_id) { void nr_schedule_ue_spec(module_id_t module_id, frame_t frame, sub_frame_t slot) { + gNB_MAC_INST *gNB_mac = RC.nrmac[module_id]; if (!is_xlsch_in_slot(gNB_mac->dlsch_slot_bitmap[slot / 64], slot)) @@ -918,6 +919,7 @@ void nr_schedule_ue_spec(module_id_t module_id, UE_iterator(UE_info->list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_UE_BWP_t *current_BWP = &UE->current_BWP; if (sched_ctrl->ul_failure==1 && get_softmodem_params()->phy_test==0) continue; @@ -1013,7 +1015,7 @@ void nr_schedule_ue_spec(module_id_t module_id, NR_SearchSpace_t *ss = (bwp||bwpd) ? sched_ctrl->search_space : gNB_mac->sched_ctrlCommon->search_space; - const int bwp_id = bwp ? bwp->bwp_Id : 0; + const int bwp_id = current_BWP->dl_bwp_id; const int coresetid = (bwp||bwpd) ? sched_ctrl->coreset->controlResourceSetId : gNB_mac->sched_ctrlCommon->coreset->controlResourceSetId; /* look up the PDCCH PDU for this CC, BWP, and CORESET. If it does not exist, create it */ @@ -1166,7 +1168,7 @@ void nr_schedule_ue_spec(module_id_t module_id, AssertFatal(n_dl_bwp <= NR_MAX_NUM_BWP, "downlinkBWP_ToAddModList has %d BWP!\n", n_dl_bwp); // as per table 7.3.1.1.2-1 in 38.212 - dci_payload.bwp_indicator.val = bwp ? (n_dl_bwp < 4 ? bwp->bwp_Id : bwp->bwp_Id - 1) : 0; + dci_payload.bwp_indicator.val = bwp ? (n_dl_bwp < 4 ? bwp_id : bwp_id - 1) : 0; if (bwp) AssertFatal(bwp->bwp_Dedicated->pdsch_Config->choice.setup->resourceAllocation == NR_PDSCH_Config__resourceAllocation_resourceAllocationType1, "Only frequency resource allocation type 1 is currently supported\n"); @@ -1216,7 +1218,7 @@ void nr_schedule_ue_spec(module_id_t module_id, dci_format, rnti_type, pdsch_pdu->BWPSize, - bwp ? bwp->bwp_Id : 0, + bwp_id, coresetid, gNB_mac->cset0_bwp_size); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index afc37d8d8a..cb767edda3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -1025,7 +1025,7 @@ void nr_configure_css_dci_initial(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu, void config_uldci(const NR_SIB1_t *sib1, const NR_BWP_Uplink_t *ubwp, - const NR_BWP_UplinkDedicated_t *ubwpd, + const NR_BWP_UplinkDedicated_t *ubwpd, const NR_ServingCellConfigCommon_t *scc, const nfapi_nr_pusch_pdu_t *pusch_pdu, dci_pdu_rel15_t *dci_pdu_rel15, @@ -1566,7 +1566,10 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, uint64_t *dci_pdu = (uint64_t *)pdcch_dci_pdu->Payload; *dci_pdu=0; - int dci_size = nr_dci_size(scc->downlinkConfigCommon->initialDownlinkBWP,scc->uplinkConfigCommon->initialUplinkBWP, CellGroup, dci_pdu_rel15, dci_format, rnti_type, N_RB, bwp_id, coreset_id, cset0_bwp_size); + int dci_size = nr_dci_size(scc->downlinkConfigCommon->initialDownlinkBWP, + scc->uplinkConfigCommon->initialUplinkBWP, + CellGroup, dci_pdu_rel15, dci_format, + rnti_type, N_RB, bwp_id, coreset_id, cset0_bwp_size); pdcch_dci_pdu->PayloadSizeBits = dci_size; AssertFatal(dci_size <= 64, "DCI sizes above 64 bits not yet supported"); if (dci_format == NR_DL_DCI_FORMAT_1_1 || dci_format == NR_UL_DCI_FORMAT_0_1) @@ -2332,24 +2335,6 @@ int get_nrofHARQ_ProcessesForPDSCH(e_NR_PDSCH_ServingCellConfig__nrofHARQ_Proces } } -int get_dl_bwp_id(const NR_ServingCellConfig_t *servingCellConfig) -{ - if (servingCellConfig->firstActiveDownlinkBWP_Id) - return *servingCellConfig->firstActiveDownlinkBWP_Id; - else if (servingCellConfig->defaultDownlinkBWP_Id) - return *servingCellConfig->defaultDownlinkBWP_Id; - else - return 1; -} - -int get_ul_bwp_id(const NR_ServingCellConfig_t *servingCellConfig) -{ - if (servingCellConfig->uplinkConfig && servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id) - return *servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id; - else - return 1; -} - /* hack data to remove UE in the phy */ int rnti_to_remove[10]; volatile int rnti_to_remove_count; @@ -2393,6 +2378,25 @@ void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr) } } +void configure_UE_BWP(NR_UE_BWP_t *BWP, NR_CellGroupConfig_t *CellGroup) { + + if (CellGroup && + CellGroup->spCellConfig && + CellGroup->spCellConfig->spCellConfigDedicated) { + const NR_ServingCellConfig_t *servingCellConfig = CellGroup->spCellConfig->spCellConfigDedicated; + + // (re)configuring BWP ID + // TODO BWP switching not via RRC reconfiguration + // via RRC if firstActiveXlinkBWP_Id is NULL, MAC stays on the same BWP as before + if (servingCellConfig->firstActiveDownlinkBWP_Id) { + BWP->dl_bwp_id = *servingCellConfig->firstActiveDownlinkBWP_Id; + BWP->ul_bwp_id = *servingCellConfig->firstActiveDownlinkBWP_Id; + } + if (servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id) + BWP->ul_bwp_id = *servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id; + } +} + //------------------------------------------------------------------------------ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConfig_t *CellGroup) { @@ -2423,84 +2427,90 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig && CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup) compute_csi_bitlen (CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup, UE); - NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - memset(sched_ctrl, 0, sizeof(*sched_ctrl)); - sched_ctrl->dl_max_mcs = 28; /* do not limit MCS for individual UEs */ - sched_ctrl->set_pmi = false; - sched_ctrl->ta_frame = 0; - sched_ctrl->ta_update = 31; - sched_ctrl->ta_apply = false; - sched_ctrl->ul_rssi = 0; - sched_ctrl->pucch_consecutive_dtx_cnt = 0; - sched_ctrl->pusch_consecutive_dtx_cnt = 0; - sched_ctrl->ul_failure = 0; - sched_ctrl->sched_srs.frame = -1; - sched_ctrl->sched_srs.slot = -1; - sched_ctrl->sched_srs.srs_scheduled = false; - /* set illegal time domain allocation to force recomputation of all fields */ - sched_ctrl->pdsch_semi_static.time_domain_allocation = -1; - sched_ctrl->pusch_semi_static.time_domain_allocation = -1; - const NR_ServingCellConfig_t *servingCellConfig = CellGroup && CellGroup->spCellConfig ? CellGroup->spCellConfig->spCellConfigDedicated : NULL; + NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + memset(sched_ctrl, 0, sizeof(*sched_ctrl)); + sched_ctrl->dl_max_mcs = 28; /* do not limit MCS for individual UEs */ + sched_ctrl->set_pmi = false; + sched_ctrl->ta_frame = 0; + sched_ctrl->ta_update = 31; + sched_ctrl->ta_apply = false; + sched_ctrl->ul_rssi = 0; + sched_ctrl->pucch_consecutive_dtx_cnt = 0; + sched_ctrl->pusch_consecutive_dtx_cnt = 0; + sched_ctrl->ul_failure = 0; + sched_ctrl->sched_srs.frame = -1; + sched_ctrl->sched_srs.slot = -1; + sched_ctrl->sched_srs.srs_scheduled = false; + + // initialize UE BWP information + NR_UE_BWP_t *BWP = &UE->current_BWP; + memset(BWP, 0, sizeof(*BWP)); + configure_UE_BWP(BWP, CellGroup); + + /* set illegal time domain allocation to force recomputation of all fields */ + sched_ctrl->pdsch_semi_static.time_domain_allocation = -1; + sched_ctrl->pusch_semi_static.time_domain_allocation = -1; + const NR_ServingCellConfig_t *servingCellConfig = CellGroup && CellGroup->spCellConfig ? CellGroup->spCellConfig->spCellConfigDedicated : NULL; /* Set default BWPs */ const struct NR_ServingCellConfig__downlinkBWP_ToAddModList *bwpList = servingCellConfig ? servingCellConfig->downlinkBWP_ToAddModList : NULL; - const int bwp_id = servingCellConfig ? *servingCellConfig->firstActiveDownlinkBWP_Id : 0; - sched_ctrl->active_bwp = bwpList && bwp_id > 0 ? bwpList->list.array[bwp_id - 1] : NULL; - NR_BWP_t *genericParameters = sched_ctrl->active_bwp ? - &sched_ctrl->active_bwp->bwp_Common->genericParameters: - &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; - const int target_ss = sched_ctrl->active_bwp ? NR_SearchSpace__searchSpaceType_PR_ue_Specific : NR_SearchSpace__searchSpaceType_PR_common; - const NR_SIB1_t *sib1 = nr_mac->common_channels[0].sib1 ? nr_mac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - sched_ctrl->search_space = get_searchspace(sib1, - scc, - sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Dedicated : NULL, - target_ss); + sched_ctrl->active_bwp = bwpList && BWP->dl_bwp_id > 0 ? bwpList->list.array[BWP->dl_bwp_id - 1] : NULL; + NR_BWP_t *genericParameters = sched_ctrl->active_bwp ? + &sched_ctrl->active_bwp->bwp_Common->genericParameters: + &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; + const int target_ss = sched_ctrl->active_bwp ? NR_SearchSpace__searchSpaceType_PR_ue_Specific : NR_SearchSpace__searchSpaceType_PR_common; + const NR_SIB1_t *sib1 = nr_mac->common_channels[0].sib1 ? nr_mac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; + sched_ctrl->search_space = get_searchspace(sib1, + scc, + sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Dedicated : NULL, + target_ss); sched_ctrl->coreset = get_coreset(nr_mac, scc, sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Dedicated : NULL, - sched_ctrl->search_space, + sched_ctrl->search_space, target_ss); - sched_ctrl->sched_pdcch = set_pdcch_structure(nr_mac, - sched_ctrl->search_space, - sched_ctrl->coreset, - scc, - genericParameters, - NULL); - sched_ctrl->next_dl_bwp_id = -1; - sched_ctrl->next_ul_bwp_id = -1; - const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig ? servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList : NULL; + sched_ctrl->sched_pdcch = set_pdcch_structure(nr_mac, + sched_ctrl->search_space, + sched_ctrl->coreset, + scc, + genericParameters, + NULL); + sched_ctrl->next_dl_bwp_id = -1; + sched_ctrl->next_ul_bwp_id = -1; + const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig ? servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList : NULL; if (ubwpList) AssertFatal(ubwpList->list.count <= NR_MAX_NUM_BWP, - "uplinkBWP_ToAddModList has %d BWP!\n", - ubwpList->list.count); - const int ul_bwp_id = servingCellConfig ? *servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id : 0; - sched_ctrl->active_ubwp = ubwpList && ul_bwp_id > 0 ? ubwpList->list.array[ul_bwp_id - 1] : NULL; + "uplinkBWP_ToAddModList has %d BWP!\n", + ubwpList->list.count); - /* get Number of HARQ processes for this UE */ + sched_ctrl->active_ubwp = ubwpList && BWP->ul_bwp_id > 0 ? ubwpList->list.array[BWP->ul_bwp_id - 1] : NULL; + + /* get Number of HARQ processes for this UE */ if (servingCellConfig) AssertFatal(servingCellConfig->pdsch_ServingCellConfig->present == NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup, "no pdsch-ServingCellConfig found for UE %04x\n", UE->rnti); - const NR_PDSCH_ServingCellConfig_t *pdsch = servingCellConfig ? servingCellConfig->pdsch_ServingCellConfig->choice.setup : NULL; - // pdsch == NULL in SA -> will create default (8) number of HARQ processes - create_dl_harq_list(sched_ctrl, pdsch); - // add all available UL HARQ processes for this UE - // nb of ul harq processes not configurable - create_nr_list(&sched_ctrl->available_ul_harq, 16); - for (int harq = 0; harq < 16; harq++) - add_tail_nr_list(&sched_ctrl->available_ul_harq, harq); - create_nr_list(&sched_ctrl->feedback_ul_harq, 16); - create_nr_list(&sched_ctrl->retrans_ul_harq, 16); + const NR_PDSCH_ServingCellConfig_t *pdsch = servingCellConfig ? servingCellConfig->pdsch_ServingCellConfig->choice.setup : NULL; + // pdsch == NULL in SA -> will create default (8) number of HARQ processes + create_dl_harq_list(sched_ctrl, pdsch); + // add all available UL HARQ processes for this UE + // nb of ul harq processes not configurable + create_nr_list(&sched_ctrl->available_ul_harq, 16); + for (int harq = 0; harq < 16; harq++) + add_tail_nr_list(&sched_ctrl->available_ul_harq, harq); + create_nr_list(&sched_ctrl->feedback_ul_harq, 16); + create_nr_list(&sched_ctrl->retrans_ul_harq, 16); pthread_mutex_lock(&UE_info->mutex); int i; - for(i=0; ilist[i] == NULL) { UE_info->list[i] = UE; break; } + } if (i == MAX_MOBILES_PER_GNB) { LOG_E(NR_MAC,"Try to add UE %04x but the list is full\n", rntiP); delete_nr_ue_data(UE, nr_mac->common_channels); @@ -2593,8 +2603,7 @@ uint8_t nr_get_tpc(int target, uint8_t cqi, int incr) { } -void get_pdsch_to_harq_feedback( NR_UE_info_t * UE, - int bwp_id, +void get_pdsch_to_harq_feedback(NR_UE_info_t *UE, NR_SearchSpace__searchSpaceType_PR ss_type, int *max_fb_time, uint8_t *pdsch_to_harq_feedback) { @@ -2602,26 +2611,28 @@ void get_pdsch_to_harq_feedback( NR_UE_info_t * UE, NR_CellGroupConfig_t *CellGroup = UE->CellGroup; NR_BWP_DownlinkDedicated_t *bwpd=NULL; NR_BWP_UplinkDedicated_t *ubwpd=NULL; + int dl_bwp_id = UE->current_BWP.dl_bwp_id; + int ul_bwp_id = UE->current_BWP.ul_bwp_id; if (ss_type == NR_SearchSpace__searchSpaceType_PR_ue_Specific) { AssertFatal(CellGroup!=NULL,"Cellgroup is not defined for UE %04x\n",UE->rnti); AssertFatal(CellGroup->spCellConfig!=NULL,"Cellgroup->spCellConfig is null\n"); AssertFatal(CellGroup->spCellConfig->spCellConfigDedicated!=NULL,"CellGroup->spCellConfig->spCellConfigDedicated is null\n"); } - if (bwp_id>0) { + if (dl_bwp_id>0 && ul_bwp_id>0) { AssertFatal(CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList!=NULL, "CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList is null\n"); AssertFatal(CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList!=NULL, "CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList is null\n"); - AssertFatal(CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count >= bwp_id, + AssertFatal(CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count >= dl_bwp_id, "CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count %d < bwp_id %d\n", - CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count,bwp_id); - AssertFatal(CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count >= bwp_id, + CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count,dl_bwp_id); + AssertFatal(CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count >= ul_bwp_id, "CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count %d < bwp_id %d\n", - CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count,bwp_id); + CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count,ul_bwp_id); - bwpd = CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Dedicated; - ubwpd = CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Dedicated; + bwpd = CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[dl_bwp_id-1]->bwp_Dedicated; + ubwpd = CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ul_bwp_id-1]->bwp_Dedicated; } else if (CellGroup && CellGroup->spCellConfig && CellGroup->spCellConfig->spCellConfigDedicated) { // this is an initialBWP AssertFatal((bwpd=CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP)!=NULL, @@ -2915,23 +2926,26 @@ void nr_mac_update_timers(module_id_t module_id, NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon; const NR_ServingCellConfig_t *spCellConfigDedicated = cg && cg->spCellConfig ? cg->spCellConfig->spCellConfigDedicated : NULL; + // re-configure BWP information + NR_UE_BWP_t *BWP = &UE->current_BWP; + // If needed, update the Dedicated BWP - const int current_bwp_id = sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0; - const int current_ubwp_id = sched_ctrl->active_ubwp ? sched_ctrl->active_ubwp->bwp_Id : 0; if (spCellConfigDedicated && spCellConfigDedicated->downlinkBWP_ToAddModList && spCellConfigDedicated->uplinkConfig && spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList) { - if (*spCellConfigDedicated->firstActiveDownlinkBWP_Id != current_bwp_id) { + if (*spCellConfigDedicated->firstActiveDownlinkBWP_Id != BWP->dl_bwp_id) { sched_ctrl->active_bwp = spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[*spCellConfigDedicated->firstActiveDownlinkBWP_Id - 1]; LOG_I(NR_MAC, "Changing to DL-BWP %li\n", sched_ctrl->active_bwp->bwp_Id); } - if (*spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id != current_ubwp_id) { + if (*spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id != BWP->ul_bwp_id) { sched_ctrl->active_ubwp = spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[*spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id - 1]; LOG_I(NR_MAC, "Changing to UL-BWP %li\n", sched_ctrl->active_ubwp->bwp_Id); } } + configure_UE_BWP(BWP, UE->CellGroup); + NR_BWP_Downlink_t *bwp = sched_ctrl->active_bwp; NR_BWP_DownlinkDedicated_t *bwpd = cg && cg->spCellConfig && diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index a86767ffbc..9378edfd47 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -938,13 +938,12 @@ void tci_handling(NR_UE_info_t *UE, frame_t frame, slot_t slot) { uint8_t target_ssb_beam_index = curr_ssb_beam_index; uint8_t is_triggering_ssb_beam_switch =0; uint8_t ssb_idx = 0; - int pdsch_bwp_id =0; + int pdsch_bwp_id = 0; int ssb_index[MAX_NUM_SSB] = {0}; int ssb_rsrp[MAX_NUM_SSB] = {0}; uint8_t idx = 0; - + NR_UE_BWP_t *BWP = &UE->current_BWP; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - const int bwp_id = sched_ctrl->active_bwp ? 1 : 0; NR_CellGroupConfig_t *CellGroup = UE->CellGroup; //bwp indicator @@ -960,6 +959,7 @@ void tci_handling(NR_UE_info_t *UE, frame_t frame, slot_t slot) { uint8_t diff_rsrp_idx = 0; uint8_t i, j; + const int bwp_id = BWP->dl_bwp_id; if (n_dl_bwp < 4) pdsch_bwp_id = bwp_id; else @@ -1632,6 +1632,7 @@ int nr_acknack_scheduling(int mod_id, * * each UE has dedicated PUCCH Format 0 resources, and we use index 0! */ NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_CellGroupConfig_t *cg = UE->CellGroup; + NR_UE_BWP_t *BWP = &UE->current_BWP; NR_PUCCH_Config_t *pucch_Config = NULL; if (sched_ctrl->active_ubwp) { @@ -1714,10 +1715,9 @@ int nr_acknack_scheduling(int mod_id, NR_SearchSpace__searchSpaceType_PR ss_type = (is_common==0 && (sched_ctrl->active_bwp || ubwpd)) ? NR_SearchSpace__searchSpaceType_PR_ue_Specific: NR_SearchSpace__searchSpaceType_PR_common; uint8_t pdsch_to_harq_feedback[8]; - const int bwp_id = sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0; int max_fb_time = 0; - get_pdsch_to_harq_feedback(UE, bwp_id, ss_type, &max_fb_time, pdsch_to_harq_feedback); + get_pdsch_to_harq_feedback(UE, ss_type, &max_fb_time, pdsch_to_harq_feedback); LOG_D(NR_MAC, "In %s: 1b. DL %4d.%2d, UL_ACK %4d.%2d, DAI_C %d\n", __FUNCTION__, frame,slot,pucch->frame,pucch->ul_slot,pucch->dai_c); /* there is a HARQ. Check whether we can use it for this ACKNACK */ diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index dfc8b24ed8..53ebacdcc6 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1526,6 +1526,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) if (sched_ctrl->ul_failure == 1 && get_softmodem_params()->phy_test==0) continue; NR_CellGroupConfig_t *cg = UE->CellGroup; + NR_UE_BWP_t *current_BWP = &UE->current_BWP; NR_BWP_UplinkDedicated_t *ubwpd = cg && cg->spCellConfig && cg->spCellConfig->spCellConfigDedicated && cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? @@ -1765,7 +1766,6 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) /* look up the PDCCH PDU for this BWP and CORESET. If it does not exist, * create it */ - const int bwp_id = sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0; NR_SearchSpace_t *ss = (sched_ctrl->active_bwp || ubwpd) ? sched_ctrl->search_space: RC.nrmac[module_id]->sched_ctrlCommon->search_space; NR_ControlResourceSet_t *coreset = (sched_ctrl->active_bwp || ubwpd) ? sched_ctrl->coreset: RC.nrmac[module_id]->sched_ctrlCommon->coreset; const int coresetid = coreset->controlResourceSetId; @@ -1821,7 +1821,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) ps->time_domain_allocation, UE->UE_sched_ctrl.tpc0, n_ubwp, - bwp_id); + current_BWP->ul_bwp_id); fill_dci_pdu_rel15(scc, cg, dci_pdu, @@ -1829,7 +1829,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) ps->dci_format, rnti_types[0], pusch_pdu->bwp_size, - bwp_id, + current_BWP->ul_bwp_id, coresetid, nr_mac->cset0_bwp_size); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index f3dd5208d6..1a73cf51ee 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -225,8 +225,7 @@ int nr_acknack_scheduling( int Mod_idP, int r_pucch, int do_common); -void get_pdsch_to_harq_feedback(NR_UE_info_t *, - int bwp_id, +void get_pdsch_to_harq_feedback(NR_UE_info_t *UE, NR_SearchSpace__searchSpaceType_PR ss_type, int *max_fb_time, uint8_t *pdsch_to_harq_feedback); @@ -406,7 +405,9 @@ NR_UE_info_t * find_nr_UE(NR_UEs_t* UEs, rnti_t rntiP); int find_nr_RA_id(module_id_t mod_idP, int CC_idP, rnti_t rntiP); -NR_UE_info_t*add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConfig_t *CellGroup); +void configure_UE_BWP(NR_UE_BWP_t *BWP, NR_CellGroupConfig_t *CellGroup); + +NR_UE_info_t* add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConfig_t *CellGroup); void mac_remove_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rnti); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 1d0d9750e6..f1692e7710 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -701,6 +701,11 @@ typedef struct NR_bler_options { uint8_t max_mcs; } NR_bler_options_t; +typedef struct NR_UE_BWP { + NR_BWP_Id_t dl_bwp_id; + NR_BWP_Id_t ul_bwp_id; +} NR_UE_BWP_t; + /*! \brief UE list used by gNB to order UEs/CC for scheduling*/ #define MAX_CSI_REPORTCONFIG 48 typedef struct { @@ -708,6 +713,7 @@ typedef struct { /// scheduling control info nr_csi_report_t csi_report_template[MAX_CSI_REPORTCONFIG]; NR_UE_sched_ctrl_t UE_sched_ctrl; + NR_UE_BWP_t current_BWP; NR_mac_stats_t mac_stats; NR_CellGroupConfig_t *CellGroup; char cg_buf[32768]; /* arbitrary size */ From 6c69393edaf7d8a82af9172169665d3bb25a4909 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 8 Jun 2022 12:22:16 +0200 Subject: [PATCH 125/267] genericParameters in the new structure --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 124 +++++++----------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 19 +-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 17 ++- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 98 +++++++------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c | 22 +--- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 22 +--- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 37 ++---- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 17 +-- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 19 ++- openair2/RRC/NR/MESSAGES/asn1_msg.c | 4 +- 10 files changed, 152 insertions(+), 227 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 76becbfcef..c00f89394a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -569,20 +569,8 @@ void nr_initiate_ra_proc(module_id_t module_idP, else ra_rnti = 1 + symbol + (slotP * 14) + (freq_index * 14 * 80) + (ul_carrier_id * 14 * 80 * 8); - // This should be handled differently when we use the initialBWP for RA - ra->dl_bwp_id = 0;//TODO - ra->ul_bwp_id = 0; - NR_BWP_Downlink_t *bwp=NULL; - if (ra->CellGroup && ra->CellGroup->spCellConfig && ra->CellGroup->spCellConfig->spCellConfigDedicated) { - if (ra->CellGroup->spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id && - ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList) { - ra->dl_bwp_id = *ra->CellGroup->spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id; - bwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->dl_bwp_id - 1]; - } - if (ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig && - ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id) - ra->ul_bwp_id = *ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id; - } + // Configure RA BWP + configure_UE_BWP(&ra->BWP, scc, ra->CellGroup); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 1); @@ -615,15 +603,19 @@ void nr_initiate_ra_proc(module_id_t module_idP, NR_SearchSpaceId_t ra_SearchSpace = 0; struct NR_PDCCH_ConfigCommon__commonSearchSpaceList *commonSearchSpaceList = NULL; - NR_BWP_t *genericParameters = NULL; + NR_BWP_Downlink_t *bwp=NULL; + if (ra->CellGroup && ra->CellGroup->spCellConfig && ra->CellGroup->spCellConfig->spCellConfigDedicated) { + if (ra->CellGroup->spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id && + ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList) { + bwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->BWP.dl_bwp_id - 1]; + } + } if(bwp) { commonSearchSpaceList = bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList; ra_SearchSpace = *bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->ra_SearchSpace; - genericParameters = &bwp->bwp_Common->genericParameters; } else { commonSearchSpaceList = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList; ra_SearchSpace = *scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->ra_SearchSpace; - genericParameters = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; } AssertFatal(commonSearchSpaceList->list.count > 0, "common SearchSpace list has 0 elements\n"); @@ -641,7 +633,7 @@ void nr_initiate_ra_proc(module_id_t module_idP, ra->ra_ss, ra->coreset, scc, - genericParameters, + ra->BWP.dl_genericParameters, &nr_mac->type0_PDCCH_CSS_config[ra->beam_id]); // retrieving ra pdcch monitoring period and offset @@ -741,22 +733,19 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t gNB_MAC_INST *nr_mac = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; + NR_UE_BWP_t *ra_BWP = &ra->BWP; NR_BWP_Uplink_t *ubwp = NULL; NR_BWP_UplinkDedicated_t *ubwpd = NULL; NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = NULL; - NR_BWP_t *genericParameters = NULL; if(ra->CellGroup) { - ubwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra->ul_bwp_id-1]; + ubwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra_BWP->ul_bwp_id-1]; ubwpd = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; - genericParameters = &ubwp->bwp_Common->genericParameters; pusch_TimeDomainAllocationList = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; - } else { - genericParameters = &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; + } else pusch_TimeDomainAllocationList = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; - } - int mu = genericParameters->subcarrierSpacing; + int mu = ra_BWP->ul_genericParameters->subcarrierSpacing; uint8_t K2 = *pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->k2; const int sched_frame = frame + (slot + K2 >= nr_slots_per_frame[mu]); const int sched_slot = (slot + K2) % nr_slots_per_frame[mu]; @@ -778,7 +767,6 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t tdd_beam_association[num_tdd_period] = ra->beam_id; } - int scs = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing; int fh = 0; int startSymbolAndLength = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; int StartSymbolIndex, NrOfSymbols; @@ -823,7 +811,7 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t fill_msg3_pusch_pdu(pusch_pdu, scc, ra->msg3_round, startSymbolAndLength, - ra->rnti, scs, + ra->rnti, mu, BWPSize, BWPStart, mappingtype, fh, rbStart, ra->msg3_nb_rb); @@ -845,7 +833,7 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t ul_dci_request_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); pdcch_pdu_rel15 = &ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15; ul_dci_req->numPdus += 1; - nr_configure_pdcch(pdcch_pdu_rel15, coreset, genericParameters, &ra->sched_pdcch); + nr_configure_pdcch(pdcch_pdu_rel15, coreset, ra_BWP->dl_genericParameters, &ra->sched_pdcch); nr_mac->pdcch_pdu_idx[CC_id][coresetid] = pdcch_pdu_rel15; } @@ -894,7 +882,7 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t ra->Msg3_tda_id, ra->msg3_TPC, 0, // not used in format 0_0 - ra->ul_bwp_id); + &ra->BWP); fill_dci_pdu_rel15(scc, ra->CellGroup, @@ -903,7 +891,7 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t NR_UL_DCI_FORMAT_0_0, NR_RNTI_TC, pusch_pdu->bwp_size, - ra->ul_bwp_id, + ra_BWP->ul_bwp_id, coresetid, nr_mac->cset0_bwp_size); @@ -925,7 +913,6 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t ra->Msg3_slot = sched_slot; } - } void nr_get_Msg3alloc(module_id_t module_id, @@ -940,12 +927,11 @@ void nr_get_Msg3alloc(module_id_t module_id, // msg3 is scheduled in mixed slot in the following TDD period uint16_t msg3_nb_rb = 8; // sdu has 6 or 8 bytes - frame_type_t frame_type = RC.nrmac[module_id]->common_channels->frame_type; - int mu = ubwp ? - ubwp->bwp_Common->genericParameters.subcarrierSpacing : - scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing; + NR_UE_BWP_t *ra_BWP = &ra->BWP; + + int mu = ra_BWP->ul_genericParameters->subcarrierSpacing; int StartSymbolIndex = 0; int NrOfSymbols = 0; int startSymbolAndLength = 0; @@ -1018,10 +1004,9 @@ void nr_get_Msg3alloc(module_id_t module_id, int bwpSize = NRRIV2BW(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); int bwpStart = NRRIV2PRBOFFSET(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - if (ra->CellGroup) { - NR_BWP_Uplink_t *ubwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra->ul_bwp_id - 1]; - int act_bwp_start = NRRIV2PRBOFFSET(ubwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - int act_bwp_size = NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + if (ra_BWP->ul_genericParameters != &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters) { + int act_bwp_start = NRRIV2PRBOFFSET(ra_BWP->ul_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + int act_bwp_size = NRRIV2BW(ra_BWP->ul_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); if (!((bwpStart >= act_bwp_start) && ((bwpStart+bwpSize) <= (act_bwp_start+act_bwp_size)))) bwpStart = act_bwp_start; } @@ -1056,7 +1041,6 @@ void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, int mappingtype, int fh, int msg3_first_rb, int msg3_nb_rb) { - int start_symbol_index,nr_of_symbols; SLIV2SL(startSymbolAndLength, &start_symbol_index, &nr_of_symbols); @@ -1128,9 +1112,10 @@ void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t slotP, NR_RA_t *ra, uint8_t *RAR_pdu) { - gNB_MAC_INST *mac = RC.nrmac[module_idP]; - NR_COMMON_channels_t *cc = &mac->common_channels[CC_id]; - NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; + gNB_MAC_INST *mac = RC.nrmac[module_idP]; + NR_COMMON_channels_t *cc = &mac->common_channels[CC_id]; + NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; + NR_UE_BWP_t *ra_BWP = &ra->BWP; if (ra->state == RA_IDLE) { LOG_W(NR_MAC,"RA is not active for RA %X. skipping msg3 scheduling\n", ra->rnti); @@ -1164,17 +1149,16 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t memset(pusch_pdu, 0, sizeof(nfapi_nr_pusch_pdu_t)); int ibwp_size = NRRIV2BW(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - int scs = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing; + int scs = ra_BWP->ul_genericParameters->subcarrierSpacing; int fh = 0; int startSymbolAndLength = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; int mappingtype = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->mappingType; if (ra->CellGroup) { - NR_BWP_Uplink_t *ubwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra->ul_bwp_id - 1]; + NR_BWP_Uplink_t *ubwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra_BWP->ul_bwp_id - 1]; startSymbolAndLength = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; mappingtype = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->mappingType; - scs = ubwp->bwp_Common->genericParameters.subcarrierSpacing; fh = ubwp->bwp_Dedicated->pusch_Config->choice.setup->frequencyHopping ? 1 : 0; } @@ -1205,6 +1189,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra gNB_MAC_INST *nr_mac = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; + NR_UE_BWP_t *ra_BWP = &ra->BWP; if ((ra->Msg2_frame == frameP) && (ra->Msg2_slot == slotP)) { @@ -1217,20 +1202,17 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra NR_BWP_Downlink_t *bwp = NULL; NR_ControlResourceSet_t *coreset = NULL; - NR_BWP_t *genericParameters = NULL; NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList=NULL; if (ra->CellGroup && ra->CellGroup->spCellConfig && ra->CellGroup->spCellConfig->spCellConfigDedicated && ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList && - ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->dl_bwp_id-1]) { - bwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->dl_bwp_id-1]; - genericParameters = &bwp->bwp_Common->genericParameters; + ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra_BWP->dl_bwp_id-1]) { + bwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra_BWP->dl_bwp_id-1]; pdsch_TimeDomainAllocationList = bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; } else { - genericParameters= &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; pdsch_TimeDomainAllocationList = scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; } @@ -1238,8 +1220,8 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra long BWPSize = 0; NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config = NULL; if(*ss->controlResourceSetId!=0) { - BWPStart = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - BWPSize = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + BWPStart = NRRIV2PRBOFFSET(ra_BWP->dl_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + BWPSize = NRRIV2BW(ra_BWP->dl_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); } else { type0_PDCCH_CSS_config = &nr_mac->type0_PDCCH_CSS_config[ra->beam_id]; BWPStart = type0_PDCCH_CSS_config->cset_start_rb; @@ -1314,7 +1296,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2 + sizeof(nfapi_nr_dl_tti_pdcch_pdu)); dl_req->nPDUs += 1; pdcch_pdu_rel15 = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; - nr_configure_pdcch(pdcch_pdu_rel15, coreset, genericParameters, &ra->sched_pdcch); + nr_configure_pdcch(pdcch_pdu_rel15, coreset, ra_BWP->dl_genericParameters, &ra->sched_pdcch); nr_mac->pdcch_pdu_idx[CC_id][coresetid] = pdcch_pdu_rel15; } @@ -1362,7 +1344,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra pdsch_pdu_rel15->pduIndex = pduindex; pdsch_pdu_rel15->BWPSize = BWPSize; pdsch_pdu_rel15->BWPStart = BWPStart; - pdsch_pdu_rel15->SubcarrierSpacing = genericParameters->subcarrierSpacing; + pdsch_pdu_rel15->SubcarrierSpacing = ra_BWP->dl_genericParameters->subcarrierSpacing; pdsch_pdu_rel15->CyclicPrefix = 0; pdsch_pdu_rel15->NrOfCodewords = 1; pdsch_pdu_rel15->mcsTable[0] = mcsTableIdx; @@ -1421,7 +1403,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra pdsch_pdu_rel15->TBSize[0] = TBS; } - int bw_tbslbrm = get_bw_tbslbrm(genericParameters, ra->CellGroup); + int bw_tbslbrm = get_bw_tbslbrm(ra_BWP->dl_genericParameters, ra->CellGroup); pdsch_pdu_rel15->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(mcsTableIdx, bw_tbslbrm, 1); @@ -1478,7 +1460,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra NR_DL_DCI_FORMAT_1_0, NR_RNTI_RA, BWPSize, - ra->dl_bwp_id, + ra_BWP->dl_bwp_id, coresetid, nr_mac->cset0_bwp_size); @@ -1487,7 +1469,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra // Program UL processing for Msg3 NR_BWP_Uplink_t *ubwp = ra->CellGroup ? - ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra->ul_bwp_id-1] : + ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra_BWP->ul_bwp_id-1] : NULL; nr_get_Msg3alloc(module_idP, CC_id, scc, ubwp, slotP, frameP, ra, nr_mac->tdd_beam_association); nr_add_msg3(module_idP, CC_id, frameP, slotP, ra, (uint8_t *) &tx_req->TLVs[0].value.direct[0]); @@ -1527,6 +1509,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra gNB_MAC_INST *nr_mac = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; + NR_UE_BWP_t *ra_BWP = &ra->BWP; if (ra->Msg4_frame == frameP && ra->Msg4_slot == slotP ) { @@ -1544,8 +1527,8 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra ra->CellGroup->spCellConfig && ra->CellGroup->spCellConfig->spCellConfigDedicated && ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList && - ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->dl_bwp_id-1]) { - bwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->dl_bwp_id-1]; + ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra_BWP->dl_bwp_id-1]) { + bwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra_BWP->dl_bwp_id-1]; pdsch_TimeDomainAllocationList = bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; } else { @@ -1571,14 +1554,12 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra LOG_I(NR_MAC,"Generate msg4, rnti: %04x\n", ra->rnti); NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_BWP_t *genericParameters = bwp ? & bwp->bwp_Common->genericParameters : &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; - long BWPStart = 0; long BWPSize = 0; NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config = NULL; if(*ss->controlResourceSetId!=0) { - BWPStart = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - BWPSize = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + BWPStart = NRRIV2PRBOFFSET(ra_BWP->dl_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + BWPSize = NRRIV2BW(ra_BWP->dl_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); } else { type0_PDCCH_CSS_config = &nr_mac->type0_PDCCH_CSS_config[ra->beam_id]; BWPStart = type0_PDCCH_CSS_config->cset_start_rb; @@ -1772,7 +1753,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2 + sizeof(nfapi_nr_dl_tti_pdcch_pdu)); dl_req->nPDUs += 1; pdcch_pdu_rel15 = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; - nr_configure_pdcch(pdcch_pdu_rel15, coreset, genericParameters, &ra->sched_pdcch); + nr_configure_pdcch(pdcch_pdu_rel15, coreset, ra_BWP->dl_genericParameters, &ra->sched_pdcch); nr_mac->pdcch_pdu_idx[CC_id][coresetid] = pdcch_pdu_rel15; } @@ -1794,7 +1775,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra pdsch_pdu_rel15->pduIndex = pduindex; pdsch_pdu_rel15->BWPSize = BWPSize; pdsch_pdu_rel15->BWPStart = BWPStart; - pdsch_pdu_rel15->SubcarrierSpacing = genericParameters->subcarrierSpacing; + pdsch_pdu_rel15->SubcarrierSpacing = ra_BWP->dl_genericParameters->subcarrierSpacing; pdsch_pdu_rel15->CyclicPrefix = 0; pdsch_pdu_rel15->NrOfCodewords = 1; int R = nr_get_code_rate_dl(mcsIndex,mcsTableIdx); @@ -1823,7 +1804,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra int x_Overhead = 0; nr_get_tbs_dl(&dl_tti_pdsch_pdu->pdsch_pdu, x_Overhead, pdsch_pdu_rel15->numDmrsCdmGrpsNoData, tb_scaling); - int bw_tbslbrm = get_bw_tbslbrm(genericParameters, ra->CellGroup); + int bw_tbslbrm = get_bw_tbslbrm(ra_BWP->dl_genericParameters, ra->CellGroup); pdsch_pdu_rel15->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(mcsTableIdx, bw_tbslbrm, 1); @@ -1893,7 +1874,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra NR_DL_DCI_FORMAT_1_0, NR_RNTI_TC, pdsch_pdu_rel15->BWPSize, - ra->dl_bwp_id, + ra_BWP->dl_bwp_id, coresetid, nr_mac->cset0_bwp_size); @@ -1985,16 +1966,11 @@ void nr_check_Msg4_Ack(module_id_t module_id, int CC_id, frame_t frame, sub_fram // Pause scheduling according to: // 3GPP TS 38.331 Section 12 Table 12.1-1: UE performance requirements for RRC procedures for UEs - const NR_COMMON_channels_t *common_channels = &RC.nrmac[module_id]->common_channels[0]; - const NR_SIB1_t *sib1 = common_channels->sib1 ? common_channels->sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; const NR_ServingCellConfig_t *servingCellConfig = UE->CellGroup ? UE->CellGroup->spCellConfig->spCellConfigDedicated : NULL; - NR_BWP_t *genericParameters = get_dl_bwp_genericParameters(sched_ctrl->active_bwp, - common_channels->ServingCellConfigCommon, - sib1); uint32_t delay_ms = servingCellConfig && servingCellConfig->downlinkBWP_ToAddModList ? NR_RRC_SETUP_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_SETUP_DELAY_MS; - sched_ctrl->rrc_processing_timer = (delay_ms << genericParameters->subcarrierSpacing); + sched_ctrl->rrc_processing_timer = (delay_ms << ra->BWP.dl_genericParameters->subcarrierSpacing); LOG_I(NR_MAC, "(%d.%d) Activating RRC processing timer for UE %04x with %d ms\n", frame, slot, UE->rnti, delay_ms); } else { LOG_I(NR_MAC, "(ue rnti 0x%04x) RA Procedure failed at Msg4!\n", ra->rnti); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 51dd6d4a8d..fcb5d0d0ae 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -393,12 +393,9 @@ bool allocate_dl_retransmission(module_id_t module_id, cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; const NR_SIB1_t *sib1 = RC.nrmac[module_id]->common_channels[0].sib1 ? RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - NR_BWP_t *genericParameters = get_dl_bwp_genericParameters(sched_ctrl->active_bwp, - RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon, - sib1); const int coresetid = (sched_ctrl->active_bwp||bwpd) ? sched_ctrl->coreset->controlResourceSetId : RC.nrmac[module_id]->sched_ctrlCommon->coreset->controlResourceSetId; - const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : NRRIV2BW(UE->current_BWP.dl_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); int rbStart = 0; // start wrt BWPstart NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; @@ -672,9 +669,7 @@ void pf_dl(module_id_t module_id, RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - NR_BWP_t *genericParameters = get_dl_bwp_genericParameters(sched_ctrl->active_bwp, - RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon, - sib1); + NR_BWP_t *genericParameters = iterator->UE->current_BWP.dl_genericParameters; const int coresetid = (sched_ctrl->active_bwp||bwpd) ? sched_ctrl->coreset->controlResourceSetId : @@ -828,10 +823,7 @@ void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength; SLIV2SL(startSymbolAndLength, &startSymbolIndex, &nrOfSymbols); - const NR_SIB1_t *sib1 = RC.nrmac[module_id]->common_channels[0].sib1 ? RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - NR_BWP_t *genericParameters = get_dl_bwp_genericParameters(sched_ctrl->active_bwp, - RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon, - sib1); + NR_BWP_t *genericParameters = UE->current_BWP.dl_genericParameters; NR_BWP_DownlinkDedicated_t *bwpd = UE->CellGroup && @@ -1008,10 +1000,7 @@ void nr_schedule_ue_spec(module_id_t module_id, sched_ctrl->tpc1); NR_BWP_Downlink_t *bwp = sched_ctrl->active_bwp; - const NR_SIB1_t *sib1 = RC.nrmac[module_id]->common_channels[0].sib1 ? RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - NR_BWP_t *genericParameters = get_dl_bwp_genericParameters(bwp, - RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon, - sib1); + NR_BWP_t *genericParameters = current_BWP->dl_genericParameters; NR_SearchSpace_t *ss = (bwp||bwpd) ? sched_ctrl->search_space : gNB_mac->sched_ctrlCommon->search_space; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index aff03a5323..8300dd0ff4 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -194,6 +194,7 @@ void nr_preprocessor_phytest(module_id_t module_id, NR_UE_info_t *UE = RC.nrmac[module_id]->UE_info.list[0]; NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_UE_BWP_t *BWP = &UE->current_BWP; const int CC_id = 0; const int tda = get_dl_tda(RC.nrmac[module_id], scc, slot); @@ -203,8 +204,8 @@ void nr_preprocessor_phytest(module_id_t module_id, nr_set_pdsch_semi_static(NULL, scc, UE->CellGroup, sched_ctrl->active_bwp, NULL, tda, target_dl_Nl,sched_ctrl , ps); /* find largest unallocated chunk */ - const int bwpSize = NRRIV2BW(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - const int BWPStart = NRRIV2PRBOFFSET(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + const int bwpSize = NRRIV2BW(BWP->dl_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + const int BWPStart = NRRIV2PRBOFFSET(BWP->dl_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); int rbStart = 0; int rbSize = 0; @@ -340,7 +341,6 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ gNB_MAC_INST *nr_mac = RC.nrmac[module_id]; NR_COMMON_channels_t *cc = nr_mac->common_channels; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - const int mu = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing; NR_UE_info_t *UE = nr_mac->UE_info.list[0]; AssertFatal(nr_mac->UE_info.list[1] == NULL, @@ -351,6 +351,9 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ const int CC_id = 0; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_UE_BWP_t *BWP = &UE->current_BWP; + NR_BWP_t *genericParameters = BWP->ul_genericParameters; + const int mu = genericParameters->subcarrierSpacing; const struct NR_PUSCH_TimeDomainResourceAllocationList *tdaList = sched_ctrl->active_ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; @@ -398,12 +401,8 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ uint16_t rbStart = 0; uint16_t rbSize; - const int bw = NRRIV2BW(sched_ctrl->active_ubwp ? - sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth : - scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - const int BWPStart = NRRIV2PRBOFFSET(sched_ctrl->active_ubwp ? - sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth : - scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + const int bw = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + const int BWPStart = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); if (target_ul_bw>bw) rbSize = bw; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index cb767edda3..c03ae014d7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -245,33 +245,6 @@ void set_dl_dmrs_ports(NR_pdsch_semi_static_t *ps) { } } -NR_BWP_t *get_dl_bwp_genericParameters(NR_BWP_Downlink_t *active_bwp, - NR_ServingCellConfigCommon_t *ServingCellConfigCommon, - const NR_SIB1_t *sib1) { - NR_BWP_t *genericParameters = NULL; - if (active_bwp) { - genericParameters = &active_bwp->bwp_Common->genericParameters; - } else if (ServingCellConfigCommon) { - genericParameters = &ServingCellConfigCommon->downlinkConfigCommon->initialDownlinkBWP->genericParameters; - } else { - genericParameters = &sib1->servingCellConfigCommon->downlinkConfigCommon.initialDownlinkBWP.genericParameters; - } - return genericParameters; -} - -NR_BWP_t *get_ul_bwp_genericParameters(NR_BWP_Uplink_t *active_ubwp, - NR_ServingCellConfigCommon_t *ServingCellConfigCommon, - const NR_SIB1_t *sib1) { - NR_BWP_t *genericParameters = NULL; - if (active_ubwp) { - genericParameters = &active_ubwp->bwp_Common->genericParameters; - } else if (ServingCellConfigCommon) { - genericParameters = &ServingCellConfigCommon->uplinkConfigCommon->initialUplinkBWP->genericParameters; - } else { - genericParameters = &sib1->servingCellConfigCommon->uplinkConfigCommon->initialUplinkBWP.genericParameters; - } - return genericParameters; -} NR_PDSCH_TimeDomainResourceAllocationList_t *get_pdsch_TimeDomainAllocationList(const NR_BWP_Downlink_t *active_bwp, const NR_ServingCellConfigCommon_t *ServingCellConfigCommon, @@ -1033,13 +1006,11 @@ void config_uldci(const NR_SIB1_t *sib1, int time_domain_assignment, uint8_t tpc, int n_ubwp, - int bwp_id) { + NR_UE_BWP_t *BWP) { - NR_BWP_t *genericParameters = get_ul_bwp_genericParameters((NR_BWP_Uplink_t *)ubwp, - (NR_ServingCellConfigCommon_t *)scc, - (NR_SIB1_t *)sib1); + int bwp_id = BWP->ul_bwp_id; - const int bw = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + const int bw = NRRIV2BW(BWP->ul_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); dci_pdu_rel15->frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size, pusch_pdu->rb_start, bw); @@ -1176,10 +1147,8 @@ int nr_get_pucch_resource(NR_ControlResourceSet_t *coreset, void nr_configure_pucch(const NR_SIB1_t *sib1, nfapi_nr_pucch_pdu_t* pucch_pdu, NR_ServingCellConfigCommon_t *scc, - NR_CellGroupConfig_t *CellGroup, - NR_BWP_Uplink_t *bwp, + NR_UE_info_t* UE, NR_BWP_UplinkDedicated_t *bwpd, - uint16_t rnti, uint8_t pucch_resource, uint16_t O_csi, uint16_t O_ack, @@ -1191,6 +1160,7 @@ void nr_configure_pucch(const NR_SIB1_t *sib1, NR_PUCCH_ResourceSet_t *pucchresset; NR_PUCCH_FormatConfig_t *pucchfmt; NR_PUCCH_ResourceId_t *resource_id = NULL; + NR_BWP_Uplink_t *bwp = UE->UE_sched_ctrl.active_ubwp; long *id0 = NULL; int n_list, n_set; @@ -1252,7 +1222,7 @@ void nr_configure_pucch(const NR_SIB1_t *sib1, else pucch_pdu->hopping_id = *scc->physCellId; - NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(bwp,scc, sib1); + NR_BWP_t *genericParameters = UE->current_BWP.ul_genericParameters; pucch_pdu->bwp_size = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); pucch_pdu->bwp_start = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth,MAX_BWP_SIZE); @@ -1316,7 +1286,7 @@ void nr_configure_pucch(const NR_SIB1_t *sib1, if (pucchres->pucch_ResourceId == *resource_id) { res_found = 1; pucch_pdu->prb_start = pucchres->startingPRB; - pucch_pdu->rnti = rnti; + pucch_pdu->rnti = UE->rnti; // FIXME why there is only one frequency hopping flag // what about inter slot frequency hopping? pucch_pdu->freq_hop_flag = pucchres->intraSlotFrequencyHopping!= NULL ? 1 : 0; @@ -1417,7 +1387,7 @@ void nr_configure_pucch(const NR_SIB1_t *sib1, &start_symb); pucch_pdu->prb_start = prb_start; - pucch_pdu->rnti = rnti; + pucch_pdu->rnti = UE->rnti; pucch_pdu->freq_hop_flag = 1; pucch_pdu->second_hop_prb = second_hop_prb; pucch_pdu->format_type = default_pucch_fmt[rsetindex]; @@ -2378,7 +2348,12 @@ void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr) } } -void configure_UE_BWP(NR_UE_BWP_t *BWP, NR_CellGroupConfig_t *CellGroup) { +void configure_UE_BWP(NR_UE_BWP_t *BWP, + NR_ServingCellConfigCommon_t *scc, + NR_CellGroupConfig_t *CellGroup) { + + NR_BWP_Downlink_t *dl_bwp = NULL; + NR_BWP_Uplink_t *ul_bwp = NULL; if (CellGroup && CellGroup->spCellConfig && @@ -2394,7 +2369,37 @@ void configure_UE_BWP(NR_UE_BWP_t *BWP, NR_CellGroupConfig_t *CellGroup) { } if (servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id) BWP->ul_bwp_id = *servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id; + + const struct NR_ServingCellConfig__downlinkBWP_ToAddModList *bwpList = servingCellConfig->downlinkBWP_ToAddModList; + if (BWP->dl_bwp_id>0) { + for (int i=0; ilist.count; i++) { + if(dl_bwp->bwp_Id == BWP->dl_bwp_id) { + dl_bwp = bwpList->list.array[i - 1]; + break; + } + } + AssertFatal(dl_bwp!=NULL,"Couldn't find DLBWP corresponding to BWP ID %ld\n",BWP->dl_bwp_id); + } + + const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList; + if (BWP->ul_bwp_id>0) { + for (int i=0; ilist.count; i++) { + if(ul_bwp->bwp_Id == BWP->ul_bwp_id) { + ul_bwp = ubwpList->list.array[i - 1]; + break; + } + } + AssertFatal(ul_bwp!=NULL,"Couldn't find DLBWP corresponding to BWP ID %ld\n",BWP->ul_bwp_id); + } } + + BWP->dl_genericParameters = (BWP->dl_bwp_id>0 && dl_bwp) ? + &dl_bwp->bwp_Common->genericParameters: + &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; + + BWP->ul_genericParameters = (BWP->ul_bwp_id>0 && ul_bwp) ? + &ul_bwp->bwp_Common->genericParameters: + &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; } //------------------------------------------------------------------------------ @@ -2446,7 +2451,7 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf // initialize UE BWP information NR_UE_BWP_t *BWP = &UE->current_BWP; memset(BWP, 0, sizeof(*BWP)); - configure_UE_BWP(BWP, CellGroup); + configure_UE_BWP(BWP, scc, CellGroup); /* set illegal time domain allocation to force recomputation of all fields */ sched_ctrl->pdsch_semi_static.time_domain_allocation = -1; @@ -2457,9 +2462,7 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf const struct NR_ServingCellConfig__downlinkBWP_ToAddModList *bwpList = servingCellConfig ? servingCellConfig->downlinkBWP_ToAddModList : NULL; sched_ctrl->active_bwp = bwpList && BWP->dl_bwp_id > 0 ? bwpList->list.array[BWP->dl_bwp_id - 1] : NULL; - NR_BWP_t *genericParameters = sched_ctrl->active_bwp ? - &sched_ctrl->active_bwp->bwp_Common->genericParameters: - &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; + const int target_ss = sched_ctrl->active_bwp ? NR_SearchSpace__searchSpaceType_PR_ue_Specific : NR_SearchSpace__searchSpaceType_PR_common; const NR_SIB1_t *sib1 = nr_mac->common_channels[0].sib1 ? nr_mac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; sched_ctrl->search_space = get_searchspace(sib1, @@ -2475,7 +2478,7 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf sched_ctrl->search_space, sched_ctrl->coreset, scc, - genericParameters, + BWP->dl_genericParameters, NULL); sched_ctrl->next_dl_bwp_id = -1; sched_ctrl->next_ul_bwp_id = -1; @@ -2712,6 +2715,7 @@ void nr_csirs_scheduling(int Mod_idP, continue; } NR_CellGroupConfig_t *CellGroup = UE->CellGroup; + NR_UE_BWP_t *BWP = &UE->current_BWP; if (!CellGroup || !CellGroup->spCellConfig || !CellGroup->spCellConfig->spCellConfigDedicated || !CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig) continue; @@ -2724,9 +2728,7 @@ void nr_csirs_scheduling(int Mod_idP, int period, offset; nfapi_nr_dl_tti_request_body_t *dl_req = &gNB_mac->DL_req[CC_id].dl_tti_request_body; - NR_BWP_t *genericParameters = sched_ctrl->active_bwp ? - &sched_ctrl->active_bwp->bwp_Common->genericParameters : - &gNB_mac->common_channels[0].ServingCellConfigCommon->downlinkConfigCommon->initialDownlinkBWP->genericParameters; + NR_BWP_t *genericParameters = BWP->dl_genericParameters; for (int id = 0; id < csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.count; id++){ nzpcsi = csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.array[id]; @@ -2944,7 +2946,7 @@ void nr_mac_update_timers(module_id_t module_id, } } - configure_UE_BWP(BWP, UE->CellGroup); + configure_UE_BWP(BWP, scc, UE->CellGroup); NR_BWP_Downlink_t *bwp = sched_ctrl->active_bwp; NR_BWP_DownlinkDedicated_t *bwpd = cg && diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index c156ebf36d..fe07925e3a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -36,19 +36,15 @@ extern RAN_CONTEXT_t RC; void nr_configure_srs(nfapi_nr_srs_pdu_t *srs_pdu, int module_id, int CC_id,NR_UE_info_t* UE, NR_SRS_Resource_t *srs_resource) { - gNB_MAC_INST *nrmac = RC.nrmac[module_id]; - NR_ServingCellConfigCommon_t *scc = nrmac->common_channels[CC_id].ServingCellConfigCommon; - NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_UE_BWP_t *current_BWP = &UE->current_BWP; - NR_BWP_t ubwp = sched_ctrl->active_ubwp ? - sched_ctrl->active_ubwp->bwp_Common->genericParameters : - scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; + NR_BWP_t *ubwp = current_BWP->ul_genericParameters; srs_pdu->rnti = UE->rnti; srs_pdu->handle = 0; - srs_pdu->bwp_size = NRRIV2BW(ubwp.locationAndBandwidth, MAX_BWP_SIZE);; - srs_pdu->bwp_start = NRRIV2PRBOFFSET(ubwp.locationAndBandwidth, MAX_BWP_SIZE);; - srs_pdu->subcarrier_spacing = ubwp.subcarrierSpacing; + srs_pdu->bwp_size = NRRIV2BW(ubwp->locationAndBandwidth, MAX_BWP_SIZE);; + srs_pdu->bwp_start = NRRIV2PRBOFFSET(ubwp->locationAndBandwidth, MAX_BWP_SIZE);; + srs_pdu->subcarrier_spacing = ubwp->subcarrierSpacing; srs_pdu->cyclic_prefix = 0; srs_pdu->num_ant_ports = srs_resource->nrofSRS_Ports; srs_pdu->num_symbols = srs_resource->resourceMapping.nrofSymbols; @@ -114,9 +110,9 @@ void nr_schedule_srs(int module_id, frame_t frame) { UE_iterator(UE_info->list, UE) { const int CC_id = 0; - NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[CC_id].ServingCellConfigCommon; NR_CellGroupConfig_t *cg = UE->CellGroup; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_UE_BWP_t *current_BWP = &UE->current_BWP; sched_ctrl->sched_srs.frame = -1; sched_ctrl->sched_srs.slot = -1; @@ -163,14 +159,10 @@ void nr_schedule_srs(int module_id, frame_t frame) { continue; } - NR_BWP_t ubwp = sched_ctrl->active_ubwp ? - sched_ctrl->active_ubwp->bwp_Common->genericParameters : - scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; - uint16_t period = srs_period[srs_resource->resourceType.choice.periodic->periodicityAndOffset_p.present]; uint16_t offset = get_nr_srs_offset(srs_resource->resourceType.choice.periodic->periodicityAndOffset_p); - int n_slots_frame = nr_slots_per_frame[ubwp.subcarrierSpacing]; + int n_slots_frame = nr_slots_per_frame[current_BWP->ul_genericParameters->subcarrierSpacing]; // Check if UE will transmit the SRS in this frame if ( ((frame - offset/n_slots_frame)*n_slots_frame)%period == 0) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 9378edfd47..a4c10257e8 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -93,10 +93,8 @@ static void nr_fill_nfapi_pucch(gNB_MAC_INST *nrmac, nr_configure_pucch(sib1, pucch_pdu, scc, - UE->CellGroup, - UE->UE_sched_ctrl.active_ubwp, + UE, ubwpd, - UE->rnti, pucch->resource_indicator, pucch->csi_bits, pucch->dai_c, @@ -706,6 +704,7 @@ void nr_csi_meas_reporting(int Mod_idP, UE_iterator(RC.nrmac[Mod_idP]->UE_info.list, UE ) { const NR_CellGroupConfig_t *CellGroup = UE->CellGroup; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_UE_BWP_t *BWP = &UE->current_BWP; if ((sched_ctrl->rrc_processing_timer > 0) || (sched_ctrl->ul_failure==1 && get_softmodem_params()->phy_test==0)) { continue; } @@ -765,12 +764,7 @@ void nr_csi_meas_reporting(int Mod_idP, curr_pucch->csi_bits += nr_get_csi_bitlen(UE,csi_report_id); - const NR_SIB1_t *sib1 = RC.nrmac[Mod_idP]->common_channels[0].sib1 ? RC.nrmac[Mod_idP]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, - scc, - sib1); - - int bwp_start = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth,MAX_BWP_SIZE); + int bwp_start = NRRIV2PRBOFFSET(BWP->ul_genericParameters->locationAndBandwidth,MAX_BWP_SIZE); // going through the list of PUCCH resources to find the one indexed by resource_id uint16_t *vrb_map_UL = &RC.nrmac[Mod_idP]->common_channels[0].vrb_map_UL[sched_slot * MAX_BWP_SIZE]; @@ -1631,8 +1625,8 @@ int nr_acknack_scheduling(int mod_id, * later) * * each UE has dedicated PUCCH Format 0 resources, and we use index 0! */ NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_CellGroupConfig_t *cg = UE->CellGroup; NR_UE_BWP_t *BWP = &UE->current_BWP; + NR_CellGroupConfig_t *cg = UE->CellGroup; NR_PUCCH_Config_t *pucch_Config = NULL; if (sched_ctrl->active_ubwp) { @@ -1644,11 +1638,9 @@ int nr_acknack_scheduling(int mod_id, cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { pucch_Config = cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pucch_Config->choice.setup; } - NR_BWP_t *genericParameters = sched_ctrl->active_ubwp ? - &sched_ctrl->active_ubwp->bwp_Common->genericParameters: - &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; - int bwp_start = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth,MAX_BWP_SIZE); - int bwp_size = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + + int bwp_start = NRRIV2PRBOFFSET(BWP->ul_genericParameters->locationAndBandwidth,MAX_BWP_SIZE); + int bwp_size = NRRIV2BW(BWP->ul_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); NR_sched_pucch_t *pucch = &sched_ctrl->sched_pucch[0]; LOG_D(NR_MAC, "In %s: %4d.%2d Trying to allocate pucch, current DAI %d\n", __FUNCTION__, frame, slot, pucch->dai_c); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 53ebacdcc6..deb15d4c09 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -847,12 +847,8 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; - NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, - (NR_ServingCellConfigCommon_t *)scc, - sib1); - int rbStart = 0; // wrt BWP start - const uint16_t bwpSize = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + const uint16_t bwpSize = NRRIV2BW(UE->current_BWP.ul_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); const uint8_t nrOfLayers = 1; const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_bwp || ubwpd) ? 1 : 2; LOG_D(NR_MAC,"retInfo->time_domain_allocation = %d, tda = %d\n", retInfo->time_domain_allocation, tda); @@ -1042,10 +1038,7 @@ void pf_ul(module_id_t module_id, LOG_D(NR_MAC,"pf_ul: preparing UL scheduling for UE %04x\n",UE->rnti); NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - - NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, - scc, - sib1); + NR_UE_BWP_t *BWP = &UE->current_BWP; int rbStart = 0; // wrt BWP start NR_CellGroupConfig_t *cg = UE->CellGroup; @@ -1053,7 +1046,7 @@ void pf_ul(module_id_t module_id, cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; - const uint16_t bwpSize = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + const uint16_t bwpSize = NRRIV2BW(BWP->ul_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; const NR_mac_dir_stats_t *stats = &UE->mac_stats.ul; @@ -1243,17 +1236,15 @@ void pf_ul(module_id_t module_id, } else LOG_D(NR_MAC, "%4d.%2d free CCE for UL DCI UE %04x\n",frame,slot, iterator->UE->rnti); + NR_UE_BWP_t *BWP = &iterator->UE->current_BWP; NR_CellGroupConfig_t *cg = iterator->UE->CellGroup; NR_BWP_UplinkDedicated_t *ubwpd = cg && cg->spCellConfig && cg->spCellConfig->spCellConfigDedicated && cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; - NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, - scc, - sib1); - int rbStart = sched_ctrl->active_ubwp ? NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE) : 0; - const uint16_t bwpSize = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + int rbStart = sched_ctrl->active_ubwp ? NRRIV2PRBOFFSET(BWP->ul_genericParameters->locationAndBandwidth, MAX_BWP_SIZE) : 0; + const uint16_t bwpSize = NRRIV2BW(BWP->ul_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; @@ -1346,9 +1337,6 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t AssertFatal(scc!=NULL || scc_sib1!=NULL,"We need one serving cell config common\n"); - const int mu = scc ? scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing : - scc_sib1->uplinkConfigCommon->initialUplinkBWP.genericParameters.subcarrierSpacing; - if (nr_mac->UE_info.list[0] == NULL) // no UEs return false; @@ -1360,6 +1348,9 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t * TDAs yet). If the TDA is negative, it means that there is no UL slot to * schedule now (slot + k2 is not UL slot) */ NR_UE_sched_ctrl_t *sched_ctrl = &nr_mac->UE_info.list[0]->UE_sched_ctrl; + NR_UE_BWP_t *BWP = &nr_mac->UE_info.list[0]->current_BWP; + NR_BWP_t *genericParameters = BWP->ul_genericParameters; + int mu = genericParameters->subcarrierSpacing; const int temp_tda = get_ul_tda(nr_mac, scc, slot); int K2 = get_K2(scc, scc_sib1, sched_ctrl->active_ubwp, temp_tda, mu); const int sched_frame = (frame + (slot + K2 >= nr_slots_per_frame[mu])) & 1023; @@ -1409,10 +1400,6 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t uint16_t *vrb_map_UL = &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[sched_slot * MAX_BWP_SIZE]; - NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, - scc, - sib1); - const uint16_t bwpSize = NRRIV2BW(genericParameters->locationAndBandwidth,MAX_BWP_SIZE); const uint16_t bwpStart = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth,MAX_BWP_SIZE); @@ -1656,9 +1643,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) pusch_pdu->handle = 0; //not yet used /* FAPI: BWP */ - NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, - scc, - sib1); + NR_BWP_t *genericParameters = current_BWP->ul_genericParameters; pusch_pdu->bwp_size = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); pusch_pdu->bwp_start = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); @@ -1821,7 +1806,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) ps->time_domain_allocation, UE->UE_sched_ctrl.tpc0, n_ubwp, - current_BWP->ul_bwp_id); + current_BWP); fill_dci_pdu_rel15(scc, cg, dci_pdu, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 1a73cf51ee..6bcef03611 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -201,7 +201,7 @@ void config_uldci(const NR_SIB1_t *sib1, int time_domain_assignment, uint8_t tpc, int n_ubwp, - int bwp_id); + NR_UE_BWP_t *BWP); void nr_schedule_pucch(gNB_MAC_INST* nrmac, frame_t frameP, @@ -257,10 +257,8 @@ int nr_get_pucch_resource(NR_ControlResourceSet_t *coreset, void nr_configure_pucch(const NR_SIB1_t *sib1, nfapi_nr_pucch_pdu_t* pucch_pdu, NR_ServingCellConfigCommon_t *scc, - NR_CellGroupConfig_t *CellGroup, - NR_BWP_Uplink_t *bwp, + NR_UE_info_t* UE, NR_BWP_UplinkDedicated_t *bwpd, - uint16_t rnti, uint8_t pucch_resource, uint16_t O_csi, uint16_t O_ack, @@ -321,13 +319,6 @@ void set_r_pucch_parms(int rsetindex, int *nr_of_symbols, int *start_symbol_index); -NR_BWP_t *get_dl_bwp_genericParameters(NR_BWP_Downlink_t *active_bwp, - NR_ServingCellConfigCommon_t *ServingCellConfigCommon, - const NR_SIB1_t *sib1); - -NR_BWP_t *get_ul_bwp_genericParameters(NR_BWP_Uplink_t *active_ubwp, - NR_ServingCellConfigCommon_t *ServingCellConfigCommon, - const NR_SIB1_t *sib1); NR_PDSCH_TimeDomainResourceAllocationList_t *get_pdsch_TimeDomainAllocationList(const NR_BWP_Downlink_t *active_bwp, const NR_ServingCellConfigCommon_t *ServingCellConfigCommon, @@ -405,7 +396,9 @@ NR_UE_info_t * find_nr_UE(NR_UEs_t* UEs, rnti_t rntiP); int find_nr_RA_id(module_id_t mod_idP, int CC_idP, rnti_t rntiP); -void configure_UE_BWP(NR_UE_BWP_t *BWP, NR_CellGroupConfig_t *CellGroup); +void configure_UE_BWP(NR_UE_BWP_t *BWP, + NR_ServingCellConfigCommon_t *scc, + NR_CellGroupConfig_t *CellGroup); NR_UE_info_t* add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConfig_t *CellGroup); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index f1692e7710..914f9b7052 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -91,6 +91,12 @@ typedef struct { int len; } NR_list_t; +typedef struct NR_UE_BWP { + NR_BWP_Id_t dl_bwp_id; + NR_BWP_Id_t ul_bwp_id; + NR_BWP_t *dl_genericParameters; + NR_BWP_t *ul_genericParameters; +} NR_UE_BWP_t; typedef enum { RA_IDLE = 0, @@ -124,10 +130,6 @@ typedef struct NR_sched_pdcch { typedef struct { /// Flag to indicate this process is active RA_gNB_state_t state; - /// DL BWP id of RA process - int dl_bwp_id; - /// UL BWP id of RA process - int ul_bwp_id; /// CORESET0 configured flag int coreset0_configured; /// Slot where preamble was received @@ -199,6 +201,8 @@ typedef struct { rnti_t crnti; /// CFRA flag bool cfra; + // BWP for RA + NR_UE_BWP_t BWP; } NR_RA_t; /*! \brief gNB common channels */ @@ -701,11 +705,6 @@ typedef struct NR_bler_options { uint8_t max_mcs; } NR_bler_options_t; -typedef struct NR_UE_BWP { - NR_BWP_Id_t dl_bwp_id; - NR_BWP_Id_t ul_bwp_id; -} NR_UE_BWP_t; - /*! \brief UE list used by gNB to order UEs/CC for scheduling*/ #define MAX_CSI_REPORTCONFIG 48 typedef struct { @@ -718,8 +717,6 @@ typedef struct { NR_CellGroupConfig_t *CellGroup; char cg_buf[32768]; /* arbitrary size */ asn_enc_rval_t enc_rval; - /// CCE indexing - int m; // UE selected beam index uint8_t UE_beam_index; bool Msg4_ACKed; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 7e38cac8a0..71b1b12fa0 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -304,8 +304,8 @@ uint8_t do_MIB_NR(gNB_RRC_INST *rrc,uint32_t frame) { } uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier, - gNB_RrcConfigurationReq *configuration - ) { + gNB_RrcConfigurationReq *configuration) { + asn_enc_rval_t enc_rval; NR_BCCH_DL_SCH_Message_t *sib1_message = CALLOC(1,sizeof(NR_BCCH_DL_SCH_Message_t)); From 55e943c34740990092f49aac89c38188f49f8a5a Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 9 Jun 2022 00:48:39 +0100 Subject: [PATCH 126/267] Remove obsolete code after merge --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 187 ---------------------------- 1 file changed, 187 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 5b8bfa13a4..36d45a4905 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1011,193 +1011,6 @@ long rrc_get_max_nr_csrs(uint8_t max_rbs, long b_SRS) { return c_srs; } -void fill_default_csi_MeasConfig(int uid, - NR_SetupRelease_CSI_MeasConfig_t *setupRelease_csi_MeasConfig, - NR_ServingCellConfigCommon_t *scc, - const gNB_RrcConfigurationReq* configuration) { - - int curr_bwp = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth,MAX_BWP_SIZE); - int dl_antenna_ports = configuration->pdsch_AntennaPorts.N1 * configuration->pdsch_AntennaPorts.N2 * configuration->pdsch_AntennaPorts.XP; - - setupRelease_csi_MeasConfig->present = NR_SetupRelease_CSI_MeasConfig_PR_setup; - NR_CSI_MeasConfig_t *csi_MeasConfig = calloc(1,sizeof(*csi_MeasConfig)); - setupRelease_csi_MeasConfig->choice.setup = csi_MeasConfig; - - config_csirs(scc, csi_MeasConfig, uid, dl_antenna_ports, curr_bwp, configuration->do_CSIRS); - config_csiim(configuration->do_CSIRS, dl_antenna_ports, curr_bwp, csi_MeasConfig); - - csi_MeasConfig->csi_SSB_ResourceSetToAddModList = calloc(1,sizeof(*csi_MeasConfig->csi_SSB_ResourceSetToAddModList)); - csi_MeasConfig->csi_SSB_ResourceSetToReleaseList = NULL; - - NR_CSI_SSB_ResourceSet_t *ssbresset0 = calloc(1,sizeof(*ssbresset0)); - ssbresset0->csi_SSB_ResourceSetId=0; - - uint64_t bitmap=0; - switch (scc->ssb_PositionsInBurst->present) { - case 1 : - bitmap = ((uint64_t) scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0])<<56; - break; - case 2 : - bitmap = ((uint64_t) scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0])<<56; - break; - case 3 : - for (int i=0; i<8; i++) { - bitmap |= (((uint64_t) scc->ssb_PositionsInBurst->choice.longBitmap.buf[i])<<((7-i)*8)); - } - break; - default: - AssertFatal(1==0,"SSB bitmap size value %d undefined (allowed values 1,2,3) \n", scc->ssb_PositionsInBurst->present); - } - - NR_SSB_Index_t *ssbresset[64]; - for (int i=0;i<64;i++) { - if ((bitmap>>(63-i))&0x01){ - ssbresset[i]=calloc(1,sizeof(*ssbresset[i])); - *ssbresset[i] = i; - ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset[i]); - } - } - ASN_SEQUENCE_ADD(&csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list,ssbresset0); - - csi_MeasConfig->csi_ResourceConfigToAddModList = calloc(1,sizeof(*csi_MeasConfig->csi_ResourceConfigToAddModList)); - - csi_MeasConfig->csi_ResourceConfigToReleaseList = NULL; - NR_CSI_ResourceConfig_t *csires0 = calloc(1,sizeof(*csires0)); - csires0->csi_ResourceConfigId=0; - csires0->csi_RS_ResourceSetList.present = NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB; - csires0->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB = calloc(1,sizeof(*csires0->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB)); - csires0->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList = calloc(1,sizeof(*csires0->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList)); - NR_NZP_CSI_RS_ResourceSetId_t *nzp0 = calloc(1,sizeof(*nzp0)); - *nzp0 = 0; - ASN_SEQUENCE_ADD(&csires0->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list,nzp0); - csires0->bwp_Id = 0; - csires0->resourceType = NR_CSI_ResourceConfig__resourceType_periodic; - ASN_SEQUENCE_ADD(&csi_MeasConfig->csi_ResourceConfigToAddModList->list,csires0); - - NR_CSI_ResourceConfig_t *csires1 = calloc(1,sizeof(*csires1)); - csires1->csi_ResourceConfigId=1; - csires1->csi_RS_ResourceSetList.present = NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB; - csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB = calloc(1,sizeof(*csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB)); - csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList = calloc(1,sizeof(*csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList)); - NR_CSI_SSB_ResourceSetId_t *ssbres00 = calloc(1,sizeof(*ssbres00)); - *ssbres00 = 0; - ASN_SEQUENCE_ADD(&csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list,ssbres00); - csires1->bwp_Id = 0; - csires1->resourceType = NR_CSI_ResourceConfig__resourceType_periodic; - ASN_SEQUENCE_ADD(&csi_MeasConfig->csi_ResourceConfigToAddModList->list,csires1); - - if (dl_antenna_ports > 1) { - NR_CSI_ResourceConfig_t *csires2 = calloc(1,sizeof(*csires2)); - csires2->csi_ResourceConfigId=2; - csires2->csi_RS_ResourceSetList.present = NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_csi_IM_ResourceSetList; - csires2->csi_RS_ResourceSetList.choice.csi_IM_ResourceSetList = calloc(1,sizeof(*csires2->csi_RS_ResourceSetList.choice.csi_IM_ResourceSetList)); - NR_CSI_IM_ResourceSetId_t *csiim00 = calloc(1,sizeof(*csiim00)); - *csiim00 = 0; - ASN_SEQUENCE_ADD(&csires2->csi_RS_ResourceSetList.choice.csi_IM_ResourceSetList->list,csiim00); - csires2->bwp_Id=0; - csires2->resourceType = NR_CSI_ResourceConfig__resourceType_periodic; - ASN_SEQUENCE_ADD(&csi_MeasConfig->csi_ResourceConfigToAddModList->list,csires2); - } - - NR_PUCCH_CSI_Resource_t *pucchcsires1 = calloc(1,sizeof(*pucchcsires1)); - pucchcsires1->uplinkBandwidthPartId=0; - pucchcsires1->pucch_Resource=1; - csi_MeasConfig->csi_ReportConfigToAddModList = calloc(1,sizeof(*csi_MeasConfig->csi_ReportConfigToAddModList)); - csi_MeasConfig->csi_ReportConfigToReleaseList = NULL; - if (dl_antenna_ports > 1) { - LOG_I(NR_RRC,"Filling CSI Report Config for RI_PMI_CQI\n"); - NR_CSI_ReportConfig_t *csirep1 = calloc(1,sizeof(*csirep1)); - csirep1->reportConfigId=0; - csirep1->carrier=NULL; - csirep1->resourcesForChannelMeasurement=0; - csirep1->csi_IM_ResourcesForInterference=calloc(1,sizeof(*csirep1->csi_IM_ResourcesForInterference)); - *csirep1->csi_IM_ResourcesForInterference=2; - csirep1->nzp_CSI_RS_ResourcesForInterference=NULL; - csirep1->reportConfigType.present = NR_CSI_ReportConfig__reportConfigType_PR_periodic; - csirep1->reportConfigType.choice.periodic = calloc(1,sizeof(*csirep1->reportConfigType.choice.periodic)); - csirep1->reportConfigType.choice.periodic->reportSlotConfig.present=NR_CSI_ReportPeriodicityAndOffset_PR_slots320; - csirep1->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320 = (8 + (20 * uid)) % 320; - ASN_SEQUENCE_ADD(&csirep1->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list,pucchcsires1); - csirep1->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI; - csirep1->reportQuantity.choice.cri_RI_PMI_CQI=(NULL_t)0; - csirep1->reportFreqConfiguration = calloc(1,sizeof(*csirep1->reportFreqConfiguration)); - csirep1->reportFreqConfiguration->cqi_FormatIndicator = calloc(1,sizeof(*csirep1->reportFreqConfiguration->cqi_FormatIndicator)); - *csirep1->reportFreqConfiguration->cqi_FormatIndicator=NR_CSI_ReportConfig__reportFreqConfiguration__cqi_FormatIndicator_widebandCQI; - csirep1->reportFreqConfiguration->pmi_FormatIndicator = calloc(1,sizeof(*csirep1->reportFreqConfiguration->pmi_FormatIndicator)); - *csirep1->reportFreqConfiguration->pmi_FormatIndicator=NR_CSI_ReportConfig__reportFreqConfiguration__pmi_FormatIndicator_widebandPMI; - csirep1->reportFreqConfiguration->csi_ReportingBand = NULL; - /*calloc(1,sizeof(*csirep1->reportFreqConfiguration->csi_ReportingBand)); - csirep1->reportFreqConfiguration->csi_ReportingBand->present = NR_CSI_ReportConfig__reportFreqConfiguration__csi_ReportingBand_PR_subbands7; - csirep1->reportFreqConfiguration->csi_ReportingBand->choice.subbands7.size=1; - csirep1->reportFreqConfiguration->csi_ReportingBand->choice.subbands7.bits_unused=1; - csirep1->reportFreqConfiguration->csi_ReportingBand->choice.subbands7.buf=malloc(1); - csirep1->reportFreqConfiguration->csi_ReportingBand->choice.subbands7.buf[0]=254;*/ - csirep1->timeRestrictionForChannelMeasurements= NR_CSI_ReportConfig__timeRestrictionForChannelMeasurements_notConfigured; - csirep1->timeRestrictionForInterferenceMeasurements=NR_CSI_ReportConfig__timeRestrictionForInterferenceMeasurements_notConfigured; - csirep1->codebookConfig=calloc(1,sizeof(*csirep1->codebookConfig)); - csirep1->codebookConfig->codebookType.present = NR_CodebookConfig__codebookType_PR_type1; - csirep1->codebookConfig->codebookType.choice.type1 = calloc(1,sizeof(*csirep1->codebookConfig->codebookType.choice.type1)); - csirep1->codebookConfig->codebookType.choice.type1->subType.present=NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel; - csirep1->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel=calloc(1,sizeof(*csirep1->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel)); - csirep1->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->nrOfAntennaPorts.present= - NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_two; - csirep1->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->nrOfAntennaPorts.choice.two= - calloc(1,sizeof(*csirep1->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->nrOfAntennaPorts.choice.two)); - csirep1->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->nrOfAntennaPorts.choice.two->twoTX_CodebookSubsetRestriction.size=1; - csirep1->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->nrOfAntennaPorts.choice.two->twoTX_CodebookSubsetRestriction.bits_unused=2; - csirep1->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->nrOfAntennaPorts.choice.two->twoTX_CodebookSubsetRestriction.buf=malloc(1); - csirep1->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->nrOfAntennaPorts.choice.two->twoTX_CodebookSubsetRestriction.buf[0]=0xfc; - csirep1->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->typeI_SinglePanel_ri_Restriction.size=1; - csirep1->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->typeI_SinglePanel_ri_Restriction.bits_unused=0; - csirep1->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->typeI_SinglePanel_ri_Restriction.buf=malloc(1); - csirep1->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->typeI_SinglePanel_ri_Restriction.buf[0]=0x03; - csirep1->codebookConfig->codebookType.choice.type1->codebookMode=1; - csirep1->dummy = NULL; - csirep1->groupBasedBeamReporting.present = NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled; - csirep1->groupBasedBeamReporting.choice.disabled=calloc(1,sizeof(*csirep1->groupBasedBeamReporting.choice.disabled)); - //csirep1->groupBasedBeamReporting.choice.disabled->nrofReportedRS = calloc(1,sizeof(*csirep1->groupBasedBeamReporting.choice.disabled->nrofReportedRS)); - //*csirep1->groupBasedBeamReporting.choice.disabled->nrofReportedRS=NR_CSI_ReportConfig__groupBasedBeamReporting__disabled__nrofReportedRS_n1; - csirep1->cqi_Table = calloc(1,sizeof(*csirep1->cqi_Table)); - *csirep1->cqi_Table = NR_CSI_ReportConfig__cqi_Table_table1; - csirep1->subbandSize = NR_CSI_ReportConfig__subbandSize_value2; - csirep1->non_PMI_PortIndication = NULL; - csirep1->ext1 = NULL; - ASN_SEQUENCE_ADD(&csi_MeasConfig->csi_ReportConfigToAddModList->list,csirep1); - } - - LOG_I(NR_RRC,"Filling CSI Report Config for CRI_RSRP\n"); - NR_CSI_ReportConfig_t *csirep2 = calloc(1,sizeof(*csirep2)); - csirep2->reportConfigId=1; - csirep2->carrier=NULL; - csirep2->resourcesForChannelMeasurement=0; - csirep2->csi_IM_ResourcesForInterference=NULL; - csirep2->nzp_CSI_RS_ResourcesForInterference=NULL; - csirep2->reportConfigType.present = NR_CSI_ReportConfig__reportConfigType_PR_periodic; - csirep2->reportConfigType.choice.periodic = calloc(1,sizeof(*csirep2->reportConfigType.choice.periodic)); - csirep2->reportConfigType.choice.periodic->reportSlotConfig.present=NR_CSI_ReportPeriodicityAndOffset_PR_slots320; - csirep2->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320 = (28 + (20 * uid)) % 320; - ASN_SEQUENCE_ADD(&csirep2->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list,pucchcsires1); - csirep2->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP; - csirep2->reportQuantity.choice.cri_RSRP=(NULL_t)0; - csirep2->reportFreqConfiguration = calloc(1,sizeof(*csirep2->reportFreqConfiguration)); - csirep2->reportFreqConfiguration->cqi_FormatIndicator = NULL; - csirep2->reportFreqConfiguration->pmi_FormatIndicator=NULL; - csirep2->reportFreqConfiguration->csi_ReportingBand=NULL; - csirep2->timeRestrictionForChannelMeasurements= NR_CSI_ReportConfig__timeRestrictionForChannelMeasurements_configured; - csirep2->timeRestrictionForInterferenceMeasurements=NR_CSI_ReportConfig__timeRestrictionForInterferenceMeasurements_configured; - csirep2->codebookConfig=NULL; - csirep2->dummy = NULL; - csirep2->groupBasedBeamReporting.present = NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled; - csirep2->groupBasedBeamReporting.choice.disabled=calloc(1,sizeof(*csirep2->groupBasedBeamReporting.choice.disabled)); - csirep2->groupBasedBeamReporting.choice.disabled->nrofReportedRS=calloc(1,sizeof(*csirep2->groupBasedBeamReporting.choice.disabled->nrofReportedRS)); - *csirep2->groupBasedBeamReporting.choice.disabled->nrofReportedRS=NR_CSI_ReportConfig__groupBasedBeamReporting__disabled__nrofReportedRS_n1; - csirep2->cqi_Table = NULL; - csirep2->subbandSize = NR_CSI_ReportConfig__subbandSize_value1; - csirep2->non_PMI_PortIndication = NULL; - csirep2->ext1 = NULL; - ASN_SEQUENCE_ADD(&csi_MeasConfig->csi_ReportConfigToAddModList->list,csirep2); -} - void fill_default_downlinkBWP(NR_BWP_Downlink_t *bwp, int bwp_loop, NR_ServingCellConfig_t *servingcellconfigdedicated, From 894c45eae5020ddc970fa596e24499d7c5c71a9b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 9 Jun 2022 10:20:39 +0200 Subject: [PATCH 127/267] Add comment to fix fill_mastercellGroupConfig() --- openair2/RRC/NR/rrc_gNB.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 7faadcba4a..7632abd5cd 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1008,6 +1008,8 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( memset(buffer, 0, sizeof(buffer)); if(cell_groupConfig_from_DU == NULL){ cellGroupConfig = calloc(1, sizeof(NR_CellGroupConfig_t)); + // FIXME: fill_mastercellGroupConfig() won't fill the right priorities or + // bearer IDs for the DRBs fill_mastercellGroupConfig(cellGroupConfig, ue_context_pP->ue_context.masterCellGroup, rrc->um_on_default_drb, (drb_id_to_setup_start < 2) ? 1 : 0, drb_id_to_setup_start, nb_drb_to_setup, drb_priority); } else{ @@ -3478,6 +3480,8 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha NR_CellGroupConfig_t *cellGroupConfig = calloc(1, sizeof(NR_CellGroupConfig_t)); if (req->srbs_to_be_setup_length > 0 || req->drbs_to_be_setup_length>0) + // FIXME: fill_mastercellGroupConfig() won't fill the right priorities or + // bearer IDs for the DRBs fill_mastercellGroupConfig(cellGroupConfig, ue_context_p->ue_context.masterCellGroup, rrc->um_on_default_drb, SRB2_config ? 1 : 0, drb_id_to_setup_start, nb_drb_to_setup, drb_priority); apply_macrlc_config(rrc, ue_context_p, &ctxt); From 8adcf8368a68bbbc039b5acf1a3b0fd45287b626 Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 9 Jun 2022 14:48:42 +0200 Subject: [PATCH 128/267] reverting activation of timer at transmission --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 89549b5466..2ea4328b17 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1963,10 +1963,6 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra harq->round = 0; harq->ndi ^= 1; } else { - const NR_ServingCellConfig_t *servingCellConfig = ra->CellGroup ? ra->CellGroup->spCellConfig->spCellConfigDedicated : NULL; - uint32_t delay_ms = servingCellConfig && servingCellConfig->downlinkBWP_ToAddModList ? NR_RRC_SETUP_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_SETUP_DELAY_MS; - sched_ctrl->rrc_processing_timer = (delay_ms << genericParameters->subcarrierSpacing); - LOG_I(NR_MAC, "(%d.%d) Activating RRC processing timer for UE 0x%04x with %d ms\n", frameP, slotP, UE->rnti, delay_ms); ra->state = WAIT_Msg4_ACK; LOG_D(NR_MAC,"[gNB %d][RAPROC] Frame %d, Subframe %d: RA state %d\n", module_idP, frameP, slotP, ra->state); } @@ -1991,6 +1987,19 @@ void nr_check_Msg4_Ack(module_id_t module_id, int CC_id, frame_t frame, sub_fram LOG_A(NR_MAC, "(UE RNTI 0x%04x) Received Ack of RA-Msg4. CBRA procedure succeeded!\n", ra->rnti); UE->Msg4_ACKed = true; + // Pause scheduling according to: + // 3GPP TS 38.331 Section 12 Table 12.1-1: UE performance requirements for RRC procedures for UEs + const NR_COMMON_channels_t *common_channels = &RC.nrmac[module_id]->common_channels[0]; + const NR_SIB1_t *sib1 = common_channels->sib1 ? common_channels->sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; + const NR_ServingCellConfig_t *servingCellConfig = UE_info->CellGroup[UE_id] ? UE_info->CellGroup[UE_id]->spCellConfig->spCellConfigDedicated : NULL; + NR_BWP_t *genericParameters = get_dl_bwp_genericParameters(sched_ctrl->active_bwp, + common_channels->ServingCellConfigCommon, + sib1); + uint32_t delay_ms = servingCellConfig && servingCellConfig->downlinkBWP_ToAddModList ? + NR_RRC_SETUP_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_SETUP_DELAY_MS; + + sched_ctrl->rrc_processing_timer = (delay_ms << genericParameters->subcarrierSpacing); + LOG_I(NR_MAC, "(%d.%d) Activating RRC processing timer for UE %d with %d ms\n", frame, slot, UE_id, delay_ms); } else { LOG_I(NR_MAC, "(ue rnti 0x%04x) RA Procedure failed at Msg4!\n", ra->rnti); } From c1c5c68e707181932f3bddd61290be67acc637aa Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 10 Jun 2022 13:55:57 +0200 Subject: [PATCH 129/267] calling get_searchspace/coreset inside BWP function --- openair1/SIMULATION/NR_PHY/dlsim.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 4 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 109 ++++++++++-------- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 7 +- 4 files changed, 65 insertions(+), 57 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 99236c9a43..d0b422dc74 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -276,7 +276,7 @@ void nr_dlsim_preprocessor(module_id_t module_id, /* manually set free CCE to 0 */ const int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; - sched_ctrl->search_space = get_searchspace(NULL, scc, sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Dedicated : NULL, target_ss); + sched_ctrl->search_space = get_searchspace(scc, sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Dedicated : NULL, target_ss); uint8_t nr_of_candidates; find_aggregation_candidates(&sched_ctrl->aggregation_level, &nr_of_candidates, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 7911c6e2ea..0336829e1c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -570,7 +570,7 @@ void nr_initiate_ra_proc(module_id_t module_idP, ra_rnti = 1 + symbol + (slotP * 14) + (freq_index * 14 * 80) + (ul_carrier_id * 14 * 80 * 8); // Configure RA BWP - configure_UE_BWP(&ra->BWP, scc, ra->CellGroup); + configure_UE_BWP(nr_mac, &ra->BWP, scc, NULL, ra->CellGroup); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 1); @@ -601,7 +601,7 @@ void nr_initiate_ra_proc(module_id_t module_idP, ra->timing_offset = timing_offset; ra->preamble_slot = slotP; - NR_SearchSpaceId_t ra_SearchSpace = 0; + NR_SearchSpaceId_t ra_SearchSpace = 0; struct NR_PDCCH_ConfigCommon__commonSearchSpaceList *commonSearchSpaceList = NULL; NR_BWP_Downlink_t *bwp=NULL; if (ra->CellGroup && ra->CellGroup->spCellConfig && ra->CellGroup->spCellConfig->spCellConfigDedicated) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 8c74b580e7..45be14c622 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -266,6 +266,7 @@ NR_ControlResourceSet_t *get_coreset(gNB_MAC_INST *nrmac, void *bwp, NR_SearchSpace_t *ss, NR_SearchSpace__searchSpaceType_PR ss_type) { + NR_ControlResourceSetId_t coreset_id = *ss->controlResourceSetId; if (ss_type == NR_SearchSpace__searchSpaceType_PR_common) { // common search space @@ -297,29 +298,22 @@ NR_ControlResourceSet_t *get_coreset(gNB_MAC_INST *nrmac, } } -NR_SearchSpace_t *get_searchspace(const NR_SIB1_t *sib1, - NR_ServingCellConfigCommon_t *scc, +NR_SearchSpace_t *get_searchspace(NR_ServingCellConfigCommon_t *scc, NR_BWP_DownlinkDedicated_t *bwp_Dedicated, NR_SearchSpace__searchSpaceType_PR target_ss) { int n = 0; - if(bwp_Dedicated) { + if(bwp_Dedicated) n = bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count; - } else if(scc) { + else n = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList->list.count; - } else { - n = sib1->servingCellConfigCommon->downlinkConfigCommon.initialDownlinkBWP.pdcch_ConfigCommon->choice.setup->commonSearchSpaceList->list.count; - } for (int i=0;ipdcch_Config->choice.setup->searchSpacesToAddModList->list.array[i]; - } else if(scc) { + else ss = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList->list.array[i]; - } else { - ss = sib1->servingCellConfigCommon->downlinkConfigCommon.initialDownlinkBWP.pdcch_ConfigCommon->choice.setup->commonSearchSpaceList->list.array[i]; - } AssertFatal(ss->controlResourceSetId != NULL, "ss->controlResourceSetId is null\n"); AssertFatal(ss->searchSpaceType != NULL, "ss->searchSpaceType is null\n"); if (ss->searchSpaceType->present == target_ss) { @@ -2324,19 +2318,27 @@ void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr) } } -void configure_UE_BWP(NR_UE_BWP_t *BWP, +void configure_UE_BWP(gNB_MAC_INST *nr_mac, + NR_UE_BWP_t *BWP, NR_ServingCellConfigCommon_t *scc, + NR_UE_sched_ctrl_t *sched_ctrl, NR_CellGroupConfig_t *CellGroup) { NR_BWP_Downlink_t *dl_bwp = NULL; NR_BWP_Uplink_t *ul_bwp = NULL; + NR_BWP_DownlinkDedicated_t *bwpd = NULL; + NR_BWP_UplinkDedicated_t *ubwpd = NULL; + + int target_ss; if (CellGroup && CellGroup->spCellConfig && CellGroup->spCellConfig->spCellConfigDedicated) { - const NR_ServingCellConfig_t *servingCellConfig = CellGroup->spCellConfig->spCellConfigDedicated; - // (re)configuring BWP ID + const NR_ServingCellConfig_t *servingCellConfig = CellGroup->spCellConfig->spCellConfigDedicated; + target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; + + // (re)configuring BWP // TODO BWP switching not via RRC reconfiguration // via RRC if firstActiveXlinkBWP_Id is NULL, MAC stays on the same BWP as before if (servingCellConfig->firstActiveDownlinkBWP_Id) { @@ -2349,10 +2351,9 @@ void configure_UE_BWP(NR_UE_BWP_t *BWP, const struct NR_ServingCellConfig__downlinkBWP_ToAddModList *bwpList = servingCellConfig->downlinkBWP_ToAddModList; if (BWP->dl_bwp_id>0) { for (int i=0; ilist.count; i++) { - if(dl_bwp->bwp_Id == BWP->dl_bwp_id) { - dl_bwp = bwpList->list.array[i - 1]; + dl_bwp = bwpList->list.array[i]; + if(dl_bwp->bwp_Id == BWP->dl_bwp_id) break; - } } AssertFatal(dl_bwp!=NULL,"Couldn't find DLBWP corresponding to BWP ID %ld\n",BWP->dl_bwp_id); } @@ -2360,15 +2361,30 @@ void configure_UE_BWP(NR_UE_BWP_t *BWP, const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList; if (BWP->ul_bwp_id>0) { for (int i=0; ilist.count; i++) { - if(ul_bwp->bwp_Id == BWP->ul_bwp_id) { - ul_bwp = ubwpList->list.array[i - 1]; + ul_bwp = ubwpList->list.array[i]; + if(ul_bwp->bwp_Id == BWP->ul_bwp_id) break; - } } AssertFatal(ul_bwp!=NULL,"Couldn't find DLBWP corresponding to BWP ID %ld\n",BWP->ul_bwp_id); } + + // selection of dedicated BWPs + if(dl_bwp) + bwpd = dl_bwp->bwp_Dedicated; + else + bwpd = servingCellConfig->initialDownlinkBWP; + if(ul_bwp) + ubwpd = ul_bwp->bwp_Dedicated; + else + ubwpd = servingCellConfig->uplinkConfig->initialUplinkBWP; + } + else { + BWP->dl_bwp_id = 0; + BWP->ul_bwp_id = 0; + target_ss = NR_SearchSpace__searchSpaceType_PR_common; } + // acquiring generic parameters BWP->dl_genericParameters = (BWP->dl_bwp_id>0 && dl_bwp) ? &dl_bwp->bwp_Common->genericParameters: &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; @@ -2376,6 +2392,24 @@ void configure_UE_BWP(NR_UE_BWP_t *BWP, BWP->ul_genericParameters = (BWP->ul_bwp_id>0 && ul_bwp) ? &ul_bwp->bwp_Common->genericParameters: &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; + + if(sched_ctrl) { + sched_ctrl->search_space = get_searchspace(scc, + bwpd, + target_ss); + sched_ctrl->coreset = get_coreset(nr_mac, + scc, + bwpd, + sched_ctrl->search_space, + target_ss); + + sched_ctrl->sched_pdcch = set_pdcch_structure(nr_mac, + sched_ctrl->search_space, + sched_ctrl->coreset, + scc, + BWP->dl_genericParameters, + nr_mac->type0_PDCCH_CSS_config); + } } //------------------------------------------------------------------------------ @@ -2428,7 +2462,7 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf // initialize UE BWP information NR_UE_BWP_t *BWP = &UE->current_BWP; memset(BWP, 0, sizeof(*BWP)); - configure_UE_BWP(BWP, scc, CellGroup); + configure_UE_BWP(nr_mac, BWP, scc, sched_ctrl, CellGroup); /* set illegal time domain allocation to force recomputation of all fields */ sched_ctrl->pdsch_semi_static.time_domain_allocation = -1; @@ -2440,23 +2474,6 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf sched_ctrl->active_bwp = bwpList && BWP->dl_bwp_id > 0 ? bwpList->list.array[BWP->dl_bwp_id - 1] : NULL; - const int target_ss = sched_ctrl->active_bwp ? NR_SearchSpace__searchSpaceType_PR_ue_Specific : NR_SearchSpace__searchSpaceType_PR_common; - const NR_SIB1_t *sib1 = nr_mac->common_channels[0].sib1 ? nr_mac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - sched_ctrl->search_space = get_searchspace(sib1, - scc, - sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Dedicated : NULL, - target_ss); - sched_ctrl->coreset = get_coreset(nr_mac, - scc, - sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Dedicated : NULL, - sched_ctrl->search_space, - target_ss); - sched_ctrl->sched_pdcch = set_pdcch_structure(nr_mac, - sched_ctrl->search_space, - sched_ctrl->coreset, - scc, - BWP->dl_genericParameters, - NULL); sched_ctrl->next_dl_bwp_id = -1; sched_ctrl->next_ul_bwp_id = -1; const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig ? servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList : NULL; @@ -2944,30 +2961,20 @@ void nr_mac_update_timers(module_id_t module_id, } } - configure_UE_BWP(BWP, scc, UE->CellGroup); + configure_UE_BWP(RC.nrmac[module_id], BWP, scc, sched_ctrl, UE->CellGroup); // Update coreset/searchspace NR_BWP_Downlink_t *bwp = sched_ctrl->active_bwp; NR_BWP_DownlinkDedicated_t *bwpd = NULL; - int target_ss = NR_SearchSpace__searchSpaceType_PR_common; if (bwp) { - target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; bwpd = sched_ctrl->active_bwp->bwp_Dedicated; } else if (cg && cg->spCellConfig && cg->spCellConfig->spCellConfigDedicated && (cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP)) { - target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; bwpd = cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP; } - sched_ctrl->search_space = get_searchspace(sib1, scc, (void*)bwpd, target_ss); - sched_ctrl->coreset = get_coreset(RC.nrmac[module_id], scc, (void*)bwpd, sched_ctrl->search_space, target_ss); - sched_ctrl->sched_pdcch = set_pdcch_structure(RC.nrmac[module_id], - sched_ctrl->search_space, - sched_ctrl->coreset, - scc, - BWP->dl_genericParameters, - RC.nrmac[module_id]->type0_PDCCH_CSS_config); + sched_ctrl->maxL = 2; if (cg && cg->spCellConfig && diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 6bcef03611..f880b8e709 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -332,8 +332,7 @@ NR_ControlResourceSet_t *get_coreset(gNB_MAC_INST *nrmac, NR_SearchSpace__searchSpaceType_PR ss_type); /* find a search space within a BWP */ -NR_SearchSpace_t *get_searchspace(const NR_SIB1_t *sib1, - NR_ServingCellConfigCommon_t *scc, +NR_SearchSpace_t *get_searchspace(NR_ServingCellConfigCommon_t *scc, NR_BWP_DownlinkDedicated_t *bwp_Dedicated, NR_SearchSpace__searchSpaceType_PR target_ss); @@ -396,8 +395,10 @@ NR_UE_info_t * find_nr_UE(NR_UEs_t* UEs, rnti_t rntiP); int find_nr_RA_id(module_id_t mod_idP, int CC_idP, rnti_t rntiP); -void configure_UE_BWP(NR_UE_BWP_t *BWP, +void configure_UE_BWP(gNB_MAC_INST *nr_mac, + NR_UE_BWP_t *BWP, NR_ServingCellConfigCommon_t *scc, + NR_UE_sched_ctrl_t *sched_ctrl, NR_CellGroupConfig_t *CellGroup); NR_UE_info_t* add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConfig_t *CellGroup); From e592045d8f841579758dbb2e1a35c7e42bdbf585 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 10 Jun 2022 18:18:57 +0200 Subject: [PATCH 130/267] improvements in using genericParameters and other stuff --- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 24 ++--- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h | 2 +- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 6 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 84 +++++----------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 2 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 54 ++++------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 11 +-- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 95 +++++++++++++------ .../LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c | 10 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 39 +++----- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 30 +++--- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 3 +- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 10 +- 13 files changed, 175 insertions(+), 195 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index bb80ff2a3c..c906a6dcef 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -4112,22 +4112,22 @@ uint16_t compute_pucch_prb_size(uint8_t format, } } -int get_bw_tbslbrm(NR_BWP_t *genericParameters, +int get_bw_tbslbrm(int scc_bwpsize, NR_CellGroupConfig_t *cg) { - int bw = 0; - if (cg && cg->spCellConfig && cg->spCellConfig->spCellConfigDedicated && - cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList) { - struct NR_ServingCellConfig__downlinkBWP_ToAddModList *BWP_list = cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList; - for (int i=0; ilist.count; i++) { - genericParameters = &BWP_list->list.array[i]->bwp_Common->genericParameters; - int curr_bw = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - if (curr_bw > bw) - bw = curr_bw; + int bw = scc_bwpsize; + if (cg && cg->spCellConfig && cg->spCellConfig->spCellConfigDedicated) { + const NR_ServingCellConfig_t *servingCellConfig = cg->spCellConfig->spCellConfigDedicated; + if(servingCellConfig->downlinkBWP_ToAddModList) { + struct NR_ServingCellConfig__downlinkBWP_ToAddModList *BWP_list = servingCellConfig->downlinkBWP_ToAddModList; + for (int i=0; ilist.count; i++) { + NR_BWP_t genericParameters = BWP_list->list.array[i]->bwp_Common->genericParameters; + int curr_bw = NRRIV2BW(genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + if (curr_bw > bw) + bw = curr_bw; + } } } - else - bw = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); return bw; } diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index a658c990bc..a7a2a88e94 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -140,7 +140,7 @@ uint32_t nr_get_code_rate_ul(uint8_t Imcs, uint8_t table_idx); uint16_t get_nr_srs_offset(NR_SRS_PeriodicityAndOffset_t periodicityAndOffset); -int get_bw_tbslbrm(NR_BWP_t *genericParameters, +int get_bw_tbslbrm(int scc_bwpsize, NR_CellGroupConfig_t *cg); uint32_t nr_compute_tbslbrm(uint16_t table, diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 6b8dce9c9a..d06e8b71ec 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -957,7 +957,8 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr if (mac->scc || mac->scc_SIB || mac->cg) { NR_BWP_t genericParameters = mac->scc ? mac->scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters : mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP.genericParameters; - bw_tbslbrm = get_bw_tbslbrm(&genericParameters, mac->cg); + int BWPSize = NRRIV2BW(genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + bw_tbslbrm = get_bw_tbslbrm(BWPSize, mac->cg); } else bw_tbslbrm = dlsch_config_pdu_1_0->BWPSize; @@ -1396,7 +1397,8 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr int nl_tbslbrm = *maxMIMO_Layers < 4 ? *maxMIMO_Layers : 4; NR_BWP_t genericParameters = mac->scc ? mac->scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters : mac->scc_SIB->downlinkConfigCommon.initialDownlinkBWP.genericParameters; - int bw_tbslbrm = get_bw_tbslbrm(&genericParameters, mac->cg); + int BWPSize = NRRIV2BW(genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + int bw_tbslbrm = get_bw_tbslbrm(BWPSize, mac->cg); dlsch_config_pdu_1_1->tbslbrm = nr_compute_tbslbrm(dlsch_config_pdu_1_1->mcs_table, bw_tbslbrm, nl_tbslbrm); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 0336829e1c..05fcfb0e04 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -398,7 +398,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP void nr_schedule_msg2(uint16_t rach_frame, uint16_t rach_slot, uint16_t *msg2_frame, uint16_t *msg2_slot, - NR_ServingCellConfigCommon_t *scc, + int mu, NR_ServingCellConfigCommon_t *scc, frame_type_t frame_type, uint16_t monitoring_slot_period, uint16_t monitoring_offset,uint8_t beam_index, @@ -407,10 +407,9 @@ void nr_schedule_msg2(uint16_t rach_frame, uint16_t rach_slot, // preferentially we schedule the msg2 in the mixed slot or in the last dl slot // if they are allowed by search space configuration - uint8_t mu = *scc->ssbSubcarrierSpacing; uint8_t response_window = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.ra_ResponseWindow; uint8_t slot_window; - const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; + const int n_slots_frame = nr_slots_per_frame[mu]; const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; // number of mixed slot or of last dl slot if there is no mixed slot uint8_t last_dl_slot_period = n_slots_frame-1; @@ -516,7 +515,6 @@ void nr_initiate_ra_proc(module_id_t module_idP, int16_t timing_offset){ uint8_t ul_carrier_id = 0; // 0 for NUL 1 for SUL - NR_SearchSpace_t *ss; uint16_t msg2_frame, msg2_slot,monitoring_slot_period,monitoring_offset; gNB_MAC_INST *nr_mac = RC.nrmac[module_idP]; @@ -570,7 +568,7 @@ void nr_initiate_ra_proc(module_id_t module_idP, ra_rnti = 1 + symbol + (slotP * 14) + (freq_index * 14 * 80) + (ul_carrier_id * 14 * 80 * 8); // Configure RA BWP - configure_UE_BWP(nr_mac, &ra->BWP, scc, NULL, ra->CellGroup); + configure_UE_BWP(nr_mac, &ra->BWP, scc, NULL, ra, ra->CellGroup); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 1); @@ -601,41 +599,6 @@ void nr_initiate_ra_proc(module_id_t module_idP, ra->timing_offset = timing_offset; ra->preamble_slot = slotP; - NR_SearchSpaceId_t ra_SearchSpace = 0; - struct NR_PDCCH_ConfigCommon__commonSearchSpaceList *commonSearchSpaceList = NULL; - NR_BWP_Downlink_t *bwp=NULL; - if (ra->CellGroup && ra->CellGroup->spCellConfig && ra->CellGroup->spCellConfig->spCellConfigDedicated) { - if (ra->CellGroup->spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id && - ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList) { - bwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->BWP.dl_bwp_id - 1]; - } - } - if(bwp) { - commonSearchSpaceList = bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList; - ra_SearchSpace = *bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->ra_SearchSpace; - } else { - commonSearchSpaceList = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList; - ra_SearchSpace = *scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->ra_SearchSpace; - } - AssertFatal(commonSearchSpaceList->list.count > 0, "common SearchSpace list has 0 elements\n"); - - // Common SearchSpace list - for (int i = 0; i < commonSearchSpaceList->list.count; i++) { - ss = commonSearchSpaceList->list.array[i]; - if (ss->searchSpaceId == ra_SearchSpace) - ra->ra_ss = ss; - } - - AssertFatal(ra->ra_ss!=NULL,"SearchSpace cannot be null for RA\n"); - - ra->coreset = get_coreset(nr_mac, scc, bwp, ra->ra_ss, NR_SearchSpace__searchSpaceType_PR_common); - ra->sched_pdcch = set_pdcch_structure(nr_mac, - ra->ra_ss, - ra->coreset, - scc, - ra->BWP.dl_genericParameters, - &nr_mac->type0_PDCCH_CSS_config[ra->beam_id]); - // retrieving ra pdcch monitoring period and offset find_monitoring_periodicity_offset_common(ra->ra_ss, &monitoring_slot_period, &monitoring_offset); @@ -643,6 +606,7 @@ void nr_initiate_ra_proc(module_id_t module_idP, slotP, &msg2_frame, &msg2_slot, + ra->BWP.dl_scs, scc, frame_type, monitoring_slot_period, @@ -745,7 +709,7 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t } else pusch_TimeDomainAllocationList = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; - int mu = ra_BWP->ul_genericParameters->subcarrierSpacing; + int mu = ra_BWP->ul_scs; uint8_t K2 = *pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->k2; const int sched_frame = frame + (slot + K2 >= nr_slots_per_frame[mu]); const int sched_slot = (slot + K2) % nr_slots_per_frame[mu]; @@ -755,7 +719,7 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t int16_t *tdd_beam_association = nr_mac->tdd_beam_association; if (*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0] >= 257) { // FR2 - const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; + const int n_slots_frame = nr_slots_per_frame[mu]; const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; AssertFatal(tdd,"Dynamic TDD not handled yet\n"); uint8_t tdd_period_slot = n_slots_frame/get_nb_periods_per_frame(tdd->dl_UL_TransmissionPeriodicity); @@ -833,7 +797,7 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t ul_dci_request_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); pdcch_pdu_rel15 = &ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15; ul_dci_req->numPdus += 1; - nr_configure_pdcch(pdcch_pdu_rel15, coreset, ra_BWP->dl_genericParameters, &ra->sched_pdcch); + nr_configure_pdcch(pdcch_pdu_rel15, coreset, false, &ra->sched_pdcch); nr_mac->pdcch_pdu_idx[CC_id][coresetid] = pdcch_pdu_rel15; } @@ -931,7 +895,7 @@ void nr_get_Msg3alloc(module_id_t module_id, NR_UE_BWP_t *ra_BWP = &ra->BWP; - int mu = ra_BWP->ul_genericParameters->subcarrierSpacing; + int mu = ra_BWP->ul_scs; int StartSymbolIndex = 0; int NrOfSymbols = 0; int startSymbolAndLength = 0; @@ -1004,9 +968,9 @@ void nr_get_Msg3alloc(module_id_t module_id, int bwpSize = NRRIV2BW(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); int bwpStart = NRRIV2PRBOFFSET(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - if (ra_BWP->ul_genericParameters != &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters) { - int act_bwp_start = NRRIV2PRBOFFSET(ra_BWP->ul_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - int act_bwp_size = NRRIV2BW(ra_BWP->ul_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + if (bwpSize != ra_BWP->ul_BWPSize || bwpStart != ra_BWP->ul_BWPStart) { + int act_bwp_start = ra_BWP->ul_BWPStart; + int act_bwp_size = ra_BWP->ul_BWPSize; if (!((bwpStart >= act_bwp_start) && ((bwpStart+bwpSize) <= (act_bwp_start+act_bwp_size)))) bwpStart = act_bwp_start; } @@ -1149,7 +1113,7 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t memset(pusch_pdu, 0, sizeof(nfapi_nr_pusch_pdu_t)); int ibwp_size = NRRIV2BW(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - int scs = ra_BWP->ul_genericParameters->subcarrierSpacing; + int scs = ra_BWP->ul_scs; int fh = 0; int startSymbolAndLength = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; int mappingtype = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->mappingType; @@ -1220,8 +1184,8 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra long BWPSize = 0; NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config = NULL; if(*ss->controlResourceSetId!=0) { - BWPStart = NRRIV2PRBOFFSET(ra_BWP->dl_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - BWPSize = NRRIV2BW(ra_BWP->dl_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + BWPStart = ra_BWP->dl_BWPStart; + BWPSize = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); } else { type0_PDCCH_CSS_config = &nr_mac->type0_PDCCH_CSS_config[ra->beam_id]; BWPStart = type0_PDCCH_CSS_config->cset_start_rb; @@ -1296,7 +1260,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2 + sizeof(nfapi_nr_dl_tti_pdcch_pdu)); dl_req->nPDUs += 1; pdcch_pdu_rel15 = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; - nr_configure_pdcch(pdcch_pdu_rel15, coreset, ra_BWP->dl_genericParameters, &ra->sched_pdcch); + nr_configure_pdcch(pdcch_pdu_rel15, coreset, false, &ra->sched_pdcch); nr_mac->pdcch_pdu_idx[CC_id][coresetid] = pdcch_pdu_rel15; } @@ -1344,7 +1308,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra pdsch_pdu_rel15->pduIndex = pduindex; pdsch_pdu_rel15->BWPSize = BWPSize; pdsch_pdu_rel15->BWPStart = BWPStart; - pdsch_pdu_rel15->SubcarrierSpacing = ra_BWP->dl_genericParameters->subcarrierSpacing; + pdsch_pdu_rel15->SubcarrierSpacing = ra_BWP->dl_scs; pdsch_pdu_rel15->CyclicPrefix = 0; pdsch_pdu_rel15->NrOfCodewords = 1; pdsch_pdu_rel15->mcsTable[0] = mcsTableIdx; @@ -1404,7 +1368,8 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra pdsch_pdu_rel15->TBSize[0] = TBS; } - int bw_tbslbrm = get_bw_tbslbrm(ra_BWP->dl_genericParameters, ra->CellGroup); + int scc_bwpsize = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + int bw_tbslbrm = get_bw_tbslbrm(scc_bwpsize, ra->CellGroup); pdsch_pdu_rel15->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(mcsTableIdx, bw_tbslbrm, 1); @@ -1559,8 +1524,8 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra long BWPSize = 0; NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config = NULL; if(*ss->controlResourceSetId!=0) { - BWPStart = NRRIV2PRBOFFSET(ra_BWP->dl_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - BWPSize = NRRIV2BW(ra_BWP->dl_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + BWPStart = ra_BWP->dl_BWPStart; + BWPSize = ra_BWP->dl_BWPSize; } else { type0_PDCCH_CSS_config = &nr_mac->type0_PDCCH_CSS_config[ra->beam_id]; BWPStart = type0_PDCCH_CSS_config->cset_start_rb; @@ -1755,7 +1720,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2 + sizeof(nfapi_nr_dl_tti_pdcch_pdu)); dl_req->nPDUs += 1; pdcch_pdu_rel15 = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; - nr_configure_pdcch(pdcch_pdu_rel15, coreset, ra_BWP->dl_genericParameters, &ra->sched_pdcch); + nr_configure_pdcch(pdcch_pdu_rel15, coreset, false, &ra->sched_pdcch); nr_mac->pdcch_pdu_idx[CC_id][coresetid] = pdcch_pdu_rel15; } @@ -1777,7 +1742,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra pdsch_pdu_rel15->pduIndex = pduindex; pdsch_pdu_rel15->BWPSize = BWPSize; pdsch_pdu_rel15->BWPStart = BWPStart; - pdsch_pdu_rel15->SubcarrierSpacing = ra_BWP->dl_genericParameters->subcarrierSpacing; + pdsch_pdu_rel15->SubcarrierSpacing = ra_BWP->dl_scs; pdsch_pdu_rel15->CyclicPrefix = 0; pdsch_pdu_rel15->NrOfCodewords = 1; int R = nr_get_code_rate_dl(mcsIndex,mcsTableIdx); @@ -1806,7 +1771,8 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra int x_Overhead = 0; nr_get_tbs_dl(&dl_tti_pdsch_pdu->pdsch_pdu, x_Overhead, pdsch_pdu_rel15->numDmrsCdmGrpsNoData, tb_scaling); - int bw_tbslbrm = get_bw_tbslbrm(ra_BWP->dl_genericParameters, ra->CellGroup); + int scc_bwpsize = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + int bw_tbslbrm = get_bw_tbslbrm(scc_bwpsize, ra->CellGroup); pdsch_pdu_rel15->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(mcsTableIdx, bw_tbslbrm, 1); @@ -1972,7 +1938,7 @@ void nr_check_Msg4_Ack(module_id_t module_id, int CC_id, frame_t frame, sub_fram uint32_t delay_ms = servingCellConfig && servingCellConfig->downlinkBWP_ToAddModList ? NR_RRC_SETUP_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_SETUP_DELAY_MS; - sched_ctrl->rrc_processing_timer = (delay_ms << ra->BWP.dl_genericParameters->subcarrierSpacing); + sched_ctrl->rrc_processing_timer = (delay_ms << ra->BWP.dl_scs); LOG_I(NR_MAC, "(%d.%d) Activating RRC processing timer for UE %04x with %d ms\n", frame, slot, UE->rnti, delay_ms); } else { LOG_I(NR_MAC, "(ue rnti 0x%04x) RA Procedure failed at Msg4!\n", ra->rnti); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index e2ceadb889..f3eea60e63 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -452,7 +452,7 @@ void nr_fill_nfapi_dl_sib1_pdu(int Mod_idP, nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; nr_configure_pdcch(pdcch_pdu_rel15, gNB_mac->sched_ctrlCommon->coreset, - NULL, + true, // sib1 &gNB_mac->sched_ctrlCommon->sched_pdcch); nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs]; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index af09571195..8b7da91f63 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -394,8 +394,8 @@ bool allocate_dl_retransmission(module_id_t module_id, const NR_SIB1_t *sib1 = RC.nrmac[module_id]->common_channels[0].sib1 ? RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - const int coresetid = (sched_ctrl->active_bwp||bwpd) ? sched_ctrl->coreset->controlResourceSetId : RC.nrmac[module_id]->sched_ctrlCommon->coreset->controlResourceSetId; - const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : NRRIV2BW(UE->current_BWP.dl_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + const int coresetid = sched_ctrl->coreset->controlResourceSetId; + const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : UE->current_BWP.dl_BWPSize; int rbStart = 0; // start wrt BWPstart NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; @@ -670,14 +670,12 @@ void pf_dl(module_id_t module_id, RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - NR_BWP_t *genericParameters = iterator->UE->current_BWP.dl_genericParameters; + NR_UE_BWP_t *BWP = &iterator->UE->current_BWP; - const int coresetid = (sched_ctrl->active_bwp||bwpd) ? - sched_ctrl->coreset->controlResourceSetId : - RC.nrmac[module_id]->sched_ctrlCommon->coreset->controlResourceSetId; + const int coresetid = sched_ctrl->coreset->controlResourceSetId; const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : - NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + BWP->dl_BWPSize; int rbStart = 0; // start wrt BWPstart if (sched_ctrl->available_dl_harq.head < 0) { @@ -824,18 +822,12 @@ void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength; SLIV2SL(startSymbolAndLength, &startSymbolIndex, &nrOfSymbols); - NR_BWP_t *genericParameters = UE->current_BWP.dl_genericParameters; + NR_UE_BWP_t *BWP = &UE->current_BWP; - NR_BWP_DownlinkDedicated_t *bwpd = - UE->CellGroup && - UE->CellGroup->spCellConfig && - UE->CellGroup->spCellConfig->spCellConfigDedicated ? - UE->CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP : NULL; + const int coresetid = sched_ctrl->coreset->controlResourceSetId; - const int coresetid = (sched_ctrl->active_bwp||bwpd) ? sched_ctrl->coreset->controlResourceSetId : RC.nrmac[module_id]->sched_ctrlCommon->coreset->controlResourceSetId; - - const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : NRRIV2BW(genericParameters->locationAndBandwidth,MAX_BWP_SIZE); - const uint16_t BWPStart = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_start : NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth,MAX_BWP_SIZE); + const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : BWP->dl_BWPSize; + const uint16_t BWPStart = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_start : BWP->dl_BWPStart; const uint16_t slbitmap = SL_to_bitmap(startSymbolIndex, nrOfSymbols); uint16_t *vrb_map = RC.nrmac[module_id]->common_channels[CC_id].vrb_map; @@ -920,12 +912,6 @@ void nr_schedule_ue_spec(module_id_t module_id, UE->mac_stats.dl.current_bytes = 0; NR_CellGroupConfig_t *cg = UE->CellGroup; - NR_BWP_DownlinkDedicated_t *bwpd = - cg && - cg->spCellConfig && - cg->spCellConfig->spCellConfigDedicated ? - cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP : NULL; - /* update TA and set ta_apply every 10 frames. * Possible improvement: take the periodicity from input file. * If such UE is not scheduled now, it will be by the preprocessor later. @@ -999,14 +985,13 @@ void nr_schedule_ue_spec(module_id_t module_id, pucch->ul_slot, sched_pdsch->pucch_allocation, sched_ctrl->tpc1); + NR_BWP_Downlink_t *bwp = sched_ctrl->active_bwp; - NR_BWP_t *genericParameters = current_BWP->dl_genericParameters; - - NR_SearchSpace_t *ss = (bwp||bwpd) ? sched_ctrl->search_space : gNB_mac->sched_ctrlCommon->search_space; + NR_SearchSpace_t *ss = sched_ctrl->search_space; const int bwp_id = current_BWP->dl_bwp_id; - const int coresetid = (bwp||bwpd) ? sched_ctrl->coreset->controlResourceSetId : gNB_mac->sched_ctrlCommon->coreset->controlResourceSetId; + const int coresetid = sched_ctrl->coreset->controlResourceSetId; /* look up the PDCCH PDU for this CC, BWP, and CORESET. If it does not exist, create it */ nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu = gNB_mac->pdcch_pdu_idx[CC_id][coresetid]; @@ -1020,8 +1005,8 @@ void nr_schedule_ue_spec(module_id_t module_id, dl_req->nPDUs += 1; pdcch_pdu = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; LOG_D(NR_MAC,"Trying to configure DL pdcch for UE %04x, bwp %d, cs %d\n", UE->rnti, bwp_id, coresetid); - NR_ControlResourceSet_t *coreset = (bwp||bwpd)? sched_ctrl->coreset:gNB_mac->sched_ctrlCommon->coreset; - nr_configure_pdcch(pdcch_pdu, coreset, genericParameters, &sched_ctrl->sched_pdcch); + NR_ControlResourceSet_t *coreset = sched_ctrl->coreset; + nr_configure_pdcch(pdcch_pdu, coreset, false, &sched_ctrl->sched_pdcch); gNB_mac->pdcch_pdu_idx[CC_id][coresetid] = pdcch_pdu; } @@ -1043,12 +1028,12 @@ void nr_schedule_ue_spec(module_id_t module_id, pdsch_pdu->BWPSize = gNB_mac->cset0_bwp_size; pdsch_pdu->BWPStart = gNB_mac->cset0_bwp_start; } else { - pdsch_pdu->BWPSize = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - pdsch_pdu->BWPStart = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth,MAX_BWP_SIZE); + pdsch_pdu->BWPSize = current_BWP->dl_BWPSize; + pdsch_pdu->BWPStart = current_BWP->dl_BWPStart; } - pdsch_pdu->SubcarrierSpacing = genericParameters->subcarrierSpacing; - pdsch_pdu->CyclicPrefix = genericParameters->cyclicPrefix ? *genericParameters->cyclicPrefix : 0; + pdsch_pdu->SubcarrierSpacing = current_BWP->dl_scs; + pdsch_pdu->CyclicPrefix = current_BWP->dl_cyclicprefix ? *current_BWP->dl_cyclicprefix : 0; // Codeword information pdsch_pdu->NrOfCodewords = 1; //number of information bits per 1024 coded bits expressed in 0.1 bit units @@ -1096,7 +1081,8 @@ void nr_schedule_ue_spec(module_id_t module_id, AssertFatal (maxMIMO_Layers != NULL,"Option with max MIMO layers not configured is not supported\n"); int nl_tbslbrm = *maxMIMO_Layers < 4 ? *maxMIMO_Layers : 4; // Maximum number of PRBs across all configured DL BWPs - int bw_tbslbrm = get_bw_tbslbrm(genericParameters, cg); + int scc_bwpsize = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + int bw_tbslbrm = get_bw_tbslbrm(scc_bwpsize, cg); pdsch_pdu->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(ps->mcsTableIdx, bw_tbslbrm, nl_tbslbrm); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index fa114df5b7..f61fbd6da2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -205,8 +205,8 @@ void nr_preprocessor_phytest(module_id_t module_id, nr_set_pdsch_semi_static(NULL, scc, UE->CellGroup, sched_ctrl->active_bwp, NULL, tda, target_dl_Nl,sched_ctrl , ps); /* find largest unallocated chunk */ - const int bwpSize = NRRIV2BW(BWP->dl_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - const int BWPStart = NRRIV2PRBOFFSET(BWP->dl_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + const int bwpSize = BWP->dl_BWPSize; + const int BWPStart = BWP->dl_BWPStart; int rbStart = 0; int rbSize = 0; @@ -353,8 +353,7 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_BWP_t *BWP = &UE->current_BWP; - NR_BWP_t *genericParameters = BWP->ul_genericParameters; - const int mu = genericParameters->subcarrierSpacing; + const int mu = BWP->ul_scs; const struct NR_PUSCH_TimeDomainResourceAllocationList *tdaList = sched_ctrl->active_ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; @@ -402,8 +401,8 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ uint16_t rbStart = 0; uint16_t rbSize; - const int bw = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - const int BWPStart = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + const int bw = BWP->ul_BWPSize; + const int BWPStart = BWP->ul_BWPStart; if (target_ul_bw>bw) rbSize = bw; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 45be14c622..7909f192b2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -983,10 +983,8 @@ void config_uldci(const NR_SIB1_t *sib1, int bwp_id = BWP->ul_bwp_id; - const int bw = NRRIV2BW(BWP->ul_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - dci_pdu_rel15->frequency_domain_assignment.val = - PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size, pusch_pdu->rb_start, bw); + PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size, pusch_pdu->rb_start, BWP->ul_BWPSize); dci_pdu_rel15->time_domain_assignment.val = time_domain_assignment; dci_pdu_rel15->frequency_hopping_flag.val = pusch_pdu->frequency_hopping; dci_pdu_rel15->mcs = pusch_pdu->mcs_index; @@ -1063,7 +1061,7 @@ int nr_get_default_pucch_res(int pucch_ResourceCommon) { void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, NR_ControlResourceSet_t *coreset, - NR_BWP_t *bwp, + bool is_sib1, NR_sched_pdcch_t *pdcch) { @@ -1087,7 +1085,7 @@ void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, pdcch_pdu->ShiftIndex = pdcch->ShiftIndex; if(coreset->controlResourceSetId == 0) { - if(bwp == NULL) + if(is_sib1) pdcch_pdu->CoreSetType = NFAPI_NR_CSET_CONFIG_MIB_SIB1; else pdcch_pdu->CoreSetType = NFAPI_NR_CSET_CONFIG_PDCCH_CONFIG_CSET_0; @@ -1193,12 +1191,12 @@ void nr_configure_pucch(const NR_SIB1_t *sib1, else pucch_pdu->hopping_id = *scc->physCellId; - NR_BWP_t *genericParameters = UE->current_BWP.ul_genericParameters; + NR_UE_BWP_t *BWP = &UE->current_BWP; - pucch_pdu->bwp_size = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - pucch_pdu->bwp_start = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth,MAX_BWP_SIZE); - pucch_pdu->subcarrier_spacing = genericParameters->subcarrierSpacing; - pucch_pdu->cyclic_prefix = (genericParameters->cyclicPrefix==NULL) ? 0 : *genericParameters->cyclicPrefix; + pucch_pdu->bwp_size = BWP->ul_BWPSize; + pucch_pdu->bwp_start = BWP->ul_BWPStart; + pucch_pdu->subcarrier_spacing = BWP->ul_scs; + pucch_pdu->cyclic_prefix = (BWP->ul_cyclicprefix==NULL) ? 0 : *BWP->ul_cyclicprefix; if (r_pucch<0 || bwp ){ LOG_D(NR_MAC,"pucch_acknak: Filling dedicated configuration for PUCCH\n"); // we have either a dedicated BWP or Dedicated PUCCH configuration on InitialBWP @@ -2322,6 +2320,7 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, NR_UE_BWP_t *BWP, NR_ServingCellConfigCommon_t *scc, NR_UE_sched_ctrl_t *sched_ctrl, + NR_RA_t *ra, NR_CellGroupConfig_t *CellGroup) { NR_BWP_Downlink_t *dl_bwp = NULL; @@ -2384,16 +2383,27 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, target_ss = NR_SearchSpace__searchSpaceType_PR_common; } - // acquiring generic parameters - BWP->dl_genericParameters = (BWP->dl_bwp_id>0 && dl_bwp) ? - &dl_bwp->bwp_Common->genericParameters: - &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; + // setting generic parameters + NR_BWP_t dl_genericParameters = (BWP->dl_bwp_id>0 && dl_bwp) ? + dl_bwp->bwp_Common->genericParameters: + scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; - BWP->ul_genericParameters = (BWP->ul_bwp_id>0 && ul_bwp) ? - &ul_bwp->bwp_Common->genericParameters: - &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; + BWP->dl_scs = dl_genericParameters.subcarrierSpacing; + BWP->dl_cyclicprefix = dl_genericParameters.cyclicPrefix; + BWP->dl_BWPSize = NRRIV2BW(dl_genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + BWP->dl_BWPStart = NRRIV2PRBOFFSET(dl_genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + + NR_BWP_t ul_genericParameters = (BWP->ul_bwp_id>0 && ul_bwp) ? + ul_bwp->bwp_Common->genericParameters: + scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; + + BWP->ul_scs = ul_genericParameters.subcarrierSpacing; + BWP->ul_cyclicprefix = ul_genericParameters.cyclicPrefix; + BWP->ul_BWPSize = NRRIV2BW(ul_genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + BWP->ul_BWPStart = NRRIV2PRBOFFSET(ul_genericParameters.locationAndBandwidth, MAX_BWP_SIZE); if(sched_ctrl) { + // setting PDCCH related structures for sched_ctrl sched_ctrl->search_space = get_searchspace(scc, bwpd, target_ss); @@ -2407,9 +2417,37 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, sched_ctrl->search_space, sched_ctrl->coreset, scc, - BWP->dl_genericParameters, + &dl_genericParameters, nr_mac->type0_PDCCH_CSS_config); } + + if(ra) { + // setting PDCCH related structures for RA + struct NR_PDCCH_ConfigCommon__commonSearchSpaceList *commonSearchSpaceList = NULL; + NR_SearchSpaceId_t ra_SearchSpace = 0; + if(dl_bwp) { + commonSearchSpaceList = dl_bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList; + ra_SearchSpace = *dl_bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->ra_SearchSpace; + } else { + commonSearchSpaceList = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList; + ra_SearchSpace = *scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->ra_SearchSpace; + } + AssertFatal(commonSearchSpaceList->list.count > 0, "common SearchSpace list has 0 elements\n"); + for (int i = 0; i < commonSearchSpaceList->list.count; i++) { + NR_SearchSpace_t * ss = commonSearchSpaceList->list.array[i]; + if (ss->searchSpaceId == ra_SearchSpace) + ra->ra_ss = ss; + } + AssertFatal(ra->ra_ss!=NULL,"SearchSpace cannot be null for RA\n"); + + ra->coreset = get_coreset(nr_mac, scc, dl_bwp, ra->ra_ss, NR_SearchSpace__searchSpaceType_PR_common); + ra->sched_pdcch = set_pdcch_structure(nr_mac, + ra->ra_ss, + ra->coreset, + scc, + &dl_genericParameters, + &nr_mac->type0_PDCCH_CSS_config[ra->beam_id]); + } } //------------------------------------------------------------------------------ @@ -2462,7 +2500,7 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf // initialize UE BWP information NR_UE_BWP_t *BWP = &UE->current_BWP; memset(BWP, 0, sizeof(*BWP)); - configure_UE_BWP(nr_mac, BWP, scc, sched_ctrl, CellGroup); + configure_UE_BWP(nr_mac, BWP, scc, sched_ctrl, NULL, CellGroup); /* set illegal time domain allocation to force recomputation of all fields */ sched_ctrl->pdsch_semi_static.time_domain_allocation = -1; @@ -2719,7 +2757,6 @@ void nr_csirs_scheduling(int Mod_idP, int period, offset; nfapi_nr_dl_tti_request_body_t *dl_req = &gNB_mac->DL_req[CC_id].dl_tti_request_body; - NR_BWP_t *genericParameters = BWP->dl_genericParameters; for (int id = 0; id < csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.count; id++){ nzpcsi = csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.array[id]; @@ -2738,22 +2775,20 @@ void nr_csirs_scheduling(int Mod_idP, nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *csirs_pdu_rel15 = &dl_tti_csirs_pdu->csi_rs_pdu.csi_rs_pdu_rel15; - csirs_pdu_rel15->subcarrier_spacing = genericParameters->subcarrierSpacing; - if (genericParameters->cyclicPrefix) - csirs_pdu_rel15->cyclic_prefix = *genericParameters->cyclicPrefix; + csirs_pdu_rel15->subcarrier_spacing = BWP->dl_scs; + if (BWP->dl_cyclicprefix) + csirs_pdu_rel15->cyclic_prefix = *BWP->dl_cyclicprefix; else csirs_pdu_rel15->cyclic_prefix = 0; // According to last paragraph of TS 38.214 5.2.2.3.1 - uint16_t BWPSize = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - uint16_t BWPStart = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - if (resourceMapping.freqBand.startingRB < BWPStart) { - csirs_pdu_rel15->start_rb = BWPStart; + if (resourceMapping.freqBand.startingRB < BWP->dl_BWPStart) { + csirs_pdu_rel15->start_rb = BWP->dl_BWPStart; } else { csirs_pdu_rel15->start_rb = resourceMapping.freqBand.startingRB; } - if (resourceMapping.freqBand.nrofRBs > (BWPStart + BWPSize - csirs_pdu_rel15->start_rb)) { - csirs_pdu_rel15->nr_of_rbs = BWPStart + BWPSize - csirs_pdu_rel15->start_rb; + if (resourceMapping.freqBand.nrofRBs > (BWP->dl_BWPStart + BWP->dl_BWPSize - csirs_pdu_rel15->start_rb)) { + csirs_pdu_rel15->nr_of_rbs = BWP->dl_BWPStart + BWP->dl_BWPSize - csirs_pdu_rel15->start_rb; } else { csirs_pdu_rel15->nr_of_rbs = resourceMapping.freqBand.nrofRBs; } @@ -2961,7 +2996,7 @@ void nr_mac_update_timers(module_id_t module_id, } } - configure_UE_BWP(RC.nrmac[module_id], BWP, scc, sched_ctrl, UE->CellGroup); + configure_UE_BWP(RC.nrmac[module_id], BWP, scc, sched_ctrl, NULL, UE->CellGroup); // Update coreset/searchspace NR_BWP_Downlink_t *bwp = sched_ctrl->active_bwp; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index fe07925e3a..4397686c64 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -38,13 +38,11 @@ void nr_configure_srs(nfapi_nr_srs_pdu_t *srs_pdu, int module_id, int CC_id,NR_U NR_UE_BWP_t *current_BWP = &UE->current_BWP; - NR_BWP_t *ubwp = current_BWP->ul_genericParameters; - srs_pdu->rnti = UE->rnti; srs_pdu->handle = 0; - srs_pdu->bwp_size = NRRIV2BW(ubwp->locationAndBandwidth, MAX_BWP_SIZE);; - srs_pdu->bwp_start = NRRIV2PRBOFFSET(ubwp->locationAndBandwidth, MAX_BWP_SIZE);; - srs_pdu->subcarrier_spacing = ubwp->subcarrierSpacing; + srs_pdu->bwp_size = current_BWP->ul_BWPSize; + srs_pdu->bwp_start = current_BWP->ul_BWPStart; + srs_pdu->subcarrier_spacing = current_BWP->ul_scs; srs_pdu->cyclic_prefix = 0; srs_pdu->num_ant_ports = srs_resource->nrofSRS_Ports; srs_pdu->num_symbols = srs_resource->resourceMapping.nrofSymbols; @@ -162,7 +160,7 @@ void nr_schedule_srs(int module_id, frame_t frame) { uint16_t period = srs_period[srs_resource->resourceType.choice.periodic->periodicityAndOffset_p.present]; uint16_t offset = get_nr_srs_offset(srs_resource->resourceType.choice.periodic->periodicityAndOffset_p); - int n_slots_frame = nr_slots_per_frame[current_BWP->ul_genericParameters->subcarrierSpacing]; + int n_slots_frame = nr_slots_per_frame[current_BWP->ul_scs]; // Check if UE will transmit the SRS in this frame if ( ((frame - offset/n_slots_frame)*n_slots_frame)%period == 0) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 9d31135666..b5472542f9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -695,14 +695,11 @@ void nr_csi_meas_reporting(int Mod_idP, frame_t frame, sub_frame_t slot) { - NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon; - const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; - - UE_iterator(RC.nrmac[Mod_idP]->UE_info.list, UE ) { const NR_CellGroupConfig_t *CellGroup = UE->CellGroup; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_BWP_t *BWP = &UE->current_BWP; + const int n_slots_frame = nr_slots_per_frame[BWP->ul_scs]; if ((sched_ctrl->rrc_processing_timer > 0) || (sched_ctrl->ul_failure==1 && get_softmodem_params()->phy_test==0)) { continue; } @@ -761,7 +758,7 @@ void nr_csi_meas_reporting(int Mod_idP, curr_pucch->resource_indicator = res_index; curr_pucch->csi_bits += nr_get_csi_bitlen(UE,csi_report_id); - int bwp_start = NRRIV2PRBOFFSET(BWP->ul_genericParameters->locationAndBandwidth,MAX_BWP_SIZE); + int bwp_start = BWP->ul_BWPStart; // going through the list of PUCCH resources to find the one indexed by resource_id uint16_t *vrb_map_UL = &RC.nrmac[Mod_idP]->common_channels[0].vrb_map_UL[sched_slot * MAX_BWP_SIZE]; @@ -1313,11 +1310,12 @@ void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig, NR_ServingCellConfigCommon_t *scc) { /** From Table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel */ - const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; uint8_t *payload = uci_pdu->csi_part1.csi_part1_payload; uint16_t bitlen = uci_pdu->csi_part1.csi_part1_bit_len; NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type = NR_CSI_ReportConfig__reportQuantity_PR_NOTHING; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_UE_BWP_t *BWP = &UE->current_BWP; + const int n_slots_frame = nr_slots_per_frame[BWP->ul_scs]; int cumul_bits = 0; int r_index = -1; for (int csi_report_id = 0; csi_report_id < csi_MeasConfig->csi_ReportConfigToAddModList->list.count; csi_report_id++ ) { @@ -1607,7 +1605,8 @@ int nr_acknack_scheduling(int mod_id, const int CC_id = 0; const int minfbtime = RC.nrmac[mod_id]->minRXTXTIMEpdsch; const NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels[CC_id].ServingCellConfigCommon; - const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; + NR_UE_BWP_t *BWP = &UE->current_BWP; + const int n_slots_frame = nr_slots_per_frame[BWP->ul_scs]; const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; AssertFatal(tdd || RC.nrmac[mod_id]->common_channels[CC_id].frame_type == FDD, "Dynamic TDD not handled yet\n"); const int nr_slots_period = tdd ? n_slots_frame / get_nb_periods_per_frame(tdd->dl_UL_TransmissionPeriodicity) : n_slots_frame; @@ -1622,7 +1621,6 @@ int nr_acknack_scheduling(int mod_id, * later) * * each UE has dedicated PUCCH Format 0 resources, and we use index 0! */ NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_BWP_t *BWP = &UE->current_BWP; NR_CellGroupConfig_t *cg = UE->CellGroup; NR_PUCCH_Config_t *pucch_Config = NULL; @@ -1636,8 +1634,8 @@ int nr_acknack_scheduling(int mod_id, pucch_Config = cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pucch_Config->choice.setup; } - int bwp_start = NRRIV2PRBOFFSET(BWP->ul_genericParameters->locationAndBandwidth,MAX_BWP_SIZE); - int bwp_size = NRRIV2BW(BWP->ul_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + int bwp_start = BWP->ul_BWPStart; + int bwp_size = BWP->ul_BWPSize; NR_sched_pucch_t *pucch = &sched_ctrl->sched_pucch[0]; LOG_D(NR_MAC, "In %s: %4d.%2d Trying to allocate pucch, current DAI %d\n", __FUNCTION__, frame, slot, pucch->dai_c); @@ -1692,19 +1690,11 @@ int nr_acknack_scheduling(int mod_id, LOG_D(NR_MAC, "In %s: pucch_acknak 1. DL %4d.%2d, UL_ACK %4d.%2d, DAI_C %d\n", __FUNCTION__, frame, slot, pucch->frame, pucch->ul_slot, pucch->dai_c); - // this is hardcoded for now as ue specific only if we are not on the initialBWP (to be fixed to allow ue_Specific also on initialBWP - NR_BWP_UplinkDedicated_t *ubwpd=NULL; + NR_SearchSpace__searchSpaceType_PR ss_type = NR_SearchSpace__searchSpaceType_PR_common; + if(is_common == 0) + ss_type = sched_ctrl->search_space->searchSpaceType->present; - if (cg && - cg->spCellConfig && - cg->spCellConfig->spCellConfigDedicated && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) - ubwpd = cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; - - NR_SearchSpace__searchSpaceType_PR ss_type = (is_common==0 && (sched_ctrl->active_bwp || ubwpd)) ? NR_SearchSpace__searchSpaceType_PR_ue_Specific: NR_SearchSpace__searchSpaceType_PR_common; uint8_t pdsch_to_harq_feedback[8]; - int max_fb_time = 0; get_pdsch_to_harq_feedback(UE, ss_type, &max_fb_time, pdsch_to_harq_feedback); @@ -1727,7 +1717,6 @@ int nr_acknack_scheduling(int mod_id, // we cannot reach this timing anymore, allocate and try again const int f = pucch->frame; const int s = pucch->ul_slot; - const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; LOG_D(NR_MAC, "In %s: %4d.%2d DAI > 0, cannot reach timing for pucch in %4d.%2d, advancing slot by 1 and trying again\n", __FUNCTION__, frame, slot, f, s); if (!(csi_pucch && csi_pucch->csi_bits > 0 && @@ -1890,11 +1879,11 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, sub_frame_t slot) { if (!is_xlsch_in_slot(nrmac->ulsch_slot_bitmap[slot / 64], slot)) return; - NR_ServingCellConfigCommon_t *scc = nrmac->common_channels->ServingCellConfigCommon; - const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; + UE_iterator(nrmac->UE_info.list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - + NR_UE_BWP_t *BWP = &UE->current_BWP; + const int n_slots_frame = nr_slots_per_frame[BWP->ul_scs]; if (sched_ctrl->ul_failure==1) continue; NR_PUCCH_Config_t *pucch_Config = NULL; if (sched_ctrl->active_ubwp) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 45c0f1b1e1..5106715b47 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -847,9 +847,9 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; int rbStart = 0; // wrt BWP start - const uint16_t bwpSize = NRRIV2BW(UE->current_BWP.ul_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + const uint16_t bwpSize = UE->current_BWP.ul_BWPSize; const uint8_t nrOfLayers = 1; - const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_bwp || ubwpd) ? 1 : 2; + const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_ubwp || ubwpd) ? 1 : 2; LOG_D(NR_MAC,"retInfo->time_domain_allocation = %d, tda = %d\n", retInfo->time_domain_allocation, tda); LOG_D(NR_MAC,"num_dmrs_cdm_grps_no_data %d, tbs %d\n",num_dmrs_cdm_grps_no_data, retInfo->tb_size); if (tda == retInfo->time_domain_allocation) { @@ -1045,7 +1045,7 @@ void pf_ul(module_id_t module_id, cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; - const uint16_t bwpSize = NRRIV2BW(BWP->ul_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + const uint16_t bwpSize = BWP->ul_BWPSize; NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; const NR_mac_dir_stats_t *stats = &UE->mac_stats.ul; @@ -1242,8 +1242,8 @@ void pf_ul(module_id_t module_id, cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; - int rbStart = sched_ctrl->active_ubwp ? NRRIV2PRBOFFSET(BWP->ul_genericParameters->locationAndBandwidth, MAX_BWP_SIZE) : 0; - const uint16_t bwpSize = NRRIV2BW(BWP->ul_genericParameters->locationAndBandwidth, MAX_BWP_SIZE); + int rbStart = sched_ctrl->active_ubwp ? BWP->ul_BWPStart : 0; + const uint16_t bwpSize = BWP->ul_BWPSize; NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; @@ -1348,8 +1348,7 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t * schedule now (slot + k2 is not UL slot) */ NR_UE_sched_ctrl_t *sched_ctrl = &nr_mac->UE_info.list[0]->UE_sched_ctrl; NR_UE_BWP_t *BWP = &nr_mac->UE_info.list[0]->current_BWP; - NR_BWP_t *genericParameters = BWP->ul_genericParameters; - int mu = genericParameters->subcarrierSpacing; + int mu = BWP->ul_scs; const int temp_tda = get_ul_tda(nr_mac, scc, slot); int K2 = get_K2(scc, scc_sib1, sched_ctrl->active_ubwp, temp_tda, mu); const int sched_frame = (frame + (slot + K2 >= nr_slots_per_frame[mu])) & 1023; @@ -1399,8 +1398,8 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t uint16_t *vrb_map_UL = &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[sched_slot * MAX_BWP_SIZE]; - const uint16_t bwpSize = NRRIV2BW(genericParameters->locationAndBandwidth,MAX_BWP_SIZE); - const uint16_t bwpStart = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth,MAX_BWP_SIZE); + const uint16_t bwpSize = BWP->ul_BWPSize; + const uint16_t bwpStart = BWP->ul_BWPStart; NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList = NULL; if (sched_ctrl->active_ubwp) { @@ -1642,11 +1641,10 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) pusch_pdu->handle = 0; //not yet used /* FAPI: BWP */ - NR_BWP_t *genericParameters = current_BWP->ul_genericParameters; - pusch_pdu->bwp_size = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - pusch_pdu->bwp_start = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); - pusch_pdu->subcarrier_spacing = genericParameters->subcarrierSpacing; + pusch_pdu->bwp_size = current_BWP->ul_BWPSize; + pusch_pdu->bwp_start = current_BWP->ul_BWPStart; + pusch_pdu->subcarrier_spacing = current_BWP->ul_scs; pusch_pdu->cyclic_prefix = 0; /* FAPI: PUSCH information always included */ @@ -1750,8 +1748,8 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) /* look up the PDCCH PDU for this BWP and CORESET. If it does not exist, * create it */ - NR_SearchSpace_t *ss = (sched_ctrl->active_bwp || ubwpd) ? sched_ctrl->search_space: RC.nrmac[module_id]->sched_ctrlCommon->search_space; - NR_ControlResourceSet_t *coreset = (sched_ctrl->active_bwp || ubwpd) ? sched_ctrl->coreset: RC.nrmac[module_id]->sched_ctrlCommon->coreset; + NR_SearchSpace_t *ss = sched_ctrl->search_space; + NR_ControlResourceSet_t *coreset = sched_ctrl->coreset; const int coresetid = coreset->controlResourceSetId; nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu = pdcch_pdu_coreset[coresetid]; if (!pdcch_pdu) { @@ -1761,7 +1759,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) ul_dci_request_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); pdcch_pdu = &ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15; ul_dci_req->numPdus += 1; - nr_configure_pdcch(pdcch_pdu, coreset, genericParameters, &sched_ctrl->sched_pdcch); + nr_configure_pdcch(pdcch_pdu, coreset, false, &sched_ctrl->sched_pdcch); pdcch_pdu_coreset[coresetid] = pdcch_pdu; } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index f880b8e709..74e6884802 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -271,7 +271,7 @@ void find_search_space(int ss_type, void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, NR_ControlResourceSet_t *coreset, - NR_BWP_t *bwp, + bool is_sib1, NR_sched_pdcch_t *pdcch); NR_sched_pdcch_t set_pdcch_structure(gNB_MAC_INST *gNB_mac, @@ -399,6 +399,7 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, NR_UE_BWP_t *BWP, NR_ServingCellConfigCommon_t *scc, NR_UE_sched_ctrl_t *sched_ctrl, + NR_RA_t *ra, NR_CellGroupConfig_t *CellGroup); NR_UE_info_t* add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConfig_t *CellGroup); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 914f9b7052..cf2e6be635 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -94,8 +94,14 @@ typedef struct { typedef struct NR_UE_BWP { NR_BWP_Id_t dl_bwp_id; NR_BWP_Id_t ul_bwp_id; - NR_BWP_t *dl_genericParameters; - NR_BWP_t *ul_genericParameters; + int dl_scs; + int ul_scs; + long *dl_cyclicprefix; + long *ul_cyclicprefix; + uint16_t dl_BWPSize; + uint16_t dl_BWPStart; + uint16_t ul_BWPSize; + uint16_t ul_BWPStart; } NR_UE_BWP_t; typedef enum { From e32d55dff9eef4f945a0e27a09b94270557e4252 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Mon, 13 Jun 2022 11:30:37 +0100 Subject: [PATCH 131/267] Update the feature set for the UE --- doc/FEATURE_SET.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md index d0856b415d..5db6e44d8d 100644 --- a/doc/FEATURE_SET.md +++ b/doc/FEATURE_SET.md @@ -440,6 +440,10 @@ The following features are valid for the gNB and the 5G-NR UE. - PTRS support - Support for 1, 2 and 4 RX antennas - Support for up to 2 layers (currently limited to DMRS configuration type 2) +* Measurements based on NR-CSIRS + - RI, PMI and CQI computation + - Support for 1 and 2 RX antennas + - Support for up to 2 layers * NR-PUSCH (including Segmentation, LDPC encoding, rate matching, scrambling, modulation, RB mapping, etc). - PUSCH mapping type A and B - DMRS configuration type 1 and 2 @@ -488,12 +492,15 @@ The following features are valid for the gNB and the 5G-NR UE. * UCI processing - ACK/NACK processing - Triggering periodic SR - - CSI measurement reporting (SSB RSRP only) -* DLSH scheduler + - CSI measurement reporting +* DLSCH scheduler - Configuration of fapi PDU according to DCI - HARQ procedures * ULSCH scheduler - Configuration of fapi PDU according to DCI +* NR-CSIRS scheduler + - Scheduling of NR-CSIRS reception + - Fill UCI for CSI measurement reporting * Scheduler procedures for SRS transmission - Periodic SRS transmission * Bandwidth part (BWP) operation From 33b69bdf304451fc2942548524b55d710b085a5b Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 13 Jun 2022 18:28:07 +0200 Subject: [PATCH 132/267] nr rlc: bugfix: use hard-coded mapping between drb ID and mac lcid This will probably impact negatively the Accelleran interoperability but the previous version is not correct and breaks the oai nr ue. To be checked in a CU/DU scenario with Accelleran. --- openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index 29aed5d042..4bd4ea75fd 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -165,7 +165,7 @@ void mac_rlc_data_ind ( switch (channel_idP) { case 1 ... 3: rb = ue->srb[channel_idP - 1]; break; - case 4 ... 8: rb = ue->drb[channel_idP - 1]; break; + case 4 ... 8: rb = ue->drb[channel_idP - 4]; break; default: rb = NULL; break; } @@ -206,7 +206,7 @@ tbs_size_t mac_rlc_data_req( switch (channel_idP) { case 1 ... 3: rb = ue->srb[channel_idP - 1]; break; - case 4 ... 8: rb = ue->drb[channel_idP - 1]; break; + case 4 ... 8: rb = ue->drb[channel_idP - 4]; break; default: rb = NULL; LOG_E(RLC, "In %s:%d:%s: data request for unknown RB with LCID 0x%02x !\n", __FILE__, __LINE__, __FUNCTION__, channel_idP); @@ -254,7 +254,7 @@ mac_rlc_status_resp_t mac_rlc_status_ind( switch (channel_idP) { case 1 ... 3: rb = ue->srb[channel_idP - 1]; break; - case 4 ... 8: rb = ue->drb[channel_idP - 1]; break; + case 4 ... 8: rb = ue->drb[channel_idP - 4]; break; default: rb = NULL; break; } @@ -317,7 +317,7 @@ rlc_buffer_occupancy_t mac_rlc_get_buffer_occupancy_ind( switch (channel_idP) { case 1 ... 3: rb = ue->srb[channel_idP - 1]; break; - case 4 ... 8: rb = ue->drb[channel_idP - 1]; break; //4 + case 4 ... 8: rb = ue->drb[channel_idP - 4]; break; default: rb = NULL; break; } @@ -410,7 +410,7 @@ int nr_rlc_get_available_tx_space( switch (channel_idP) { case 1 ... 3: rb = ue->srb[channel_idP - 1]; break; - case 4 ... 8: rb = ue->drb[channel_idP - 1]; break; + case 4 ... 8: rb = ue->drb[channel_idP - 4]; break; default: rb = NULL; break; } @@ -780,7 +780,7 @@ static void add_drb_am(int rnti, struct NR_DRB_ToAddMod *s, NR_RLC_BearerConfig_ struct NR_RLC_Config *r = rlc_BearerConfig->rlc_Config; struct NR_LogicalChannelConfig *l = rlc_BearerConfig->mac_LogicalChannelConfig; int drb_id = s->drb_Identity; - //int channel_id = rlc_BearerConfig->logicalChannelIdentity; + int channel_id = rlc_BearerConfig->logicalChannelIdentity; int logical_channel_group; int t_status_prohibit; @@ -797,11 +797,11 @@ static void add_drb_am(int rnti, struct NR_DRB_ToAddMod *s, NR_RLC_BearerConfig_ exit(1); } - /*if (channel_id != drb_id + 3) { + if (channel_id != drb_id + 3) { LOG_E(RLC, "%s:%d:%s: todo, remove this limitation\n", __FILE__, __LINE__, __FUNCTION__); exit(1); - }*/ + } logical_channel_group = *l->ul_SpecificParameters->logicalChannelGroup; @@ -874,11 +874,11 @@ static void add_drb_um(int rnti, struct NR_DRB_ToAddMod *s, NR_RLC_BearerConfig_ exit(1); } - /*if (channel_id != drb_id + 3) { + if (channel_id != drb_id + 3) { LOG_E(RLC, "%s:%d:%s: todo, remove this limitation\n", __FILE__, __LINE__, __FUNCTION__); exit(1); - }*/ + } logical_channel_group = *l->ul_SpecificParameters->logicalChannelGroup; From 1be8caaf696feaad236a8d4bae22aeb39b7dbcea Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 14 Jun 2022 18:15:42 +0200 Subject: [PATCH 133/267] removing dl active_bwp --- openair1/SIMULATION/NR_PHY/dlsim.c | 11 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 82 +++++--------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 1 + .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 57 ++-------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 7 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 105 ++++++------------ .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 33 +++--- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 1 + openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 11 +- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 5 +- 10 files changed, 101 insertions(+), 212 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index d0b422dc74..b5f946b8ab 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -272,25 +272,22 @@ void nr_dlsim_preprocessor(module_id_t module_id, NR_UE_info_t *UE_info = RC.nrmac[module_id]->UE_info.list[0]; AssertFatal(RC.nrmac[module_id]->UE_info.list[1]==NULL, "can have only a single UE\n"); NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl; + NR_UE_BWP_t *BWP = &UE_info->current_BWP; NR_ServingCellConfigCommon_t *scc = RC.nrmac[0]->common_channels[0].ServingCellConfigCommon; /* manually set free CCE to 0 */ - const int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; - sched_ctrl->search_space = get_searchspace(scc, sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Dedicated : NULL, target_ss); + uint8_t nr_of_candidates; find_aggregation_candidates(&sched_ctrl->aggregation_level, &nr_of_candidates, sched_ctrl->search_space,4); - sched_ctrl->coreset = get_coreset(RC.nrmac[module_id], scc, sched_ctrl->active_bwp->bwp_Dedicated, sched_ctrl->search_space, target_ss); sched_ctrl->cce_index = 0; NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; - nr_set_pdsch_semi_static(NULL, + nr_set_pdsch_semi_static(BWP, scc, UE_info->CellGroup, - sched_ctrl->active_bwp, - NULL, /* tda = */ 0, g_nrOfLayers, sched_ctrl, @@ -838,6 +835,8 @@ int main(int argc, char **argv) N_RB_DL = gNB->frame_parms.N_RB_DL; NR_UE_info_t *UE_info = RC.nrmac[0]->UE_info.list[0]; + configure_UE_BWP(RC.nrmac[0], &UE_info->current_BWP, scc, &UE_info->UE_sched_ctrl, NULL, UE_info->CellGroup); + // stub to configure frame_parms // nr_phy_config_request_sim(gNB,N_RB_DL,N_RB_DL,mu,Nid_cell,SSB_positions); // call MAC to configure common parameters diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 05fcfb0e04..1bbbc6ac85 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -850,6 +850,7 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t fill_dci_pdu_rel15(scc, ra->CellGroup, + ra_BWP, dci_pdu, &uldci_payload, NR_UL_DCI_FORMAT_0_0, @@ -1164,21 +1165,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; NR_SearchSpace_t *ss = ra->ra_ss; - NR_BWP_Downlink_t *bwp = NULL; - NR_ControlResourceSet_t *coreset = NULL; - NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList=NULL; - - if (ra->CellGroup && - ra->CellGroup->spCellConfig && - ra->CellGroup->spCellConfig->spCellConfigDedicated && - ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList && - ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra_BWP->dl_bwp_id-1]) { - bwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra_BWP->dl_bwp_id-1]; - pdsch_TimeDomainAllocationList = bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; - } - else { - pdsch_TimeDomainAllocationList = scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; - } + NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList = ra_BWP->tdaList; long BWPStart = 0; long BWPSize = 0; @@ -1199,7 +1186,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra SLIV2SL(startSymbolAndLength, &startSymbolIndex, &nrOfSymbols); AssertFatal(startSymbolIndex >= 0, "StartSymbolIndex is negative\n"); - coreset = ra->coreset; + NR_ControlResourceSet_t *coreset = ra->coreset; AssertFatal(coreset!=NULL,"Coreset cannot be null for RA-Msg2\n"); @@ -1278,13 +1265,11 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra // information to data and is reset every slot. const int pduindex = nr_mac->pdu_index[CC_id]++; + NR_PDSCH_Config_t *pdsch_Config = ra_BWP->pdsch_Config; uint8_t mcsTableIdx = 0; - if (bwp && - bwp->bwp_Dedicated && - bwp->bwp_Dedicated->pdsch_Config && - bwp->bwp_Dedicated->pdsch_Config->choice.setup && - bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table) { - if (*bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table == 0) + if (pdsch_Config && + pdsch_Config->mcs_Table) { + if (*pdsch_Config->mcs_Table == 0) mcsTableIdx = 1; else mcsTableIdx = 2; @@ -1292,17 +1277,12 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra else mcsTableIdx = 0; int dmrsConfigType=0; - if (bwp && - bwp->bwp_Dedicated && - bwp->bwp_Dedicated->pdsch_Config && - bwp->bwp_Dedicated->pdsch_Config->choice.setup && - bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA && - bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup && - bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type) + if (pdsch_Config && + pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA && + pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup && + pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type) dmrsConfigType = 1; - NR_PDSCH_Config_t *pdsch_config = bwp && bwp->bwp_Dedicated && bwp->bwp_Dedicated->pdsch_Config ? bwp->bwp_Dedicated->pdsch_Config->choice.setup : NULL; - pdsch_pdu_rel15->pduBitmap = 0; pdsch_pdu_rel15->rnti = ra->RA_rnti; pdsch_pdu_rel15->pduIndex = pduindex; @@ -1328,7 +1308,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra pdsch_pdu_rel15->VRBtoPRBMapping = 0; pdsch_pdu_rel15->StartSymbolIndex = startSymbolIndex; pdsch_pdu_rel15->NrOfSymbols = nrOfSymbols; - pdsch_pdu_rel15->dlDmrsSymbPos = fill_dmrs_mask(pdsch_config, + pdsch_pdu_rel15->dlDmrsSymbPos = fill_dmrs_mask(pdsch_Config, nr_mac->common_channels->ServingCellConfigCommon->dmrs_TypeA_Position, nrOfSymbols, startSymbolIndex, @@ -1421,6 +1401,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra fill_dci_pdu_rel15(scc, ra->CellGroup, + ra_BWP, &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci - 1], &dci_payload, NR_DL_DCI_FORMAT_1_0, @@ -1485,23 +1466,8 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; NR_SearchSpace_t *ss = ra->ra_ss; - NR_BWP_Downlink_t *bwp = NULL; - NR_ControlResourceSet_t *coreset = NULL; - NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList=NULL; - - if (ra->CellGroup && - ra->CellGroup->spCellConfig && - ra->CellGroup->spCellConfig->spCellConfigDedicated && - ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList && - ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra_BWP->dl_bwp_id-1]) { - bwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra_BWP->dl_bwp_id-1]; - pdsch_TimeDomainAllocationList = bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; - } - else { - pdsch_TimeDomainAllocationList = scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; - } - - coreset = ra->coreset; + NR_ControlResourceSet_t *coreset = ra->coreset; + NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList = ra_BWP->tdaList; AssertFatal(coreset!=NULL,"Coreset cannot be null for RA-Msg4\n"); @@ -1635,7 +1601,13 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra uint16_t N_DMRS_SLOT = get_num_dmrs(dlDmrsSymbPos); - long dmrsConfigType = bwp!=NULL ? (bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type == NULL ? 0 : 1) : 0; + NR_PDSCH_Config_t *pdsch_Config = ra_BWP->pdsch_Config; + int dmrsConfigType=0; + if (pdsch_Config && + pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA && + pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup && + pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type) + dmrsConfigType = 1; nr_mac->sched_ctrlCommon->pdsch_semi_static.numDmrsCdmGrpsNoData = 2; if (nrOfSymbols == 2) { @@ -1656,12 +1628,9 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra } uint8_t mcsTableIdx = 0; - if (bwp && - bwp->bwp_Dedicated && - bwp->bwp_Dedicated->pdsch_Config && - bwp->bwp_Dedicated->pdsch_Config->choice.setup && - bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table) { - if (*bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table == 0) + if (pdsch_Config && + pdsch_Config->mcs_Table) { + if (*pdsch_Config->mcs_Table == 0) mcsTableIdx = 1; else mcsTableIdx = 2; @@ -1837,6 +1806,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra fill_dci_pdu_rel15(scc, ra->CellGroup, + ra_BWP, &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci - 1], &dci_payload, NR_DL_DCI_FORMAT_1_0, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index f3eea60e63..743358f47d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -545,6 +545,7 @@ void nr_fill_nfapi_dl_sib1_pdu(int Mod_idP, int rnti_type = NR_RNTI_SI; fill_dci_pdu_rel15(scc, + NULL, NULL, &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci - 1], &dci_payload, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 8b7da91f63..829e288eae 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -376,15 +376,10 @@ bool allocate_dl_retransmission(module_id_t module_id, gNB_MAC_INST *nr_mac = RC.nrmac[module_id]; const NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels->ServingCellConfigCommon; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_UE_BWP_t *BWP = &UE->current_BWP; NR_sched_pdsch_t *retInfo = &sched_ctrl->harq_processes[current_harq_pid].sched_pdsch; NR_CellGroupConfig_t *cg = UE->CellGroup; - NR_BWP_DownlinkDedicated_t *bwpd = - cg && - cg->spCellConfig && - cg->spCellConfig->spCellConfigDedicated ? - cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP : NULL; - NR_BWP_UplinkDedicated_t *ubwpd = cg && cg->spCellConfig && @@ -392,8 +387,6 @@ bool allocate_dl_retransmission(module_id_t module_id, cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; - const NR_SIB1_t *sib1 = RC.nrmac[module_id]->common_channels[0].sib1 ? RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - const int coresetid = sched_ctrl->coreset->controlResourceSetId; const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : UE->current_BWP.dl_BWPSize; @@ -427,11 +420,9 @@ bool allocate_dl_retransmission(module_id_t module_id, /* check whether we need to switch the TDA allocation since the last * (re-)transmission */ if (ps->time_domain_allocation != tda) { - nr_set_pdsch_semi_static(sib1, + nr_set_pdsch_semi_static(BWP, scc, cg, - sched_ctrl->active_bwp, - bwpd, tda, ps->nrOfLayers, sched_ctrl, @@ -442,11 +433,9 @@ bool allocate_dl_retransmission(module_id_t module_id, * that we have enough resources */ NR_pdsch_semi_static_t temp_ps = *ps; - nr_set_pdsch_semi_static(sib1, + nr_set_pdsch_semi_static(BWP, scc, cg, - sched_ctrl->active_bwp, - bwpd, tda, ps->nrOfLayers, sched_ctrl, @@ -651,12 +640,6 @@ void pf_dl(module_id_t module_id, NR_CellGroupConfig_t *cg = iterator->UE->CellGroup; - NR_BWP_DownlinkDedicated_t *bwpd = - cg && - cg->spCellConfig && - cg->spCellConfig->spCellConfigDedicated ? - cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP : NULL; - NR_BWP_UplinkDedicated_t *ubwpd = cg && cg->spCellConfig && @@ -666,9 +649,6 @@ void pf_dl(module_id_t module_id, NR_UE_sched_ctrl_t *sched_ctrl = &iterator->UE->UE_sched_ctrl; const uint16_t rnti = iterator->UE->rnti; - const NR_SIB1_t *sib1 = RC.nrmac[module_id]->common_channels[0].sib1 ? - RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : - NULL; NR_UE_BWP_t *BWP = &iterator->UE->current_BWP; @@ -744,11 +724,9 @@ void pf_dl(module_id_t module_id, NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; if (ps->nrOfLayers != iterator->UE->layers || ps->time_domain_allocation != tda ) { - nr_set_pdsch_semi_static(sib1, + nr_set_pdsch_semi_static(BWP, scc, iterator->UE->CellGroup, - sched_ctrl->active_bwp, - bwpd, tda, iterator->UE->layers, sched_ctrl, @@ -813,17 +791,14 @@ void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t /* This is temporary and it assumes all UEs have the same BWP and TDA*/ NR_UE_info_t *UE=UE_info->list[0]; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_UE_BWP_t *BWP = &UE->current_BWP; const int tda = get_dl_tda(RC.nrmac[module_id], scc, slot); int startSymbolIndex, nrOfSymbols; - const struct NR_PDSCH_TimeDomainResourceAllocationList *tdaList = sched_ctrl->active_bwp ? - sched_ctrl->active_bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList : - scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; + const struct NR_PDSCH_TimeDomainResourceAllocationList *tdaList = BWP->tdaList; AssertFatal(tda < tdaList->list.count, "time_domain_allocation %d>=%d\n", tda, tdaList->list.count); const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength; SLIV2SL(startSymbolAndLength, &startSymbolIndex, &nrOfSymbols); - NR_UE_BWP_t *BWP = &UE->current_BWP; - const int coresetid = sched_ctrl->coreset->controlResourceSetId; const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : BWP->dl_BWPSize; @@ -986,8 +961,6 @@ void nr_schedule_ue_spec(module_id_t module_id, sched_pdsch->pucch_allocation, sched_ctrl->tpc1); - NR_BWP_Downlink_t *bwp = sched_ctrl->active_bwp; - NR_SearchSpace_t *ss = sched_ctrl->search_space; const int bwp_id = current_BWP->dl_bwp_id; @@ -1087,13 +1060,7 @@ void nr_schedule_ue_spec(module_id_t module_id, bw_tbslbrm, nl_tbslbrm); - NR_PDSCH_Config_t *pdsch_Config=NULL; - - if (bwp && - bwp->bwp_Dedicated && - bwp->bwp_Dedicated->pdsch_Config && - bwp->bwp_Dedicated->pdsch_Config->choice.setup) - pdsch_Config = bwp->bwp_Dedicated->pdsch_Config->choice.setup; + NR_PDSCH_Config_t *pdsch_Config = current_BWP->pdsch_Config; /* Check and validate PTRS values */ struct NR_SetupRelease_PTRS_DownlinkConfig *phaseTrackingRS = @@ -1140,14 +1107,11 @@ void nr_schedule_ue_spec(module_id_t module_id, dci_pdu_rel15_t dci_payload; memset(&dci_payload, 0, sizeof(dci_pdu_rel15_t)); // bwp indicator - const int n_dl_bwp = bwp ? cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count : 0; - AssertFatal(n_dl_bwp <= NR_MAX_NUM_BWP, "downlinkBWP_ToAddModList has %d BWP!\n", n_dl_bwp); - // as per table 7.3.1.1.2-1 in 38.212 - dci_payload.bwp_indicator.val = bwp ? (n_dl_bwp < 4 ? bwp_id : bwp_id - 1) : 0; + dci_payload.bwp_indicator.val = current_BWP->n_dl_bwp < 4 ? bwp_id : bwp_id - 1; - if (bwp) AssertFatal(bwp->bwp_Dedicated->pdsch_Config->choice.setup->resourceAllocation == NR_PDSCH_Config__resourceAllocation_resourceAllocationType1, - "Only frequency resource allocation type 1 is currently supported\n"); + AssertFatal(pdsch_Config->resourceAllocation == NR_PDSCH_Config__resourceAllocation_resourceAllocationType1, + "Only frequency resource allocation type 1 is currently supported\n"); dci_payload.frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pdsch_pdu->rbSize, pdsch_pdu->rbStart, @@ -1189,6 +1153,7 @@ void nr_schedule_ue_spec(module_id_t module_id, const int rnti_type = NR_RNTI_C; fill_dci_pdu_rel15(scc, cg, + current_BWP, dci_pdu, &dci_payload, dci_format, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index f61fbd6da2..94b3f99fa0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -202,7 +202,7 @@ void nr_preprocessor_phytest(module_id_t module_id, NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; ps->nrOfLayers = target_dl_Nl; if (ps->time_domain_allocation != tda || ps->nrOfLayers != target_dl_Nl) - nr_set_pdsch_semi_static(NULL, scc, UE->CellGroup, sched_ctrl->active_bwp, NULL, tda, target_dl_Nl,sched_ctrl , ps); + nr_set_pdsch_semi_static(BWP, scc, UE->CellGroup, tda, target_dl_Nl,sched_ctrl , ps); /* find largest unallocated chunk */ const int bwpSize = BWP->dl_BWPSize; @@ -380,9 +380,8 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ if (!is_xlsch_in_slot(ulsch_slot_bitmap, sched_slot)) return false; - const long f = (sched_ctrl->active_bwp && sched_ctrl->search_space && - sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific) ? - sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats : 0; + const long f = (sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific) ? + sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats : 0; const int dci_format = f ? NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0; uint8_t num_dmrs_cdm_grps_no_data = 1; if ((target_ul_Nl==4)||(target_ul_Nl==3)) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 7909f192b2..2fd3c0620a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -245,22 +245,6 @@ void set_dl_dmrs_ports(NR_pdsch_semi_static_t *ps) { } } - -NR_PDSCH_TimeDomainResourceAllocationList_t *get_pdsch_TimeDomainAllocationList(const NR_BWP_Downlink_t *active_bwp, - const NR_ServingCellConfigCommon_t *ServingCellConfigCommon, - const NR_SIB1_t *sib1) { - NR_PDSCH_TimeDomainResourceAllocationList_t *tdaList = NULL; - if (active_bwp) { - tdaList = active_bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; - } else if (ServingCellConfigCommon) { - tdaList = ServingCellConfigCommon->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; - } else { - tdaList = sib1->servingCellConfigCommon->downlinkConfigCommon.initialDownlinkBWP.pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; - } - return tdaList; -} - - NR_ControlResourceSet_t *get_coreset(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, void *bwp, @@ -544,11 +528,9 @@ bool nr_find_nb_rb(uint16_t Qm, return *tbs >= bytes && *nb_rb <= nb_rb_max; } -void nr_set_pdsch_semi_static(const NR_SIB1_t *sib1, +void nr_set_pdsch_semi_static(const NR_UE_BWP_t *BWP, const NR_ServingCellConfigCommon_t *scc, const NR_CellGroupConfig_t *secondaryCellGroup, - const NR_BWP_Downlink_t *bwp, - const NR_BWP_DownlinkDedicated_t *bwpd0, int tda, uint8_t layers, NR_UE_sched_ctrl_t *sched_ctrl, @@ -556,19 +538,11 @@ void nr_set_pdsch_semi_static(const NR_SIB1_t *sib1, { bool reset_dmrs = false; - NR_BWP_DownlinkDedicated_t *bwpd = NULL; - if (bwp && bwp->bwp_Dedicated) { - bwpd = bwp->bwp_Dedicated; - } else { - bwpd = (NR_BWP_DownlinkDedicated_t*)bwpd0; - } - - NR_PDSCH_Config_t *pdsch_Config = NULL; - if (bwpd && bwpd->pdsch_Config) pdsch_Config = bwpd->pdsch_Config->choice.setup; + NR_PDSCH_Config_t *pdsch_Config = BWP->pdsch_Config; LOG_D(NR_MAC,"tda %d, ps->time_domain_allocation %d,layers %d, ps->nrOfLayers %d, pdsch_config %p\n",tda,ps->time_domain_allocation,layers,ps->nrOfLayers,pdsch_Config); reset_dmrs = true; ps->time_domain_allocation = tda; - NR_PDSCH_TimeDomainResourceAllocationList_t *tdaList = get_pdsch_TimeDomainAllocationList(bwp, scc, sib1); + NR_PDSCH_TimeDomainResourceAllocationList_t *tdaList = BWP->tdaList; AssertFatal(tda < tdaList->list.count, "time_domain_allocation %d>=%d\n", tda, tdaList->list.count); ps->mapping_type = tdaList->list.array[tda]->mappingType; if (pdsch_Config) { @@ -582,9 +556,7 @@ void nr_set_pdsch_semi_static(const NR_SIB1_t *sib1, const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength; SLIV2SL(startSymbolAndLength, &ps->startSymbolIndex, &ps->nrOfSymbols); - const long f = ((bwp || bwpd) && - sched_ctrl->search_space && - sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific) ? + const long f = sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific ? sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats : 0; int dci_format; @@ -615,10 +587,10 @@ void nr_set_pdsch_semi_static(const NR_SIB1_t *sib1, ps->N_PRB_DMRS = ps->numDmrsCdmGrpsNoData * (ps->dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6 : 4); if (reset_dmrs) { - ps->dl_dmrs_symb_pos = fill_dmrs_mask(bwpd ? bwpd->pdsch_Config->choice.setup : NULL, scc ? scc->dmrs_TypeA_Position : 0, ps->nrOfSymbols, ps->startSymbolIndex, ps->mapping_type, ps->frontloaded_symb); + ps->dl_dmrs_symb_pos = fill_dmrs_mask(pdsch_Config, scc ? scc->dmrs_TypeA_Position : 0, ps->nrOfSymbols, ps->startSymbolIndex, ps->mapping_type, ps->frontloaded_symb); ps->N_DMRS_SLOT = get_num_dmrs(ps->dl_dmrs_symb_pos); } - LOG_D(NR_MAC,"bwpd0 %p, bwpd %p : Filling dmrs info, ps->N_PRB_DMRS %d, ps->dl_dmrs_symb_pos %x, ps->N_DMRS_SLOT %d\n",bwpd0,bwpd,ps->N_PRB_DMRS,ps->dl_dmrs_symb_pos,ps->N_DMRS_SLOT); + LOG_D(NR_MAC,"Filling dmrs info, ps->N_PRB_DMRS %d, ps->dl_dmrs_symb_pos %x, ps->N_DMRS_SLOT %d\n",ps->N_PRB_DMRS,ps->dl_dmrs_symb_pos,ps->N_DMRS_SLOT); } void nr_set_pusch_semi_static(const NR_SIB1_t *sib1, @@ -1400,25 +1372,25 @@ void set_r_pucch_parms(int rsetindex, void prepare_dci(const NR_CellGroupConfig_t *CellGroup, + const NR_UE_BWP_t *BWP, dci_pdu_rel15_t *dci_pdu_rel15, nr_dci_format_t format, int bwp_id) { AssertFatal(CellGroup!=NULL,"CellGroup shouldn't be null here\n"); - const NR_BWP_DownlinkDedicated_t *bwpd = NULL; - const NR_PDSCH_Config_t *pdsch_Config = NULL; const NR_PDCCH_Config_t *pdcch_Config = NULL; + const NR_BWP_DownlinkDedicated_t *bwpd = NULL; if (bwp_id>0) { bwpd=CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Dedicated; } else { bwpd=CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP; } - pdsch_Config = (bwpd->pdsch_Config) ? bwpd->pdsch_Config->choice.setup : NULL; pdcch_Config = (bwpd->pdcch_Config) ? bwpd->pdcch_Config->choice.setup : NULL; + const NR_PDSCH_Config_t *pdsch_Config = BWP ? BWP->pdsch_Config : NULL; switch(format) { case NR_UL_DCI_FORMAT_0_1: @@ -1493,6 +1465,7 @@ void prepare_dci(const NR_CellGroupConfig_t *CellGroup, void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, const NR_CellGroupConfig_t *CellGroup, + const NR_UE_BWP_t *BWP, nfapi_nr_dl_dci_pdu_t *pdcch_dci_pdu, dci_pdu_rel15_t *dci_pdu_rel15, int dci_format, @@ -1512,7 +1485,7 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, pdcch_dci_pdu->PayloadSizeBits = dci_size; AssertFatal(dci_size <= 64, "DCI sizes above 64 bits not yet supported"); if (dci_format == NR_DL_DCI_FORMAT_1_1 || dci_format == NR_UL_DCI_FORMAT_0_1) - prepare_dci(CellGroup, dci_pdu_rel15, dci_format, bwp_id); + prepare_dci(CellGroup, BWP, dci_pdu_rel15, dci_format, bwp_id); /// Payload generation switch (dci_format) { @@ -2327,6 +2300,8 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, NR_BWP_Uplink_t *ul_bwp = NULL; NR_BWP_DownlinkDedicated_t *bwpd = NULL; NR_BWP_UplinkDedicated_t *ubwpd = NULL; + BWP->n_dl_bwp = 1; + int old_dl_bwp_id = BWP->dl_bwp_id; int target_ss; @@ -2348,6 +2323,8 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, BWP->ul_bwp_id = *servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id; const struct NR_ServingCellConfig__downlinkBWP_ToAddModList *bwpList = servingCellConfig->downlinkBWP_ToAddModList; + if(bwpList) + BWP->n_dl_bwp = bwpList->list.count; if (BWP->dl_bwp_id>0) { for (int i=0; ilist.count; i++) { dl_bwp = bwpList->list.array[i]; @@ -2376,13 +2353,24 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, ubwpd = ul_bwp->bwp_Dedicated; else ubwpd = servingCellConfig->uplinkConfig->initialUplinkBWP; + + BWP->pdsch_Config = bwpd->pdsch_Config->choice.setup; } else { BWP->dl_bwp_id = 0; BWP->ul_bwp_id = 0; target_ss = NR_SearchSpace__searchSpaceType_PR_common; + BWP->pdsch_Config = NULL; } + if (old_dl_bwp_id != BWP->dl_bwp_id) + LOG_I(NR_MAC, "Switching to DL-BWP %li\n", BWP->dl_bwp_id); + + if (BWP->dl_bwp_id>0) + BWP->tdaList = dl_bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; + else + BWP->tdaList = scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; + // setting generic parameters NR_BWP_t dl_genericParameters = (BWP->dl_bwp_id>0 && dl_bwp) ? dl_bwp->bwp_Common->genericParameters: @@ -2508,10 +2496,6 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf const NR_ServingCellConfig_t *servingCellConfig = CellGroup && CellGroup->spCellConfig ? CellGroup->spCellConfig->spCellConfigDedicated : NULL; /* Set default BWPs */ - const struct NR_ServingCellConfig__downlinkBWP_ToAddModList *bwpList = servingCellConfig ? servingCellConfig->downlinkBWP_ToAddModList : NULL; - - sched_ctrl->active_bwp = bwpList && BWP->dl_bwp_id > 0 ? bwpList->list.array[BWP->dl_bwp_id - 1] : NULL; - sched_ctrl->next_dl_bwp_id = -1; sched_ctrl->next_ul_bwp_id = -1; const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig ? servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList : NULL; @@ -2982,14 +2966,8 @@ void nr_mac_update_timers(module_id_t module_id, } // If needed, update the Dedicated BWP - if (spCellConfigDedicated && - spCellConfigDedicated->downlinkBWP_ToAddModList && - spCellConfigDedicated->uplinkConfig && + if (spCellConfigDedicated->uplinkConfig && spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList) { - sched_ctrl->active_bwp = spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[*spCellConfigDedicated->firstActiveDownlinkBWP_Id - 1]; - if (*spCellConfigDedicated->firstActiveDownlinkBWP_Id != BWP->dl_bwp_id) { - LOG_I(NR_MAC, "Changing to DL-BWP %li\n", sched_ctrl->active_bwp->bwp_Id); - } sched_ctrl->active_ubwp = spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[*spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id - 1]; if (*spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id != BWP->ul_bwp_id) { LOG_I(NR_MAC, "Changing to UL-BWP %li\n", sched_ctrl->active_ubwp->bwp_Id); @@ -2999,16 +2977,6 @@ void nr_mac_update_timers(module_id_t module_id, configure_UE_BWP(RC.nrmac[module_id], BWP, scc, sched_ctrl, NULL, UE->CellGroup); // Update coreset/searchspace - NR_BWP_Downlink_t *bwp = sched_ctrl->active_bwp; - NR_BWP_DownlinkDedicated_t *bwpd = NULL; - if (bwp) { - bwpd = sched_ctrl->active_bwp->bwp_Dedicated; - } else if (cg && - cg->spCellConfig && - cg->spCellConfig->spCellConfigDedicated && - (cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP)) { - bwpd = cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP; - } sched_ctrl->maxL = 2; if (cg && @@ -3024,11 +2992,9 @@ void nr_mac_update_timers(module_id_t module_id, const int tda = get_dl_tda(RC.nrmac[module_id], scc, slot); // Update downlink MCS table - if (bwpd && - bwpd->pdsch_Config && - bwpd->pdsch_Config->choice.setup && - bwpd->pdsch_Config->choice.setup->mcs_Table) { - if (*bwpd->pdsch_Config->choice.setup->mcs_Table == 0) { + if (BWP->pdsch_Config && + BWP->pdsch_Config->mcs_Table) { + if (*BWP->pdsch_Config->mcs_Table == 0) { ps->mcsTableIdx = 1; } else { ps->mcsTableIdx = 2; @@ -3038,11 +3004,9 @@ void nr_mac_update_timers(module_id_t module_id, } LOG_D(NR_MAC,"MCS Table Index: %d\n",ps->mcsTableIdx); - nr_set_pdsch_semi_static(sib1, + nr_set_pdsch_semi_static(BWP, scc, cg, - bwp, - bwpd, tda, layers, sched_ctrl, @@ -3091,13 +3055,14 @@ void schedule_nr_bwp_switch(module_id_t module_id, UE_iterator(UE_info->list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_UE_BWP_t *BWP = &UE->current_BWP; if (sched_ctrl->rrc_processing_timer == 0 && UE->Msg4_ACKed && - ((sched_ctrl->next_dl_bwp_id >= 0 && sched_ctrl->active_bwp && sched_ctrl->active_bwp->bwp_Id != sched_ctrl->next_dl_bwp_id) || - (sched_ctrl->next_ul_bwp_id >= 0 && sched_ctrl->active_ubwp && sched_ctrl->active_ubwp->bwp_Id != sched_ctrl->next_ul_bwp_id))) { + ((sched_ctrl->next_dl_bwp_id >= 0 && BWP->dl_bwp_id != sched_ctrl->next_dl_bwp_id) || + (sched_ctrl->next_ul_bwp_id >= 0 && BWP->ul_bwp_id != sched_ctrl->next_ul_bwp_id))) { LOG_W(NR_MAC,"%4d.%2d UE %04x Schedule BWP switch from dl_bwp_id %ld to %ld and from ul_bwp_id %ld to %ld\n", - frame, slot, UE->rnti, sched_ctrl->active_bwp->bwp_Id, sched_ctrl->next_dl_bwp_id, sched_ctrl->active_ubwp->bwp_Id, sched_ctrl->next_ul_bwp_id); + frame, slot, UE->rnti, BWP->dl_bwp_id, sched_ctrl->next_dl_bwp_id, BWP->ul_bwp_id, sched_ctrl->next_ul_bwp_id); nr_mac_rrc_bwp_switch_req(module_id, frame, slot, UE->rnti, sched_ctrl->next_dl_bwp_id, sched_ctrl->next_ul_bwp_id); } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index b5472542f9..faf8a01c18 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -833,13 +833,13 @@ static void handle_dl_harq(NR_UE_info_t * UE, } int checkTargetSSBInFirst64TCIStates_pdschConfig(int ssb_index_t, NR_UE_info_t * UE) { - NR_CellGroupConfig_t *CellGroup = UE->CellGroup; - int nb_tci_states = CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->tci_StatesToAddModList->list.count; - NR_TCI_State_t *tci =NULL; - int i; - for(i=0; ispCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->tci_StatesToAddModList->list.array[i]; + const NR_PDSCH_Config_t *pdsch_Config = UE->current_BWP.pdsch_Config; + int nb_tci_states = pdsch_Config ? pdsch_Config->tci_StatesToAddModList->list.count : 0; + NR_TCI_State_t *tci =NULL; + + for(int i=0; itci_StatesToAddModList->list.array[i]; if(tci != NULL) { if(tci->qcl_Type1.referenceSignal.present == NR_QCL_Info__referenceSignal_PR_ssb) { @@ -859,18 +859,17 @@ int checkTargetSSBInFirst64TCIStates_pdschConfig(int ssb_index_t, NR_UE_info_t * } int checkTargetSSBInTCIStates_pdcchConfig(int ssb_index_t, NR_UE_info_t *UE) { - NR_CellGroupConfig_t *CellGroup = UE->CellGroup ; - int nb_tci_states = CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->tci_StatesToAddModList->list.count; + NR_TCI_State_t *tci =NULL; NR_TCI_StateId_t *tci_id = NULL; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_ControlResourceSet_t *coreset = sched_ctrl->coreset; - int i; int flag = 0; int tci_stateID = -1; - - for(i=0; ispCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->tci_StatesToAddModList->list.array[i]; + const NR_PDSCH_Config_t *pdsch_Config = UE->current_BWP.pdsch_Config; + int nb_tci_states = pdsch_Config ? pdsch_Config->tci_StatesToAddModList->list.count : 0; + for(int i=0; itci_StatesToAddModList->list.array[i]; if(tci != NULL && tci->qcl_Type1.referenceSignal.present == NR_QCL_Info__referenceSignal_PR_ssb) { if(tci->qcl_Type1.referenceSignal.choice.ssb == ssb_index_t) { @@ -932,14 +931,6 @@ void tci_handling(NR_UE_info_t *UE, frame_t frame, slot_t slot) { uint8_t idx = 0; NR_UE_BWP_t *BWP = &UE->current_BWP; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_CellGroupConfig_t *CellGroup = UE->CellGroup; - - //bwp indicator - int n_dl_bwp=0; - if (CellGroup->spCellConfig && - CellGroup->spCellConfig->spCellConfigDedicated && - CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList) - n_dl_bwp = CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count; uint8_t nr_ssbri_cri = 0; uint8_t nb_of_csi_ssb_report = UE->csi_report_template[cqi_idx].nb_of_csi_ssb_report; @@ -947,6 +938,8 @@ void tci_handling(NR_UE_info_t *UE, frame_t frame, slot_t slot) { uint8_t diff_rsrp_idx = 0; uint8_t i, j; + //bwp indicator + int n_dl_bwp = BWP->n_dl_bwp; const int bwp_id = BWP->dl_bwp_id; if (n_dl_bwp < 4) pdsch_bwp_id = bwp_id; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 5106715b47..3c4ca86cbd 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1806,6 +1806,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) current_BWP); fill_dci_pdu_rel15(scc, cg, + current_BWP, dci_pdu, &uldci_payload, ps->dci_format, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 74e6884802..1eed647565 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -297,6 +297,7 @@ void fill_pdcch_vrb_map(gNB_MAC_INST *mac, void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, const NR_CellGroupConfig_t *CellGroup, + const NR_UE_BWP_t *BWP, nfapi_nr_dl_dci_pdu_t *pdcch_dci_pdu, dci_pdu_rel15_t *dci_pdu_rel15, int dci_formats, @@ -307,6 +308,7 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, uint16_t cset0_bwp_size); void prepare_dci(const NR_CellGroupConfig_t *CellGroup, + const NR_UE_BWP_t *BWP, dci_pdu_rel15_t *dci_pdu_rel15, nr_dci_format_t format, int bwp_id); @@ -319,11 +321,6 @@ void set_r_pucch_parms(int rsetindex, int *nr_of_symbols, int *start_symbol_index); - -NR_PDSCH_TimeDomainResourceAllocationList_t *get_pdsch_TimeDomainAllocationList(const NR_BWP_Downlink_t *active_bwp, - const NR_ServingCellConfigCommon_t *ServingCellConfigCommon, - const NR_SIB1_t *sib1); - /* find coreset within the search space */ NR_ControlResourceSet_t *get_coreset(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, @@ -342,11 +339,9 @@ long get_K2(NR_ServingCellConfigCommon_t *scc, int time_domain_assignment, int mu); -void nr_set_pdsch_semi_static(const NR_SIB1_t *sib1, +void nr_set_pdsch_semi_static(const NR_UE_BWP_t *BWP, const NR_ServingCellConfigCommon_t *scc, const NR_CellGroupConfig_t *secondaryCellGroup, - const NR_BWP_Downlink_t *bwp, - const NR_BWP_DownlinkDedicated_t *bwpd0, int tda, uint8_t layers, NR_UE_sched_ctrl_t *sched_ctrl, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index cf2e6be635..2d42dbe15e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -94,6 +94,7 @@ typedef struct { typedef struct NR_UE_BWP { NR_BWP_Id_t dl_bwp_id; NR_BWP_Id_t ul_bwp_id; + int n_dl_bwp; int dl_scs; int ul_scs; long *dl_cyclicprefix; @@ -102,6 +103,8 @@ typedef struct NR_UE_BWP { uint16_t dl_BWPStart; uint16_t ul_BWPSize; uint16_t ul_BWPStart; + NR_PDSCH_TimeDomainResourceAllocationList_t *tdaList; + NR_PDSCH_Config_t *pdsch_Config; } NR_UE_BWP_t; typedef enum { @@ -576,8 +579,6 @@ typedef struct NR_UE_ul_harq { /*! \brief scheduling control information set through an API */ #define MAX_CSI_REPORTS 48 typedef struct { - /// the currently active BWP in DL - NR_BWP_Downlink_t *active_bwp; /// the currently active BWP in UL NR_BWP_Uplink_t *active_ubwp; From 630f8ac2b1b10917a881077edff04573f2c05bfb Mon Sep 17 00:00:00 2001 From: Melissa Elkadi Date: Tue, 14 Jun 2022 12:52:01 -0700 Subject: [PATCH 134/267] Putting all CM code in one file This commit includes reorganization of all of the SISO/MIMO channel modelling support being moved into a single CM file. Furthermore, it includes a bug fix for the number of MCS simulation tables (29 total, 0-28). --- cmake_targets/CMakeLists.txt | 1 + openair1/PHY/defs_common.h | 2 +- openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c | 255 +----------------- openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h | 37 +-- openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.c | 183 +++++++++++++ openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.h | 68 +++++ openair2/PHY_INTERFACE/phy_stub_UE.c | 2 +- openair2/PHY_INTERFACE/phy_stub_UE.h | 2 +- 8 files changed, 258 insertions(+), 292 deletions(-) create mode 100644 openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.c create mode 100644 openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index c08d9378b8..84a98a300e 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1926,6 +1926,7 @@ set (MAC_SRC_UE set (MAC_NR_SRC_UE ${NR_UE_PHY_INTERFACE_DIR}/NR_IF_Module.c + ${NR_UE_PHY_INTERFACE_DIR}/NR_Packet_Drop.c ${NR_UE_MAC_DIR}/config_ue.c ${NR_UE_MAC_DIR}/mac_vars.c ${NR_UE_MAC_DIR}/main_ue_nr.c diff --git a/openair1/PHY/defs_common.h b/openair1/PHY/defs_common.h index d13fe260de..47e17cc935 100644 --- a/openair1/PHY/defs_common.h +++ b/openair1/PHY/defs_common.h @@ -907,7 +907,7 @@ typedef enum {no_relay=1,unicast_relay_type1,unicast_relay_type2, multicast_rela -#define MCS_COUNT 28 +#define MCS_COUNT 29 #define MCS_TABLE_LENGTH_MAX 64 diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c index b8b79f8399..b6f760a86a 100644 --- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c @@ -66,17 +66,6 @@ queue_t nr_tx_req_queue; queue_t nr_ul_dci_req_queue; queue_t nr_ul_tti_req_queue; -static slot_rnti_mcs_s slot_rnti_mcs[NUM_NFAPI_SLOT]; - -//static int get_mcs_from_sinr(float sinr); -//static int get_cqi_from_mcs(void); -static void read_channel_param(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t * pdu, int sf, int index); -//static bool did_drop_transport_block(int slot, uint16_t rnti); -static float get_bler_val(uint8_t mcs, int sinr); -static bool should_drop_transport_block(int slot, uint16_t rnti); -static void save_pdsch_pdu_for_crnti(nfapi_nr_dl_tti_request_t *dl_tti_request); -static inline bool is_channel_modeling(void); - void nrue_init_standalone_socket(int tx_port, int rx_port) { { @@ -939,7 +928,7 @@ static void enqueue_nr_nfapi_msg(void *buffer, ssize_t len, nfapi_p7_message_hea return; } -static void save_pdsch_pdu_for_crnti(nfapi_nr_dl_tti_request_t *dl_tti_request) +void save_pdsch_pdu_for_crnti(nfapi_nr_dl_tti_request_t *dl_tti_request) { int count_sent = 0; NR_UE_MAC_INST_t *mac = get_mac_inst(0); @@ -1343,245 +1332,3 @@ void RCconfig_nr_ue_L1(void) { } } } - -/* -static int get_mcs_from_sinr(float sinr) -{ - if (sinr < (nr_bler_data[0].bler_table[0][0])) - { - LOG_D(NR_MAC, "The SINR found is smaller than first MCS table\n"); - return 0; - } - - if (sinr > (nr_bler_data[NR_NUM_MCS-1].bler_table[nr_bler_data[NR_NUM_MCS-1].length - 1][0])) - { - LOG_D(NR_MAC, "The SINR found is larger than last MCS table\n"); - return NR_NUM_MCS-1; - } - - for (int n = NR_NUM_MCS-1; n >= 0; n--) - { - CHECK_INDEX(nr_bler_data, n); - float largest_sinr = (nr_bler_data[n].bler_table[nr_bler_data[n].length - 1][0]); - float smallest_sinr = (nr_bler_data[n].bler_table[0][0]); - if (sinr < largest_sinr && sinr > smallest_sinr) - { - LOG_D(NR_MAC, "The SINR found in MCS %d table\n", n); - return n; - } - } - LOG_E(NR_MAC, "Unable to get an MCS value.\n"); - abort(); -} -*/ - -/* -static int get_cqi_from_mcs(void) -{ - static const int mcs_to_cqi[] = {0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, - 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15}; - assert(NUM_ELEMENTS(mcs_to_cqi) == NR_NUM_MCS); - int slot = 0; - while (slot < NUM_NFAPI_SLOT) - { - if (slot_rnti_mcs[slot].latest) - { - int num_pdus = slot_rnti_mcs[slot].num_pdus; - if (num_pdus <= 0) - { - LOG_E(NR_MAC, "%s: slot_rnti_mcs[%d].num_pdus = 0\n", __FUNCTION__, slot); - abort(); - } - - CHECK_INDEX(slot_rnti_mcs[slot].mcs, num_pdus); - int mcs = get_mcs_from_sinr(slot_rnti_mcs[slot].sinr); - CHECK_INDEX(mcs_to_cqi, mcs); - int cqi = mcs_to_cqi[mcs]; - LOG_D(NR_MAC, "SINR: %f -> MCS: %d -> CQI: %d\n", slot_rnti_mcs[slot].sinr, mcs, cqi); - return cqi; - } - slot++; - } - LOG_E(NR_MAC, "Unable to get CQI value because no MCS found\n"); - abort(); -} -*/ - -static void read_channel_param(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t * pdu, int slot, int index) -{ - if (pdu == NULL) - { - LOG_E(NR_MAC,"PDU NULL\n"); - abort(); - } - - /* This function is executed for every pdsch pdu type in a dl_tti_request. We save - the assocaited MCS and RNTI value for each. The 'index' passed in is a count of - how many times we have called this function for a particular dl_tti_request. It - allows us to save MCS/RNTI data in correct indicies when multiple pdsch pdu's are received.*/ - for (int i = 0; i < NUM_NFAPI_SLOT; i++) - { - slot_rnti_mcs[i].latest = false; - } - - CHECK_INDEX(slot_rnti_mcs[slot].rnti, index); - CHECK_INDEX(slot_rnti_mcs[slot].mcs, index); - CHECK_INDEX(slot_rnti_mcs[slot].drop_flag, index); - slot_rnti_mcs[slot].rnti[index] = pdu->rnti; - slot_rnti_mcs[slot].mcs[index] = pdu->mcsIndex[0]; - slot_rnti_mcs[slot].rvIndex[index] = pdu->rvIndex[0]; - slot_rnti_mcs[slot].drop_flag[index] = false; - slot_rnti_mcs[slot].num_pdus = index+1; //index starts at 0 so we incrament to get num of pdus - slot_rnti_mcs[slot].latest = true; - LOG_D(NR_MAC, "Adding MCS %d and RNTI %x for slot_rnti_mcs[%d]\n", slot_rnti_mcs[slot].mcs[index], slot_rnti_mcs[slot].rnti[index], slot); - - return; -} - -/* -static bool did_drop_transport_block(int slot, uint16_t rnti) -{ - int num_pdus = slot_rnti_mcs[slot].num_pdus; - if (num_pdus <= 0) - { - LOG_E(MAC, "Problem, the PDU size is <= 0. We dropped this packet\n"); - return true; - } - CHECK_INDEX(slot_rnti_mcs[slot].rnti, num_pdus); - CHECK_INDEX(slot_rnti_mcs[slot].drop_flag, num_pdus); - for (int n = 0; n < num_pdus; n++) - { - if (slot_rnti_mcs[slot].rnti[n] == rnti && slot_rnti_mcs[slot].drop_flag[n]) - { - return true; - } - } - return false; -} -*/ - -static float get_bler_val(uint8_t mcs, int sinr) -{ - // 4th col = dropped packets, 5th col = total packets - float bler_val = 0.0; - CHECK_INDEX(nr_bler_data, mcs); - LOG_D(NR_MAC, "sinr %d min %d max %d\n", sinr, - (int)(nr_bler_data[mcs].bler_table[0][0] * 10), - (int)(nr_bler_data[mcs].bler_table[nr_bler_data[mcs].length - 1][0] * 10) - ); - - if (sinr < (int)(nr_bler_data[mcs].bler_table[0][0] * 10)) - { - LOG_D(NR_MAC, "MCS %d table. SINR is smaller than lowest SINR, bler_val is set based on lowest SINR in table\n", mcs); - bler_val = nr_bler_data[mcs].bler_table[0][4] / nr_bler_data[mcs].bler_table[0][5]; - return bler_val; - } - if (sinr > (int)(nr_bler_data[mcs].bler_table[nr_bler_data[mcs].length - 1][0] * 10)) - { - LOG_D(NR_MAC, "MCS %d table. SINR is greater than largest SINR. bler_val is set based on largest SINR in table\n", mcs); - bler_val = nr_bler_data[mcs].bler_table[(nr_bler_data[mcs].length - 1)][4] / nr_bler_data[mcs].bler_table[(nr_bler_data[mcs].length - 1)][5]; - return bler_val; - } - // Loop through bler table to find sinr_index - for (int i = 0; i < nr_bler_data[mcs].length; i++) - { - int temp_sinr = (int)(nr_bler_data[mcs].bler_table[i][0] * 10); - if (temp_sinr == sinr) - { - bler_val = nr_bler_data[mcs].bler_table[i][4] / nr_bler_data[mcs].bler_table[i][5]; - return bler_val; - } - // Linear interpolation when SINR is between indices - if (temp_sinr > sinr) - { - float bler_val1 = nr_bler_data[mcs].bler_table[i - 1][4] / nr_bler_data[mcs].bler_table[i - 1][5]; - float bler_val2 = nr_bler_data[mcs].bler_table[i][4] / nr_bler_data[mcs].bler_table[i][5]; - LOG_D(NR_MAC, "sinr %d min %f max %f\n", sinr, bler_val1, bler_val2); - return ((bler_val1 + bler_val2) / 2); - } - } - LOG_E(NR_MAC, "NO SINR INDEX FOUND!\n"); - abort(); - -} - -static inline bool is_channel_modeling(void) -{ - /* TODO: For now we enable channel modeling based on the node_number. - Replace with a command line option to enable/disable channel modeling. - The LTE UE will crash when channel modeling is conducted for NSA - mode. It does not crash for LTE mode. We have not implemented channel - modeling for NSA mode yet. For now, we ensure only do do channel modeling - in LTE/NR mode. */ - return get_softmodem_params()->node_number == 0 && !get_softmodem_params()->nsa; -} - -static bool should_drop_transport_block(int slot, uint16_t rnti) -{ - if (!is_channel_modeling()) - { - return false; - } - - /* We want to avoid dropping setup messages because this would be pathological. */ - NR_UE_MAC_INST_t *mac = get_mac_inst(0); - if (mac->ra.ra_state < RA_SUCCEEDED) - { - LOG_D(NR_MAC, "Not dropping because MAC state: %d", mac->ra.ra_state); - return false; - } - - /* Get block error rate (bler_val) from table based on every saved - MCS and SINR to be used as the cutoff rate for dropping packets. - Generate random uniform vairable to compare against bler_val. */ - int num_pdus = slot_rnti_mcs[slot].num_pdus; - assert(slot < 20 && slot >= 0); - LOG_D(NR_MAC, "rnti: %x num_pdus %d state %d slot %u sinr %f\n", - rnti, num_pdus, mac->ra.ra_state, slot, slot_rnti_mcs[slot].sinr); - assert(num_pdus > 0); - CHECK_INDEX(slot_rnti_mcs[slot].rnti, num_pdus); - CHECK_INDEX(slot_rnti_mcs[slot].mcs, num_pdus); - CHECK_INDEX(slot_rnti_mcs[slot].drop_flag, num_pdus); - int n = 0; - uint8_t mcs = 99; - for (n = 0; n < num_pdus; n++) - { - if (slot_rnti_mcs[slot].rnti[n] == rnti) - { - mcs = slot_rnti_mcs[slot].mcs[n]; - } - if (mcs != 99) - { - /* Use MCS to get the bler value. Since there can be multiple MCS - values for a particular slot, we verify that all PDUs are not - flagged for drop before returning. If even one is flagged for drop - we return immediately because we drop the entire packet. */ - - LOG_D(NR_MAC, "rnti: %x mcs %u slot %u sinr %f\n", - slot_rnti_mcs[slot].rnti[n], mcs, slot, slot_rnti_mcs[slot].sinr); - - float bler_val; - if (slot_rnti_mcs[slot].rvIndex[n] != 0) - bler_val = 0; - else - bler_val = get_bler_val(mcs, ((int)(slot_rnti_mcs[slot].sinr * 10))); - double drop_cutoff = ((double) rand() / (RAND_MAX)); - assert(drop_cutoff <= 1); - LOG_D(NR_MAC, "SINR = %f, Bler_val = %f, MCS = %"PRIu8"\n", slot_rnti_mcs[slot].sinr, bler_val, slot_rnti_mcs[slot].mcs[n]); - if (drop_cutoff <= bler_val) - { - slot_rnti_mcs[slot].drop_flag[n] = true; - LOG_T(NR_MAC, "We are dropping this packet. Bler_val = %f, MCS = %"PRIu8", slot = %d\n", bler_val, slot_rnti_mcs[slot].mcs[n], slot); - return slot_rnti_mcs[slot].drop_flag[n]; - } - } - - } - - if (mcs == 99) - { - LOG_E(NR_MAC, "NO MCS Found for rnti %x. slot_rnti_mcs[%d].mcs[%d] \n", rnti, slot, n); - abort(); - } - return false; -} diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h index 45d1a071ca..f663c17d10 100755 --- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h +++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h @@ -40,45 +40,12 @@ #include "openair2/PHY_INTERFACE/queue_t.h" #include "nfapi_nr_interface_scf.h" #include "openair2/NR_PHY_INTERFACE/NR_IF_Module.h" +#include "NR_Packet_Drop.h" -#define NR_NUM_MCS 29 -#define NUM_SINR 100 -#define NUM_BLER_COL 13 -#define NUM_NFAPI_SLOT 20 -#define NR_NUM_LAYER 1 +extern slot_rnti_mcs_s slot_rnti_mcs[NUM_NFAPI_SLOT]; typedef struct NR_UL_TIME_ALIGNMENT NR_UL_TIME_ALIGNMENT_t; -typedef struct nr_phy_channel_params_t -{ - uint16_t sfn_slot; - uint16_t message_id; - uint16_t nb_of_sinrs; - float sinr[NR_NUM_LAYER]; - // Incomplete, need all channel parameters -} nr_phy_channel_params_t; - -typedef struct -{ - uint8_t slot; - uint16_t rnti[256]; - uint8_t mcs[256]; - uint8_t rvIndex[256]; - float sinr; - uint16_t num_pdus; - bool drop_flag[256]; - bool latest; - -} slot_rnti_mcs_s; - -typedef struct -{ - uint16_t length; - float bler_table[NUM_SINR][NUM_BLER_COL]; -} nr_bler_struct; - -extern nr_bler_struct nr_bler_data[NR_NUM_MCS]; - typedef enum { ONLY_PUSCH, NOT_PUSCH, diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.c b/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.c new file mode 100644 index 0000000000..41d27bda80 --- /dev/null +++ b/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.c @@ -0,0 +1,183 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ +#include +#include "openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.h" +#include "executables/softmodem-common.h" +#include "NR_MAC_UE/mac_proto.h" + +slot_rnti_mcs_s slot_rnti_mcs[NUM_NFAPI_SLOT]; +void read_channel_param(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t * pdu, int slot, int index) +{ + if (pdu == NULL) + { + LOG_E(NR_MAC,"PDU NULL\n"); + abort(); + } + + /* This function is executed for every pdsch pdu type in a dl_tti_request. We save + the assocaited MCS and RNTI value for each. The 'index' passed in is a count of + how many times we have called this function for a particular dl_tti_request. It + allows us to save MCS/RNTI data in correct indicies when multiple pdsch pdu's are received.*/ + for (int i = 0; i < NUM_NFAPI_SLOT; i++) + { + slot_rnti_mcs[i].latest = false; + } + + CHECK_INDEX(slot_rnti_mcs[slot].rnti, index); + CHECK_INDEX(slot_rnti_mcs[slot].mcs, index); + CHECK_INDEX(slot_rnti_mcs[slot].drop_flag, index); + slot_rnti_mcs[slot].rnti[index] = pdu->rnti; + slot_rnti_mcs[slot].mcs[index] = pdu->mcsIndex[0]; + slot_rnti_mcs[slot].rvIndex[index] = pdu->rvIndex[0]; + slot_rnti_mcs[slot].drop_flag[index] = false; + slot_rnti_mcs[slot].num_pdus = index+1; //index starts at 0 so we incrament to get num of pdus + slot_rnti_mcs[slot].latest = true; + LOG_D(NR_MAC, "Adding MCS %d and RNTI %x for slot_rnti_mcs[%d]\n", slot_rnti_mcs[slot].mcs[index], slot_rnti_mcs[slot].rnti[index], slot); + + return; +} + +float get_bler_val(uint8_t mcs, int sinr) +{ + // 4th col = dropped packets, 5th col = total packets + nr_bler_struct nr_bler_data[NR_NUM_MCS]; + float bler_val = 0.0; + CHECK_INDEX(nr_bler_data, mcs); + LOG_D(NR_MAC, "sinr %d min %d max %d\n", sinr, + (int)(nr_bler_data[mcs].bler_table[0][0] * 10), + (int)(nr_bler_data[mcs].bler_table[nr_bler_data[mcs].length - 1][0] * 10) + ); + + if (sinr < (int)(nr_bler_data[mcs].bler_table[0][0] * 10)) + { + LOG_D(NR_MAC, "MCS %d table. SINR is smaller than lowest SINR, bler_val is set based on lowest SINR in table\n", mcs); + bler_val = nr_bler_data[mcs].bler_table[0][4] / nr_bler_data[mcs].bler_table[0][5]; + return bler_val; + } + if (sinr > (int)(nr_bler_data[mcs].bler_table[nr_bler_data[mcs].length - 1][0] * 10)) + { + LOG_D(NR_MAC, "MCS %d table. SINR is greater than largest SINR. bler_val is set based on largest SINR in table\n", mcs); + bler_val = nr_bler_data[mcs].bler_table[(nr_bler_data[mcs].length - 1)][4] / nr_bler_data[mcs].bler_table[(nr_bler_data[mcs].length - 1)][5]; + return bler_val; + } + // Loop through bler table to find sinr_index + for (int i = 0; i < nr_bler_data[mcs].length; i++) + { + int temp_sinr = (int)(nr_bler_data[mcs].bler_table[i][0] * 10); + if (temp_sinr == sinr) + { + bler_val = nr_bler_data[mcs].bler_table[i][4] / nr_bler_data[mcs].bler_table[i][5]; + return bler_val; + } + // Linear interpolation when SINR is between indices + if (temp_sinr > sinr) + { + float bler_val1 = nr_bler_data[mcs].bler_table[i - 1][4] / nr_bler_data[mcs].bler_table[i - 1][5]; + float bler_val2 = nr_bler_data[mcs].bler_table[i][4] / nr_bler_data[mcs].bler_table[i][5]; + LOG_D(NR_MAC, "sinr %d min %f max %f\n", sinr, bler_val1, bler_val2); + return ((bler_val1 + bler_val2) / 2); + } + } + LOG_E(NR_MAC, "NO SINR INDEX FOUND!\n"); + abort(); + +} + +bool is_channel_modeling(void) +{ + /* TODO: For now we enable channel modeling based on the node_number. + Replace with a command line option to enable/disable channel modeling. + The LTE UE will crash when channel modeling is conducted for NSA + mode. It does not crash for LTE mode. We have not implemented channel + modeling for NSA mode yet. For now, we ensure only do do channel modeling + in LTE/NR mode. */ + return get_softmodem_params()->node_number == 0 && !get_softmodem_params()->nsa; +} + +bool should_drop_transport_block(int slot, uint16_t rnti) +{ + if (!is_channel_modeling()) + { + return false; + } + + /* We want to avoid dropping setup messages because this would be pathological. */ + NR_UE_MAC_INST_t *mac = get_mac_inst(0); + if (mac->ra.ra_state < RA_SUCCEEDED) + { + LOG_D(NR_MAC, "Not dropping because MAC state: %d", mac->ra.ra_state); + return false; + } + + /* Get block error rate (bler_val) from table based on every saved + MCS and SINR to be used as the cutoff rate for dropping packets. + Generate random uniform vairable to compare against bler_val. */ + int num_pdus = slot_rnti_mcs[slot].num_pdus; + assert(slot < 20 && slot >= 0); + LOG_D(NR_MAC, "rnti: %x num_pdus %d state %d slot %u sinr %f\n", + rnti, num_pdus, mac->ra.ra_state, slot, slot_rnti_mcs[slot].sinr); + assert(num_pdus > 0); + CHECK_INDEX(slot_rnti_mcs[slot].rnti, num_pdus); + CHECK_INDEX(slot_rnti_mcs[slot].mcs, num_pdus); + CHECK_INDEX(slot_rnti_mcs[slot].drop_flag, num_pdus); + int n = 0; + uint8_t mcs = 99; + for (n = 0; n < num_pdus; n++) + { + if (slot_rnti_mcs[slot].rnti[n] == rnti) + { + mcs = slot_rnti_mcs[slot].mcs[n]; + } + if (mcs != 99) + { + /* Use MCS to get the bler value. Since there can be multiple MCS + values for a particular slot, we verify that all PDUs are not + flagged for drop before returning. If even one is flagged for drop + we return immediately because we drop the entire packet. */ + + LOG_D(NR_MAC, "rnti: %x mcs %u slot %u sinr %f\n", + slot_rnti_mcs[slot].rnti[n], mcs, slot, slot_rnti_mcs[slot].sinr); + + float bler_val; + if (slot_rnti_mcs[slot].rvIndex[n] != 0) + bler_val = 0; + else + bler_val = get_bler_val(mcs, ((int)(slot_rnti_mcs[slot].sinr * 10))); + double drop_cutoff = ((double) rand() / (RAND_MAX)); + assert(drop_cutoff <= 1); + LOG_D(NR_MAC, "SINR = %f, Bler_val = %f, MCS = %"PRIu8"\n", slot_rnti_mcs[slot].sinr, bler_val, slot_rnti_mcs[slot].mcs[n]); + if (drop_cutoff <= bler_val) + { + slot_rnti_mcs[slot].drop_flag[n] = true; + LOG_T(NR_MAC, "We are dropping this packet. Bler_val = %f, MCS = %"PRIu8", slot = %d\n", bler_val, slot_rnti_mcs[slot].mcs[n], slot); + return slot_rnti_mcs[slot].drop_flag[n]; + } + } + + } + + if (mcs == 99) + { + LOG_E(NR_MAC, "NO MCS Found for rnti %x. slot_rnti_mcs[%d].mcs[%d] \n", rnti, slot, n); + abort(); + } + return false; +} diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.h b/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.h new file mode 100644 index 0000000000..549eb5c2e3 --- /dev/null +++ b/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.h @@ -0,0 +1,68 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ +#ifndef __NR_CHAN_MODEL_H__ +#define __NR_CHAN_MODEL_H__ + +#include +#include +#include +#include "openair2/NR_PHY_INTERFACE/NR_IF_Module.h" + +#define NR_NUM_MCS 29 +#define NUM_SINR 100 +#define NUM_BLER_COL 13 +#define NUM_NFAPI_SLOT 20 +#define NR_NUM_LAYER 1 +#define MAX_CHAN_PARAMS 256 + +typedef struct nr_phy_channel_params_t +{ + uint16_t sfn_slot; + uint16_t message_id; + uint16_t nb_of_sinrs; + float sinr[NR_NUM_LAYER]; +} nr_phy_channel_params_t; + +typedef struct +{ + uint8_t slot; + uint16_t rnti[MAX_CHAN_PARAMS]; + uint8_t mcs[MAX_CHAN_PARAMS]; + uint8_t rvIndex[MAX_CHAN_PARAMS]; + float sinr; + uint16_t num_pdus; + bool drop_flag[MAX_CHAN_PARAMS]; + bool latest; +} slot_rnti_mcs_s; + +typedef struct +{ + uint16_t length; + float bler_table[NUM_SINR][NUM_BLER_COL]; +} nr_bler_struct; + +void read_channel_param(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t * pdu, int sf, int index); +void save_pdsch_pdu_for_crnti(nfapi_nr_dl_tti_request_t *dl_tti_request); +float get_bler_val(uint8_t mcs, int sinr); +bool should_drop_transport_block(int slot, uint16_t rnti); +bool is_channel_modeling(void); + +#endif diff --git a/openair2/PHY_INTERFACE/phy_stub_UE.c b/openair2/PHY_INTERFACE/phy_stub_UE.c index c4650f18f3..cd57ea9ff1 100644 --- a/openair2/PHY_INTERFACE/phy_stub_UE.c +++ b/openair2/PHY_INTERFACE/phy_stub_UE.c @@ -1956,7 +1956,7 @@ static int get_mcs_from_sinr(float sinr) static int get_cqi_from_mcs(void) { - static const int mcs_to_cqi[] = {0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15}; + static const int mcs_to_cqi[] = {0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; assert(NUM_ELEMENTS(mcs_to_cqi) == NUM_MCS); int sf = 0; while(sf < NUM_NFAPI_SUBFRAME) diff --git a/openair2/PHY_INTERFACE/phy_stub_UE.h b/openair2/PHY_INTERFACE/phy_stub_UE.h index d68d1dffdd..fe0e7be12e 100644 --- a/openair2/PHY_INTERFACE/phy_stub_UE.h +++ b/openair2/PHY_INTERFACE/phy_stub_UE.h @@ -21,7 +21,7 @@ //#include "openair1/PHY/LTE_TRANSPORT/defs.h" #include "queue_t.h" -#define NUM_MCS 28 +#define NUM_MCS 29 #define NUM_SINR 100 #define NUM_BLER_COL 13 #define LTE_NUM_LAYER 1 From 40049db9c926da89d3cbae3bb48b7e5c213d90d3 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 15 Jun 2022 18:41:36 +0200 Subject: [PATCH 135/267] separate dl and ul bwp structures --- openair1/SIMULATION/NR_PHY/dlsim.c | 12 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 86 ++++----- .../LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 12 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 41 ++-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 18 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 177 ++++++++++-------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c | 12 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 43 +++-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 32 ++-- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 11 +- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 35 ++-- 11 files changed, 241 insertions(+), 238 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index b5f946b8ab..bd0fe510c7 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -272,7 +272,7 @@ void nr_dlsim_preprocessor(module_id_t module_id, NR_UE_info_t *UE_info = RC.nrmac[module_id]->UE_info.list[0]; AssertFatal(RC.nrmac[module_id]->UE_info.list[1]==NULL, "can have only a single UE\n"); NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl; - NR_UE_BWP_t *BWP = &UE_info->current_BWP; + NR_UE_DL_BWP_t *BWP = &UE_info->current_DL_BWP; NR_ServingCellConfigCommon_t *scc = RC.nrmac[0]->common_channels[0].ServingCellConfigCommon; /* manually set free CCE to 0 */ @@ -299,10 +299,10 @@ void nr_dlsim_preprocessor(module_id_t module_id, sched_pdsch->mcs = g_mcsIndex; /* the following might override the table that is mandated by RRC * configuration */ - ps->mcsTableIdx = g_mcsTableIdx; + BWP->mcsTableIdx = g_mcsTableIdx; - sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, ps->mcsTableIdx); - sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, ps->mcsTableIdx); + sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, BWP->mcsTableIdx); + sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, BWP->mcsTableIdx); sched_pdsch->tb_size = nr_compute_tbs(sched_pdsch->Qm, sched_pdsch->R, sched_pdsch->rbSize, @@ -330,7 +330,7 @@ void nr_dlsim_preprocessor(module_id_t module_id, AssertFatal(sched_pdsch->rbStart >= 0, "invalid rbStart %d\n", sched_pdsch->rbStart); AssertFatal(sched_pdsch->rbSize > 0, "invalid rbSize %d\n", sched_pdsch->rbSize); AssertFatal(sched_pdsch->mcs >= 0, "invalid mcs %d\n", sched_pdsch->mcs); - AssertFatal(ps->mcsTableIdx >= 0 && ps->mcsTableIdx <= 2, "invalid mcsTableIdx %d\n", ps->mcsTableIdx); + AssertFatal(BWP->mcsTableIdx >= 0 && BWP->mcsTableIdx <= 2, "invalid mcsTableIdx %d\n", BWP->mcsTableIdx); } typedef struct { @@ -835,7 +835,7 @@ int main(int argc, char **argv) N_RB_DL = gNB->frame_parms.N_RB_DL; NR_UE_info_t *UE_info = RC.nrmac[0]->UE_info.list[0]; - configure_UE_BWP(RC.nrmac[0], &UE_info->current_BWP, scc, &UE_info->UE_sched_ctrl, NULL, UE_info->CellGroup); + configure_UE_BWP(RC.nrmac[0], scc, &UE_info->UE_sched_ctrl, NULL, UE_info); // stub to configure frame_parms // nr_phy_config_request_sim(gNB,N_RB_DL,N_RB_DL,mu,Nid_cell,SSB_positions); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 1bbbc6ac85..d29e60b869 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -568,7 +568,7 @@ void nr_initiate_ra_proc(module_id_t module_idP, ra_rnti = 1 + symbol + (slotP * 14) + (freq_index * 14 * 80) + (ul_carrier_id * 14 * 80 * 8); // Configure RA BWP - configure_UE_BWP(nr_mac, &ra->BWP, scc, NULL, ra, ra->CellGroup); + configure_UE_BWP(nr_mac, scc, NULL, ra, NULL); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 1); @@ -606,7 +606,7 @@ void nr_initiate_ra_proc(module_id_t module_idP, slotP, &msg2_frame, &msg2_slot, - ra->BWP.dl_scs, + ra->DL_BWP.scs, scc, frame_type, monitoring_slot_period, @@ -697,19 +697,19 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t gNB_MAC_INST *nr_mac = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - NR_UE_BWP_t *ra_BWP = &ra->BWP; + NR_UE_UL_BWP_t *UL_BWP = &ra->UL_BWP; NR_BWP_Uplink_t *ubwp = NULL; NR_BWP_UplinkDedicated_t *ubwpd = NULL; NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = NULL; if(ra->CellGroup) { - ubwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra_BWP->ul_bwp_id-1]; + ubwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[UL_BWP->bwp_id-1]; ubwpd = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; pusch_TimeDomainAllocationList = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; } else pusch_TimeDomainAllocationList = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; - int mu = ra_BWP->ul_scs; + int mu = UL_BWP->scs; uint8_t K2 = *pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->k2; const int sched_frame = frame + (slot + K2 >= nr_slots_per_frame[mu]); const int sched_slot = (slot + K2) % nr_slots_per_frame[mu]; @@ -846,17 +846,17 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t ra->Msg3_tda_id, ra->msg3_TPC, 0, // not used in format 0_0 - &ra->BWP); + &ra->UL_BWP); fill_dci_pdu_rel15(scc, ra->CellGroup, - ra_BWP, + &ra->DL_BWP, dci_pdu, &uldci_payload, NR_UL_DCI_FORMAT_0_0, NR_RNTI_TC, pusch_pdu->bwp_size, - ra_BWP->ul_bwp_id, + UL_BWP->bwp_id, coresetid, nr_mac->cset0_bwp_size); @@ -894,9 +894,9 @@ void nr_get_Msg3alloc(module_id_t module_id, uint16_t msg3_nb_rb = 8; // sdu has 6 or 8 bytes frame_type_t frame_type = RC.nrmac[module_id]->common_channels->frame_type; - NR_UE_BWP_t *ra_BWP = &ra->BWP; + NR_UE_UL_BWP_t *UL_BWP = &ra->UL_BWP; - int mu = ra_BWP->ul_scs; + int mu = UL_BWP->scs; int StartSymbolIndex = 0; int NrOfSymbols = 0; int startSymbolAndLength = 0; @@ -969,9 +969,9 @@ void nr_get_Msg3alloc(module_id_t module_id, int bwpSize = NRRIV2BW(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); int bwpStart = NRRIV2PRBOFFSET(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - if (bwpSize != ra_BWP->ul_BWPSize || bwpStart != ra_BWP->ul_BWPStart) { - int act_bwp_start = ra_BWP->ul_BWPStart; - int act_bwp_size = ra_BWP->ul_BWPSize; + if (bwpSize != UL_BWP->BWPSize || bwpStart != UL_BWP->BWPStart) { + int act_bwp_start = UL_BWP->BWPStart; + int act_bwp_size = UL_BWP->BWPSize; if (!((bwpStart >= act_bwp_start) && ((bwpStart+bwpSize) <= (act_bwp_start+act_bwp_size)))) bwpStart = act_bwp_start; } @@ -1080,7 +1080,7 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t gNB_MAC_INST *mac = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = &mac->common_channels[CC_id]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - NR_UE_BWP_t *ra_BWP = &ra->BWP; + NR_UE_UL_BWP_t *UL_BWP = &ra->UL_BWP; if (ra->state == RA_IDLE) { LOG_W(NR_MAC,"RA is not active for RA %X. skipping msg3 scheduling\n", ra->rnti); @@ -1114,13 +1114,13 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t memset(pusch_pdu, 0, sizeof(nfapi_nr_pusch_pdu_t)); int ibwp_size = NRRIV2BW(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - int scs = ra_BWP->ul_scs; + int scs = UL_BWP->scs; int fh = 0; int startSymbolAndLength = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; int mappingtype = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->mappingType; if (ra->CellGroup) { - NR_BWP_Uplink_t *ubwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra_BWP->ul_bwp_id - 1]; + NR_BWP_Uplink_t *ubwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[UL_BWP->bwp_id - 1]; startSymbolAndLength = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; mappingtype = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->mappingType; @@ -1154,7 +1154,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra gNB_MAC_INST *nr_mac = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; - NR_UE_BWP_t *ra_BWP = &ra->BWP; + NR_UE_DL_BWP_t *DL_BWP = &ra->DL_BWP; if ((ra->Msg2_frame == frameP) && (ra->Msg2_slot == slotP)) { @@ -1165,13 +1165,13 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; NR_SearchSpace_t *ss = ra->ra_ss; - NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList = ra_BWP->tdaList; + NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList = DL_BWP->tdaList; long BWPStart = 0; long BWPSize = 0; NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config = NULL; if(*ss->controlResourceSetId!=0) { - BWPStart = ra_BWP->dl_BWPStart; + BWPStart = DL_BWP->BWPStart; BWPSize = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); } else { type0_PDCCH_CSS_config = &nr_mac->type0_PDCCH_CSS_config[ra->beam_id]; @@ -1265,16 +1265,8 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra // information to data and is reset every slot. const int pduindex = nr_mac->pdu_index[CC_id]++; - NR_PDSCH_Config_t *pdsch_Config = ra_BWP->pdsch_Config; - uint8_t mcsTableIdx = 0; - if (pdsch_Config && - pdsch_Config->mcs_Table) { - if (*pdsch_Config->mcs_Table == 0) - mcsTableIdx = 1; - else - mcsTableIdx = 2; - } - else mcsTableIdx = 0; + NR_PDSCH_Config_t *pdsch_Config = DL_BWP->pdsch_Config; + uint8_t mcsTableIdx = DL_BWP->mcsTableIdx; int dmrsConfigType=0; if (pdsch_Config && @@ -1288,7 +1280,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra pdsch_pdu_rel15->pduIndex = pduindex; pdsch_pdu_rel15->BWPSize = BWPSize; pdsch_pdu_rel15->BWPStart = BWPStart; - pdsch_pdu_rel15->SubcarrierSpacing = ra_BWP->dl_scs; + pdsch_pdu_rel15->SubcarrierSpacing = DL_BWP->scs; pdsch_pdu_rel15->CyclicPrefix = 0; pdsch_pdu_rel15->NrOfCodewords = 1; pdsch_pdu_rel15->mcsTable[0] = mcsTableIdx; @@ -1401,13 +1393,13 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra fill_dci_pdu_rel15(scc, ra->CellGroup, - ra_BWP, + DL_BWP, &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci - 1], &dci_payload, NR_DL_DCI_FORMAT_1_0, NR_RNTI_RA, BWPSize, - ra_BWP->dl_bwp_id, + DL_BWP->bwp_id, coresetid, nr_mac->cset0_bwp_size); @@ -1416,7 +1408,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra // Program UL processing for Msg3 NR_BWP_Uplink_t *ubwp = ra->CellGroup ? - ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra_BWP->ul_bwp_id-1] : + ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra->UL_BWP.bwp_id-1] : NULL; nr_get_Msg3alloc(module_idP, CC_id, scc, ubwp, slotP, frameP, ra, nr_mac->tdd_beam_association); nr_add_msg3(module_idP, CC_id, frameP, slotP, ra, (uint8_t *) &tx_req->TLVs[0].value.direct[0]); @@ -1456,7 +1448,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra gNB_MAC_INST *nr_mac = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; - NR_UE_BWP_t *ra_BWP = &ra->BWP; + NR_UE_DL_BWP_t *DL_BWP = &ra->DL_BWP; if (ra->Msg4_frame == frameP && ra->Msg4_slot == slotP ) { @@ -1467,7 +1459,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra NR_SearchSpace_t *ss = ra->ra_ss; NR_ControlResourceSet_t *coreset = ra->coreset; - NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList = ra_BWP->tdaList; + NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList = DL_BWP->tdaList; AssertFatal(coreset!=NULL,"Coreset cannot be null for RA-Msg4\n"); @@ -1490,8 +1482,8 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra long BWPSize = 0; NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config = NULL; if(*ss->controlResourceSetId!=0) { - BWPStart = ra_BWP->dl_BWPStart; - BWPSize = ra_BWP->dl_BWPSize; + BWPStart = DL_BWP->BWPStart; + BWPSize = DL_BWP->BWPSize; } else { type0_PDCCH_CSS_config = &nr_mac->type0_PDCCH_CSS_config[ra->beam_id]; BWPStart = type0_PDCCH_CSS_config->cset_start_rb; @@ -1601,7 +1593,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra uint16_t N_DMRS_SLOT = get_num_dmrs(dlDmrsSymbPos); - NR_PDSCH_Config_t *pdsch_Config = ra_BWP->pdsch_Config; + NR_PDSCH_Config_t *pdsch_Config = DL_BWP->pdsch_Config; int dmrsConfigType=0; if (pdsch_Config && pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA && @@ -1627,15 +1619,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra N_PRB_DMRS = nr_mac->sched_ctrlCommon->pdsch_semi_static.numDmrsCdmGrpsNoData * 4; } - uint8_t mcsTableIdx = 0; - if (pdsch_Config && - pdsch_Config->mcs_Table) { - if (*pdsch_Config->mcs_Table == 0) - mcsTableIdx = 1; - else - mcsTableIdx = 2; - } - else mcsTableIdx = 0; + uint8_t mcsTableIdx = DL_BWP->mcsTableIdx; int rbStart = 0; int rbSize = 0; @@ -1711,7 +1695,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra pdsch_pdu_rel15->pduIndex = pduindex; pdsch_pdu_rel15->BWPSize = BWPSize; pdsch_pdu_rel15->BWPStart = BWPStart; - pdsch_pdu_rel15->SubcarrierSpacing = ra_BWP->dl_scs; + pdsch_pdu_rel15->SubcarrierSpacing = DL_BWP->scs; pdsch_pdu_rel15->CyclicPrefix = 0; pdsch_pdu_rel15->NrOfCodewords = 1; int R = nr_get_code_rate_dl(mcsIndex,mcsTableIdx); @@ -1806,13 +1790,13 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra fill_dci_pdu_rel15(scc, ra->CellGroup, - ra_BWP, + DL_BWP, &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci - 1], &dci_payload, NR_DL_DCI_FORMAT_1_0, NR_RNTI_TC, pdsch_pdu_rel15->BWPSize, - ra_BWP->dl_bwp_id, + DL_BWP->bwp_id, coresetid, nr_mac->cset0_bwp_size); @@ -1908,7 +1892,7 @@ void nr_check_Msg4_Ack(module_id_t module_id, int CC_id, frame_t frame, sub_fram uint32_t delay_ms = servingCellConfig && servingCellConfig->downlinkBWP_ToAddModList ? NR_RRC_SETUP_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_SETUP_DELAY_MS; - sched_ctrl->rrc_processing_timer = (delay_ms << ra->BWP.dl_scs); + sched_ctrl->rrc_processing_timer = (delay_ms << ra->DL_BWP.scs); LOG_I(NR_MAC, "(%d.%d) Activating RRC processing timer for UE %04x with %d ms\n", frame, slot, UE->rnti, delay_ms); } else { LOG_I(NR_MAC, "(ue rnti 0x%04x) RA Procedure failed at Msg4!\n", ra->rnti); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index 743358f47d..a06c3f06ed 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -352,7 +352,6 @@ uint32_t schedule_control_sib1(module_id_t module_id, } gNB_mac->sched_ctrlCommon->pdsch_semi_static.time_domain_allocation = time_domain_allocation; - gNB_mac->sched_ctrlCommon->pdsch_semi_static.mcsTableIdx = 0; gNB_mac->sched_ctrlCommon->sched_pdsch.mcs = 0; // starting from mcs 0 gNB_mac->sched_ctrlCommon->num_total_bytes = num_total_bytes; @@ -389,6 +388,7 @@ uint32_t schedule_control_sib1(module_id_t module_id, uint8_t N_PRB_DMRS = gNB_mac->sched_ctrlCommon->pdsch_semi_static.numDmrsCdmGrpsNoData * 6; uint16_t dmrs_length = get_num_dmrs(dlDmrsSymbPos); LOG_D(MAC,"dlDmrsSymbPos %x\n",dlDmrsSymbPos); + int mcsTableIdx = 0; int rbSize = 0; uint32_t TBS = 0; do { @@ -400,8 +400,8 @@ uint32_t schedule_control_sib1(module_id_t module_id, else break; } - TBS = nr_compute_tbs(nr_get_Qm_dl(gNB_mac->sched_ctrlCommon->sched_pdsch.mcs, gNB_mac->sched_ctrlCommon->pdsch_semi_static.mcsTableIdx), - nr_get_code_rate_dl(gNB_mac->sched_ctrlCommon->sched_pdsch.mcs, gNB_mac->sched_ctrlCommon->pdsch_semi_static.mcsTableIdx), + TBS = nr_compute_tbs(nr_get_Qm_dl(gNB_mac->sched_ctrlCommon->sched_pdsch.mcs, mcsTableIdx), + nr_get_code_rate_dl(gNB_mac->sched_ctrlCommon->sched_pdsch.mcs, mcsTableIdx), rbSize, nrOfSymbols, N_PRB_DMRS * dmrs_length,0, 0,1) >> 3; } while (TBS < gNB_mac->sched_ctrlCommon->num_total_bytes); @@ -443,7 +443,7 @@ void nr_fill_nfapi_dl_sib1_pdu(int Mod_idP, gNB_MAC_INST *gNB_mac = RC.nrmac[Mod_idP]; NR_COMMON_channels_t *cc = gNB_mac->common_channels; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - + int mcsTableIdx = 0; nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdcch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs]; memset((void*)dl_tti_pdcch_pdu,0,sizeof(nfapi_nr_dl_tti_request_pdu_t)); dl_tti_pdcch_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE; @@ -494,9 +494,9 @@ void nr_fill_nfapi_dl_sib1_pdu(int Mod_idP, pdsch_pdu_rel15->rbSize = gNB_mac->sched_ctrlCommon->sched_pdsch.rbSize; pdsch_pdu_rel15->VRBtoPRBMapping = 0; pdsch_pdu_rel15->qamModOrder[0] = nr_get_Qm_dl(gNB_mac->sched_ctrlCommon->sched_pdsch.mcs, - gNB_mac->sched_ctrlCommon->pdsch_semi_static.mcsTableIdx); + mcsTableIdx); pdsch_pdu_rel15->TBSize[0] = TBS; - pdsch_pdu_rel15->mcsTable[0] = gNB_mac->sched_ctrlCommon->pdsch_semi_static.mcsTableIdx; + pdsch_pdu_rel15->mcsTable[0] = mcsTableIdx; pdsch_pdu_rel15->StartSymbolIndex = StartSymbolIndex; pdsch_pdu_rel15->NrOfSymbols = NrOfSymbols; pdsch_pdu_rel15->dlDmrsSymbPos = dlDmrsSymbPos; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 829e288eae..70f4a98a99 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -376,7 +376,7 @@ bool allocate_dl_retransmission(module_id_t module_id, gNB_MAC_INST *nr_mac = RC.nrmac[module_id]; const NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels->ServingCellConfigCommon; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_BWP_t *BWP = &UE->current_BWP; + NR_UE_DL_BWP_t *BWP = &UE->current_DL_BWP; NR_sched_pdsch_t *retInfo = &sched_ctrl->harq_processes[current_harq_pid].sched_pdsch; NR_CellGroupConfig_t *cg = UE->CellGroup; @@ -388,7 +388,7 @@ bool allocate_dl_retransmission(module_id_t module_id, cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; const int coresetid = sched_ctrl->coreset->controlResourceSetId; - const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : UE->current_BWP.dl_BWPSize; + const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : BWP->BWPSize; int rbStart = 0; // start wrt BWPstart NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; @@ -567,6 +567,7 @@ void pf_dl(module_id_t module_id, continue; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_UE_DL_BWP_t *BWP = &UE->current_DL_BWP; if (sched_ctrl->ul_failure==1 && get_softmodem_params()->phy_test==0) continue; @@ -606,12 +607,12 @@ void pf_dl(module_id_t module_id, /* Calculate coeff */ const NR_bler_options_t *bo = &mac->dl_bler; - const int max_mcs_table = ps->mcsTableIdx == 1 ? 27 : 28; + const int max_mcs_table = BWP->mcsTableIdx == 1 ? 27 : 28; const int max_mcs = min(sched_ctrl->dl_max_mcs, max_mcs_table); sched_pdsch->mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->dl_bler_stats, max_mcs, frame); UE->layers = set_dl_nrOfLayers(sched_ctrl); - const uint8_t Qm = nr_get_Qm_dl(sched_pdsch->mcs, ps->mcsTableIdx); - const uint16_t R = nr_get_code_rate_dl(sched_pdsch->mcs, ps->mcsTableIdx); + const uint8_t Qm = nr_get_Qm_dl(sched_pdsch->mcs, BWP->mcsTableIdx); + const uint16_t R = nr_get_code_rate_dl(sched_pdsch->mcs, BWP->mcsTableIdx); uint32_t tbs = nr_compute_tbs(Qm, R, 1, /* rbSize */ @@ -650,12 +651,12 @@ void pf_dl(module_id_t module_id, NR_UE_sched_ctrl_t *sched_ctrl = &iterator->UE->UE_sched_ctrl; const uint16_t rnti = iterator->UE->rnti; - NR_UE_BWP_t *BWP = &iterator->UE->current_BWP; + NR_UE_DL_BWP_t *BWP = &iterator->UE->current_DL_BWP; const int coresetid = sched_ctrl->coreset->controlResourceSetId; const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : - BWP->dl_BWPSize; + BWP->BWPSize; int rbStart = 0; // start wrt BWPstart if (sched_ctrl->available_dl_harq.head < 0) { @@ -744,8 +745,8 @@ void pf_dl(module_id_t module_id, while (rbStart + max_rbSize < bwpSize && (rballoc_mask[rbStart + max_rbSize] & slbitmap) == slbitmap) max_rbSize++; - sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, ps->mcsTableIdx); - sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, ps->mcsTableIdx); + sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, BWP->mcsTableIdx); + sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, BWP->mcsTableIdx); sched_pdsch->pucch_allocation = alloc; uint32_t TBS = 0; uint16_t rbSize; @@ -791,7 +792,7 @@ void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t /* This is temporary and it assumes all UEs have the same BWP and TDA*/ NR_UE_info_t *UE=UE_info->list[0]; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_BWP_t *BWP = &UE->current_BWP; + NR_UE_DL_BWP_t *BWP = &UE->current_DL_BWP; const int tda = get_dl_tda(RC.nrmac[module_id], scc, slot); int startSymbolIndex, nrOfSymbols; const struct NR_PDSCH_TimeDomainResourceAllocationList *tdaList = BWP->tdaList; @@ -801,8 +802,8 @@ void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t const int coresetid = sched_ctrl->coreset->controlResourceSetId; - const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : BWP->dl_BWPSize; - const uint16_t BWPStart = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_start : BWP->dl_BWPStart; + const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : BWP->BWPSize; + const uint16_t BWPStart = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_start : BWP->BWPStart; const uint16_t slbitmap = SL_to_bitmap(startSymbolIndex, nrOfSymbols); uint16_t *vrb_map = RC.nrmac[module_id]->common_channels[CC_id].vrb_map; @@ -879,7 +880,7 @@ void nr_schedule_ue_spec(module_id_t module_id, UE_iterator(UE_info->list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_BWP_t *current_BWP = &UE->current_BWP; + NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP; if (sched_ctrl->ul_failure==1 && get_softmodem_params()->phy_test==0) continue; @@ -963,7 +964,7 @@ void nr_schedule_ue_spec(module_id_t module_id, NR_SearchSpace_t *ss = sched_ctrl->search_space; - const int bwp_id = current_BWP->dl_bwp_id; + const int bwp_id = current_BWP->bwp_id; const int coresetid = sched_ctrl->coreset->controlResourceSetId; /* look up the PDCCH PDU for this CC, BWP, and CORESET. If it does not exist, create it */ @@ -1001,19 +1002,19 @@ void nr_schedule_ue_spec(module_id_t module_id, pdsch_pdu->BWPSize = gNB_mac->cset0_bwp_size; pdsch_pdu->BWPStart = gNB_mac->cset0_bwp_start; } else { - pdsch_pdu->BWPSize = current_BWP->dl_BWPSize; - pdsch_pdu->BWPStart = current_BWP->dl_BWPStart; + pdsch_pdu->BWPSize = current_BWP->BWPSize; + pdsch_pdu->BWPStart = current_BWP->BWPStart; } - pdsch_pdu->SubcarrierSpacing = current_BWP->dl_scs; - pdsch_pdu->CyclicPrefix = current_BWP->dl_cyclicprefix ? *current_BWP->dl_cyclicprefix : 0; + pdsch_pdu->SubcarrierSpacing = current_BWP->scs; + pdsch_pdu->CyclicPrefix = current_BWP->cyclicprefix ? *current_BWP->cyclicprefix : 0; // Codeword information pdsch_pdu->NrOfCodewords = 1; //number of information bits per 1024 coded bits expressed in 0.1 bit units pdsch_pdu->targetCodeRate[0] = R; pdsch_pdu->qamModOrder[0] = Qm; pdsch_pdu->mcsIndex[0] = sched_pdsch->mcs; - pdsch_pdu->mcsTable[0] = ps->mcsTableIdx; + pdsch_pdu->mcsTable[0] = current_BWP->mcsTableIdx; AssertFatal(harq!=NULL,"harq is null\n"); AssertFatal(harq->round<4,"%d",harq->round); pdsch_pdu->rvIndex[0] = nr_rv_round_map[harq->round]; @@ -1056,7 +1057,7 @@ void nr_schedule_ue_spec(module_id_t module_id, // Maximum number of PRBs across all configured DL BWPs int scc_bwpsize = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); int bw_tbslbrm = get_bw_tbslbrm(scc_bwpsize, cg); - pdsch_pdu->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(ps->mcsTableIdx, + pdsch_pdu->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(current_BWP->mcsTableIdx, bw_tbslbrm, nl_tbslbrm); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index 94b3f99fa0..66b7f2e720 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -195,7 +195,7 @@ void nr_preprocessor_phytest(module_id_t module_id, NR_UE_info_t *UE = RC.nrmac[module_id]->UE_info.list[0]; NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_BWP_t *BWP = &UE->current_BWP; + NR_UE_DL_BWP_t *BWP = &UE->current_DL_BWP; const int CC_id = 0; const int tda = get_dl_tda(RC.nrmac[module_id], scc, slot); @@ -205,8 +205,8 @@ void nr_preprocessor_phytest(module_id_t module_id, nr_set_pdsch_semi_static(BWP, scc, UE->CellGroup, tda, target_dl_Nl,sched_ctrl , ps); /* find largest unallocated chunk */ - const int bwpSize = BWP->dl_BWPSize; - const int BWPStart = BWP->dl_BWPStart; + const int bwpSize = BWP->BWPSize; + const int BWPStart = BWP->BWPStart; int rbStart = 0; int rbSize = 0; @@ -311,8 +311,8 @@ void nr_preprocessor_phytest(module_id_t module_id, sched_pdsch->rbSize = rbSize; sched_pdsch->mcs = target_dl_mcs; - sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, ps->mcsTableIdx); - sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, ps->mcsTableIdx); + sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, BWP->mcsTableIdx); + sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, BWP->mcsTableIdx); sched_pdsch->tb_size = nr_compute_tbs(sched_pdsch->Qm, sched_pdsch->R, sched_pdsch->rbSize, @@ -352,8 +352,8 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ const int CC_id = 0; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_BWP_t *BWP = &UE->current_BWP; - const int mu = BWP->ul_scs; + NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; + const int mu = BWP->scs; const struct NR_PUSCH_TimeDomainResourceAllocationList *tdaList = sched_ctrl->active_ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; @@ -400,8 +400,8 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ uint16_t rbStart = 0; uint16_t rbSize; - const int bw = BWP->ul_BWPSize; - const int BWPStart = BWP->ul_BWPStart; + const int bw = BWP->BWPSize; + const int BWPStart = BWP->BWPStart; if (target_ul_bw>bw) rbSize = bw; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 2fd3c0620a..8fdf0fa9a1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -528,7 +528,7 @@ bool nr_find_nb_rb(uint16_t Qm, return *tbs >= bytes && *nb_rb <= nb_rb_max; } -void nr_set_pdsch_semi_static(const NR_UE_BWP_t *BWP, +void nr_set_pdsch_semi_static(const NR_UE_DL_BWP_t *BWP, const NR_ServingCellConfigCommon_t *scc, const NR_CellGroupConfig_t *secondaryCellGroup, int tda, @@ -951,12 +951,12 @@ void config_uldci(const NR_SIB1_t *sib1, int time_domain_assignment, uint8_t tpc, int n_ubwp, - NR_UE_BWP_t *BWP) { + NR_UE_UL_BWP_t *UBWP) { - int bwp_id = BWP->ul_bwp_id; + int bwp_id = UBWP->bwp_id; dci_pdu_rel15->frequency_domain_assignment.val = - PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size, pusch_pdu->rb_start, BWP->ul_BWPSize); + PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size, pusch_pdu->rb_start, UBWP->BWPSize); dci_pdu_rel15->time_domain_assignment.val = time_domain_assignment; dci_pdu_rel15->frequency_hopping_flag.val = pusch_pdu->frequency_hopping; dci_pdu_rel15->mcs = pusch_pdu->mcs_index; @@ -1163,12 +1163,12 @@ void nr_configure_pucch(const NR_SIB1_t *sib1, else pucch_pdu->hopping_id = *scc->physCellId; - NR_UE_BWP_t *BWP = &UE->current_BWP; + NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; - pucch_pdu->bwp_size = BWP->ul_BWPSize; - pucch_pdu->bwp_start = BWP->ul_BWPStart; - pucch_pdu->subcarrier_spacing = BWP->ul_scs; - pucch_pdu->cyclic_prefix = (BWP->ul_cyclicprefix==NULL) ? 0 : *BWP->ul_cyclicprefix; + pucch_pdu->bwp_size = BWP->BWPSize; + pucch_pdu->bwp_start = BWP->BWPStart; + pucch_pdu->subcarrier_spacing = BWP->scs; + pucch_pdu->cyclic_prefix = (BWP->cyclicprefix==NULL) ? 0 : *BWP->cyclicprefix; if (r_pucch<0 || bwp ){ LOG_D(NR_MAC,"pucch_acknak: Filling dedicated configuration for PUCCH\n"); // we have either a dedicated BWP or Dedicated PUCCH configuration on InitialBWP @@ -1372,7 +1372,7 @@ void set_r_pucch_parms(int rsetindex, void prepare_dci(const NR_CellGroupConfig_t *CellGroup, - const NR_UE_BWP_t *BWP, + const NR_UE_DL_BWP_t *BWP, dci_pdu_rel15_t *dci_pdu_rel15, nr_dci_format_t format, int bwp_id) { @@ -1465,7 +1465,7 @@ void prepare_dci(const NR_CellGroupConfig_t *CellGroup, void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, const NR_CellGroupConfig_t *CellGroup, - const NR_UE_BWP_t *BWP, + const NR_UE_DL_BWP_t *BWP, nfapi_nr_dl_dci_pdu_t *pdcch_dci_pdu, dci_pdu_rel15_t *dci_pdu_rel15, int dci_format, @@ -2290,18 +2290,31 @@ void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr) } void configure_UE_BWP(gNB_MAC_INST *nr_mac, - NR_UE_BWP_t *BWP, NR_ServingCellConfigCommon_t *scc, NR_UE_sched_ctrl_t *sched_ctrl, NR_RA_t *ra, - NR_CellGroupConfig_t *CellGroup) { + NR_UE_info_t *UE) { + NR_CellGroupConfig_t *CellGroup; + NR_UE_DL_BWP_t *DL_BWP; + NR_UE_UL_BWP_t *UL_BWP; + + if (ra) { + DL_BWP = &ra->DL_BWP; + UL_BWP = &ra->UL_BWP; + CellGroup = ra->CellGroup; + } + else { + DL_BWP = &UE->current_DL_BWP; + UL_BWP = &UE->current_UL_BWP; + CellGroup = UE->CellGroup; + } NR_BWP_Downlink_t *dl_bwp = NULL; NR_BWP_Uplink_t *ul_bwp = NULL; NR_BWP_DownlinkDedicated_t *bwpd = NULL; NR_BWP_UplinkDedicated_t *ubwpd = NULL; - BWP->n_dl_bwp = 1; - int old_dl_bwp_id = BWP->dl_bwp_id; + DL_BWP->n_dl_bwp = 1; + int old_dl_bwp_id = DL_BWP->bwp_id; int target_ss; @@ -2315,33 +2328,31 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, // (re)configuring BWP // TODO BWP switching not via RRC reconfiguration // via RRC if firstActiveXlinkBWP_Id is NULL, MAC stays on the same BWP as before - if (servingCellConfig->firstActiveDownlinkBWP_Id) { - BWP->dl_bwp_id = *servingCellConfig->firstActiveDownlinkBWP_Id; - BWP->ul_bwp_id = *servingCellConfig->firstActiveDownlinkBWP_Id; - } + if (servingCellConfig->firstActiveDownlinkBWP_Id) + DL_BWP->bwp_id = *servingCellConfig->firstActiveDownlinkBWP_Id; if (servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id) - BWP->ul_bwp_id = *servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id; + UL_BWP->bwp_id = *servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id; const struct NR_ServingCellConfig__downlinkBWP_ToAddModList *bwpList = servingCellConfig->downlinkBWP_ToAddModList; if(bwpList) - BWP->n_dl_bwp = bwpList->list.count; - if (BWP->dl_bwp_id>0) { + DL_BWP->n_dl_bwp = bwpList->list.count; + if (DL_BWP->bwp_id>0) { for (int i=0; ilist.count; i++) { dl_bwp = bwpList->list.array[i]; - if(dl_bwp->bwp_Id == BWP->dl_bwp_id) + if(dl_bwp->bwp_Id == DL_BWP->bwp_id) break; } - AssertFatal(dl_bwp!=NULL,"Couldn't find DLBWP corresponding to BWP ID %ld\n",BWP->dl_bwp_id); + AssertFatal(dl_bwp!=NULL,"Couldn't find DLBWP corresponding to BWP ID %ld\n",DL_BWP->bwp_id); } const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList; - if (BWP->ul_bwp_id>0) { + if (UL_BWP->bwp_id>0) { for (int i=0; ilist.count; i++) { ul_bwp = ubwpList->list.array[i]; - if(ul_bwp->bwp_Id == BWP->ul_bwp_id) + if(ul_bwp->bwp_Id == UL_BWP->bwp_id) break; } - AssertFatal(ul_bwp!=NULL,"Couldn't find DLBWP corresponding to BWP ID %ld\n",BWP->ul_bwp_id); + AssertFatal(ul_bwp!=NULL,"Couldn't find DLBWP corresponding to BWP ID %ld\n",UL_BWP->bwp_id); } // selection of dedicated BWPs @@ -2354,43 +2365,54 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, else ubwpd = servingCellConfig->uplinkConfig->initialUplinkBWP; - BWP->pdsch_Config = bwpd->pdsch_Config->choice.setup; + DL_BWP->pdsch_Config = bwpd->pdsch_Config->choice.setup; } else { - BWP->dl_bwp_id = 0; - BWP->ul_bwp_id = 0; + DL_BWP->bwp_id = 0; + DL_BWP->bwp_id = 0; target_ss = NR_SearchSpace__searchSpaceType_PR_common; - BWP->pdsch_Config = NULL; + DL_BWP->pdsch_Config = NULL; } - if (old_dl_bwp_id != BWP->dl_bwp_id) - LOG_I(NR_MAC, "Switching to DL-BWP %li\n", BWP->dl_bwp_id); + if (old_dl_bwp_id != DL_BWP->bwp_id) + LOG_I(NR_MAC, "Switching to DL-BWP %li\n", DL_BWP->bwp_id); - if (BWP->dl_bwp_id>0) - BWP->tdaList = dl_bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; + if (DL_BWP->bwp_id>0) + DL_BWP->tdaList = dl_bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; else - BWP->tdaList = scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; + DL_BWP->tdaList = scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; // setting generic parameters - NR_BWP_t dl_genericParameters = (BWP->dl_bwp_id>0 && dl_bwp) ? + NR_BWP_t dl_genericParameters = (DL_BWP->bwp_id>0 && dl_bwp) ? dl_bwp->bwp_Common->genericParameters: scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; - BWP->dl_scs = dl_genericParameters.subcarrierSpacing; - BWP->dl_cyclicprefix = dl_genericParameters.cyclicPrefix; - BWP->dl_BWPSize = NRRIV2BW(dl_genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - BWP->dl_BWPStart = NRRIV2PRBOFFSET(dl_genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + DL_BWP->scs = dl_genericParameters.subcarrierSpacing; + DL_BWP->cyclicprefix = dl_genericParameters.cyclicPrefix; + DL_BWP->BWPSize = NRRIV2BW(dl_genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + DL_BWP->BWPStart = NRRIV2PRBOFFSET(dl_genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - NR_BWP_t ul_genericParameters = (BWP->ul_bwp_id>0 && ul_bwp) ? + NR_BWP_t ul_genericParameters = (UL_BWP->bwp_id>0 && ul_bwp) ? ul_bwp->bwp_Common->genericParameters: scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; - BWP->ul_scs = ul_genericParameters.subcarrierSpacing; - BWP->ul_cyclicprefix = ul_genericParameters.cyclicPrefix; - BWP->ul_BWPSize = NRRIV2BW(ul_genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - BWP->ul_BWPStart = NRRIV2PRBOFFSET(ul_genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + UL_BWP->scs = ul_genericParameters.subcarrierSpacing; + UL_BWP->cyclicprefix = ul_genericParameters.cyclicPrefix; + UL_BWP->BWPSize = NRRIV2BW(ul_genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + UL_BWP->BWPStart = NRRIV2PRBOFFSET(ul_genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - if(sched_ctrl) { + // Set downlink MCS table + if (DL_BWP->pdsch_Config && + DL_BWP->pdsch_Config->mcs_Table) { + if (*DL_BWP->pdsch_Config->mcs_Table == 0) + DL_BWP->mcsTableIdx = 1; + else + DL_BWP->mcsTableIdx = 2; + } else + DL_BWP->mcsTableIdx = 0; + LOG_D(NR_MAC,"MCS Table Index: %d\n",DL_BWP->mcsTableIdx); + + if(UE) { // setting PDCCH related structures for sched_ctrl sched_ctrl->search_space = get_searchspace(scc, bwpd, @@ -2486,9 +2508,11 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf sched_ctrl->sched_srs.srs_scheduled = false; // initialize UE BWP information - NR_UE_BWP_t *BWP = &UE->current_BWP; - memset(BWP, 0, sizeof(*BWP)); - configure_UE_BWP(nr_mac, BWP, scc, sched_ctrl, NULL, CellGroup); + NR_UE_DL_BWP_t *DL_BWP = &UE->current_DL_BWP; + memset(DL_BWP, 0, sizeof(*DL_BWP)); + NR_UE_UL_BWP_t *UL_BWP = &UE->current_UL_BWP; + memset(UL_BWP, 0, sizeof(*UL_BWP)); + configure_UE_BWP(nr_mac, scc, sched_ctrl, NULL, UE); /* set illegal time domain allocation to force recomputation of all fields */ sched_ctrl->pdsch_semi_static.time_domain_allocation = -1; @@ -2504,7 +2528,7 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf "uplinkBWP_ToAddModList has %d BWP!\n", ubwpList->list.count); - sched_ctrl->active_ubwp = ubwpList && BWP->ul_bwp_id > 0 ? ubwpList->list.array[BWP->ul_bwp_id - 1] : NULL; + sched_ctrl->active_ubwp = ubwpList && UL_BWP->bwp_id > 0 ? ubwpList->list.array[UL_BWP->bwp_id - 1] : NULL; /* get Number of HARQ processes for this UE */ if (servingCellConfig) @@ -2630,8 +2654,8 @@ void get_pdsch_to_harq_feedback(NR_UE_info_t *UE, NR_CellGroupConfig_t *CellGroup = UE->CellGroup; NR_BWP_DownlinkDedicated_t *bwpd=NULL; NR_BWP_UplinkDedicated_t *ubwpd=NULL; - int dl_bwp_id = UE->current_BWP.dl_bwp_id; - int ul_bwp_id = UE->current_BWP.ul_bwp_id; + int dl_bwp_id = UE->current_DL_BWP.bwp_id; + int ul_bwp_id = UE->current_UL_BWP.bwp_id; if (ss_type == NR_SearchSpace__searchSpaceType_PR_ue_Specific) { AssertFatal(CellGroup!=NULL,"Cellgroup is not defined for UE %04x\n",UE->rnti); @@ -2728,7 +2752,7 @@ void nr_csirs_scheduling(int Mod_idP, continue; } NR_CellGroupConfig_t *CellGroup = UE->CellGroup; - NR_UE_BWP_t *BWP = &UE->current_BWP; + NR_UE_DL_BWP_t *BWP = &UE->current_DL_BWP; if (!CellGroup || !CellGroup->spCellConfig || !CellGroup->spCellConfig->spCellConfigDedicated || !CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig) continue; @@ -2759,20 +2783,20 @@ void nr_csirs_scheduling(int Mod_idP, nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *csirs_pdu_rel15 = &dl_tti_csirs_pdu->csi_rs_pdu.csi_rs_pdu_rel15; - csirs_pdu_rel15->subcarrier_spacing = BWP->dl_scs; - if (BWP->dl_cyclicprefix) - csirs_pdu_rel15->cyclic_prefix = *BWP->dl_cyclicprefix; + csirs_pdu_rel15->subcarrier_spacing = BWP->scs; + if (BWP->cyclicprefix) + csirs_pdu_rel15->cyclic_prefix = *BWP->cyclicprefix; else csirs_pdu_rel15->cyclic_prefix = 0; // According to last paragraph of TS 38.214 5.2.2.3.1 - if (resourceMapping.freqBand.startingRB < BWP->dl_BWPStart) { - csirs_pdu_rel15->start_rb = BWP->dl_BWPStart; + if (resourceMapping.freqBand.startingRB < BWP->BWPStart) { + csirs_pdu_rel15->start_rb = BWP->BWPStart; } else { csirs_pdu_rel15->start_rb = resourceMapping.freqBand.startingRB; } - if (resourceMapping.freqBand.nrofRBs > (BWP->dl_BWPStart + BWP->dl_BWPSize - csirs_pdu_rel15->start_rb)) { - csirs_pdu_rel15->nr_of_rbs = BWP->dl_BWPStart + BWP->dl_BWPSize - csirs_pdu_rel15->start_rb; + if (resourceMapping.freqBand.nrofRBs > (BWP->BWPStart + BWP->BWPSize - csirs_pdu_rel15->start_rb)) { + csirs_pdu_rel15->nr_of_rbs = BWP->BWPStart + BWP->BWPSize - csirs_pdu_rel15->start_rb; } else { csirs_pdu_rel15->nr_of_rbs = resourceMapping.freqBand.nrofRBs; } @@ -2956,8 +2980,7 @@ void nr_mac_update_timers(module_id_t module_id, LOG_I(NR_MAC,"Modified rnti %04x with CellGroup\n", UE->rnti); process_CellGroup(cg,&UE->UE_sched_ctrl); NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - // re-configure BWP information - NR_UE_BWP_t *BWP = &UE->current_BWP; + const NR_PDSCH_ServingCellConfig_t *pdsch = spCellConfigDedicated ? spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup : NULL; if (get_softmodem_params()->sa) { @@ -2969,12 +2992,12 @@ void nr_mac_update_timers(module_id_t module_id, if (spCellConfigDedicated->uplinkConfig && spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList) { sched_ctrl->active_ubwp = spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[*spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id - 1]; - if (*spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id != BWP->ul_bwp_id) { + if (*spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id != UE->current_UL_BWP.bwp_id) { LOG_I(NR_MAC, "Changing to UL-BWP %li\n", sched_ctrl->active_ubwp->bwp_Id); } } - configure_UE_BWP(RC.nrmac[module_id], BWP, scc, sched_ctrl, NULL, UE->CellGroup); + configure_UE_BWP(RC.nrmac[module_id], scc, sched_ctrl, NULL, UE); // Update coreset/searchspace @@ -2991,20 +3014,7 @@ void nr_mac_update_timers(module_id_t module_id, const uint8_t layers = set_dl_nrOfLayers(sched_ctrl); const int tda = get_dl_tda(RC.nrmac[module_id], scc, slot); - // Update downlink MCS table - if (BWP->pdsch_Config && - BWP->pdsch_Config->mcs_Table) { - if (*BWP->pdsch_Config->mcs_Table == 0) { - ps->mcsTableIdx = 1; - } else { - ps->mcsTableIdx = 2; - } - } else { - ps->mcsTableIdx = 0; - } - LOG_D(NR_MAC,"MCS Table Index: %d\n",ps->mcsTableIdx); - - nr_set_pdsch_semi_static(BWP, + nr_set_pdsch_semi_static(&UE->current_DL_BWP, scc, cg, tda, @@ -3055,14 +3065,15 @@ void schedule_nr_bwp_switch(module_id_t module_id, UE_iterator(UE_info->list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_BWP_t *BWP = &UE->current_BWP; + NR_UE_DL_BWP_t *DLBWP = &UE->current_DL_BWP; + NR_UE_UL_BWP_t *ULBWP = &UE->current_UL_BWP; if (sched_ctrl->rrc_processing_timer == 0 && UE->Msg4_ACKed && - ((sched_ctrl->next_dl_bwp_id >= 0 && BWP->dl_bwp_id != sched_ctrl->next_dl_bwp_id) || - (sched_ctrl->next_ul_bwp_id >= 0 && BWP->ul_bwp_id != sched_ctrl->next_ul_bwp_id))) { + ((sched_ctrl->next_dl_bwp_id >= 0 && DLBWP->bwp_id != sched_ctrl->next_dl_bwp_id) || + (sched_ctrl->next_ul_bwp_id >= 0 && ULBWP->bwp_id != sched_ctrl->next_ul_bwp_id))) { LOG_W(NR_MAC,"%4d.%2d UE %04x Schedule BWP switch from dl_bwp_id %ld to %ld and from ul_bwp_id %ld to %ld\n", - frame, slot, UE->rnti, BWP->dl_bwp_id, sched_ctrl->next_dl_bwp_id, BWP->ul_bwp_id, sched_ctrl->next_ul_bwp_id); + frame, slot, UE->rnti, DLBWP->bwp_id, sched_ctrl->next_dl_bwp_id, ULBWP->bwp_id, sched_ctrl->next_ul_bwp_id); nr_mac_rrc_bwp_switch_req(module_id, frame, slot, UE->rnti, sched_ctrl->next_dl_bwp_id, sched_ctrl->next_ul_bwp_id); } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index 4397686c64..15d06886f5 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -36,13 +36,13 @@ extern RAN_CONTEXT_t RC; void nr_configure_srs(nfapi_nr_srs_pdu_t *srs_pdu, int module_id, int CC_id,NR_UE_info_t* UE, NR_SRS_Resource_t *srs_resource) { - NR_UE_BWP_t *current_BWP = &UE->current_BWP; + NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP; srs_pdu->rnti = UE->rnti; srs_pdu->handle = 0; - srs_pdu->bwp_size = current_BWP->ul_BWPSize; - srs_pdu->bwp_start = current_BWP->ul_BWPStart; - srs_pdu->subcarrier_spacing = current_BWP->ul_scs; + srs_pdu->bwp_size = current_BWP->BWPSize; + srs_pdu->bwp_start = current_BWP->BWPStart; + srs_pdu->subcarrier_spacing = current_BWP->scs; srs_pdu->cyclic_prefix = 0; srs_pdu->num_ant_ports = srs_resource->nrofSRS_Ports; srs_pdu->num_symbols = srs_resource->resourceMapping.nrofSymbols; @@ -110,7 +110,7 @@ void nr_schedule_srs(int module_id, frame_t frame) { const int CC_id = 0; NR_CellGroupConfig_t *cg = UE->CellGroup; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_BWP_t *current_BWP = &UE->current_BWP; + NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP; sched_ctrl->sched_srs.frame = -1; sched_ctrl->sched_srs.slot = -1; @@ -160,7 +160,7 @@ void nr_schedule_srs(int module_id, frame_t frame) { uint16_t period = srs_period[srs_resource->resourceType.choice.periodic->periodicityAndOffset_p.present]; uint16_t offset = get_nr_srs_offset(srs_resource->resourceType.choice.periodic->periodicityAndOffset_p); - int n_slots_frame = nr_slots_per_frame[current_BWP->ul_scs]; + int n_slots_frame = nr_slots_per_frame[current_BWP->scs]; // Check if UE will transmit the SRS in this frame if ( ((frame - offset/n_slots_frame)*n_slots_frame)%period == 0) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index faf8a01c18..559b3cb988 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -698,8 +698,8 @@ void nr_csi_meas_reporting(int Mod_idP, UE_iterator(RC.nrmac[Mod_idP]->UE_info.list, UE ) { const NR_CellGroupConfig_t *CellGroup = UE->CellGroup; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_BWP_t *BWP = &UE->current_BWP; - const int n_slots_frame = nr_slots_per_frame[BWP->ul_scs]; + NR_UE_UL_BWP_t *UL_BWP = &UE->current_UL_BWP; + const int n_slots_frame = nr_slots_per_frame[UL_BWP->scs]; if ((sched_ctrl->rrc_processing_timer > 0) || (sched_ctrl->ul_failure==1 && get_softmodem_params()->phy_test==0)) { continue; } @@ -758,7 +758,7 @@ void nr_csi_meas_reporting(int Mod_idP, curr_pucch->resource_indicator = res_index; curr_pucch->csi_bits += nr_get_csi_bitlen(UE,csi_report_id); - int bwp_start = BWP->ul_BWPStart; + int bwp_start = UL_BWP->BWPStart; // going through the list of PUCCH resources to find the one indexed by resource_id uint16_t *vrb_map_UL = &RC.nrmac[Mod_idP]->common_channels[0].vrb_map_UL[sched_slot * MAX_BWP_SIZE]; @@ -834,7 +834,7 @@ static void handle_dl_harq(NR_UE_info_t * UE, int checkTargetSSBInFirst64TCIStates_pdschConfig(int ssb_index_t, NR_UE_info_t * UE) { - const NR_PDSCH_Config_t *pdsch_Config = UE->current_BWP.pdsch_Config; + const NR_PDSCH_Config_t *pdsch_Config = UE->current_DL_BWP.pdsch_Config; int nb_tci_states = pdsch_Config ? pdsch_Config->tci_StatesToAddModList->list.count : 0; NR_TCI_State_t *tci =NULL; @@ -866,7 +866,7 @@ int checkTargetSSBInTCIStates_pdcchConfig(int ssb_index_t, NR_UE_info_t *UE) { NR_ControlResourceSet_t *coreset = sched_ctrl->coreset; int flag = 0; int tci_stateID = -1; - const NR_PDSCH_Config_t *pdsch_Config = UE->current_BWP.pdsch_Config; + const NR_PDSCH_Config_t *pdsch_Config = UE->current_DL_BWP.pdsch_Config; int nb_tci_states = pdsch_Config ? pdsch_Config->tci_StatesToAddModList->list.count : 0; for(int i=0; itci_StatesToAddModList->list.array[i]; @@ -929,7 +929,7 @@ void tci_handling(NR_UE_info_t *UE, frame_t frame, slot_t slot) { int ssb_index[MAX_NUM_SSB] = {0}; int ssb_rsrp[MAX_NUM_SSB] = {0}; uint8_t idx = 0; - NR_UE_BWP_t *BWP = &UE->current_BWP; + NR_UE_DL_BWP_t *BWP = &UE->current_DL_BWP; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; uint8_t nr_ssbri_cri = 0; @@ -940,7 +940,7 @@ void tci_handling(NR_UE_info_t *UE, frame_t frame, slot_t slot) { //bwp indicator int n_dl_bwp = BWP->n_dl_bwp; - const int bwp_id = BWP->dl_bwp_id; + const int bwp_id = BWP->bwp_id; if (n_dl_bwp < 4) pdsch_bwp_id = bwp_id; else @@ -1203,9 +1203,12 @@ void evaluate_cqi_report(uint8_t *payload, nr_csi_report_t *csi_report, int cumul_bits, uint8_t ri, - NR_UE_sched_ctrl_t *sched_ctrl, + NR_UE_info_t *UE, long *cqi_Table){ + NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_UE_DL_BWP_t *BWP = &UE->current_DL_BWP; + //TODO sub-band CQI report not yet implemented int cqi_bitlen = csi_report->csi_meas_bitlen.cqi_bitlen[ri]; @@ -1228,7 +1231,7 @@ void evaluate_cqi_report(uint8_t *payload, // TODO for wideband case and multiple TB const int cqi_idx = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb; - const int mcs_table = sched_ctrl->pdsch_semi_static.mcsTableIdx; + const int mcs_table = BWP->mcsTableIdx; const int cqi_table = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.cqi_table; sched_ctrl->dl_max_mcs = get_mcs_from_cqi(mcs_table, cqi_table, cqi_idx); } @@ -1307,8 +1310,8 @@ void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig, uint16_t bitlen = uci_pdu->csi_part1.csi_part1_bit_len; NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type = NR_CSI_ReportConfig__reportQuantity_PR_NOTHING; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_BWP_t *BWP = &UE->current_BWP; - const int n_slots_frame = nr_slots_per_frame[BWP->ul_scs]; + NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; + const int n_slots_frame = nr_slots_per_frame[BWP->scs]; int cumul_bits = 0; int r_index = -1; for (int csi_report_id = 0; csi_report_id < csi_MeasConfig->csi_ReportConfigToAddModList->list.count; csi_report_id++ ) { @@ -1343,7 +1346,7 @@ void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig, cumul_bits += ri_bitlen; if (r_index != -1) skip_zero_padding(&cumul_bits,csi_report,r_index,bitlen); - evaluate_cqi_report(payload,csi_report,cumul_bits,r_index,sched_ctrl,csirep->cqi_Table); + evaluate_cqi_report(payload,csi_report,cumul_bits,r_index,UE,csirep->cqi_Table); break; case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI: cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; @@ -1359,7 +1362,7 @@ void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig, pmi_bitlen = evaluate_pmi_report(payload,csi_report,cumul_bits,r_index,sched_ctrl); sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id = csi_report_id; cumul_bits += pmi_bitlen; - evaluate_cqi_report(payload,csi_report,cumul_bits,r_index,sched_ctrl,csirep->cqi_Table); + evaluate_cqi_report(payload,csi_report,cumul_bits,r_index,UE,csirep->cqi_Table); break; case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI: cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; @@ -1377,7 +1380,7 @@ void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig, pmi_bitlen = evaluate_pmi_report(payload,csi_report,cumul_bits,r_index,sched_ctrl); sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id = csi_report_id; cumul_bits += pmi_bitlen; - evaluate_cqi_report(payload,csi_report,cumul_bits,r_index,sched_ctrl,csirep->cqi_Table); + evaluate_cqi_report(payload,csi_report,cumul_bits,r_index,UE,csirep->cqi_Table); break; default: AssertFatal(1==0, "Invalid or not supported CSI measurement report\n"); @@ -1598,8 +1601,8 @@ int nr_acknack_scheduling(int mod_id, const int CC_id = 0; const int minfbtime = RC.nrmac[mod_id]->minRXTXTIMEpdsch; const NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels[CC_id].ServingCellConfigCommon; - NR_UE_BWP_t *BWP = &UE->current_BWP; - const int n_slots_frame = nr_slots_per_frame[BWP->ul_scs]; + NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; + const int n_slots_frame = nr_slots_per_frame[BWP->scs]; const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; AssertFatal(tdd || RC.nrmac[mod_id]->common_channels[CC_id].frame_type == FDD, "Dynamic TDD not handled yet\n"); const int nr_slots_period = tdd ? n_slots_frame / get_nb_periods_per_frame(tdd->dl_UL_TransmissionPeriodicity) : n_slots_frame; @@ -1627,8 +1630,8 @@ int nr_acknack_scheduling(int mod_id, pucch_Config = cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pucch_Config->choice.setup; } - int bwp_start = BWP->ul_BWPStart; - int bwp_size = BWP->ul_BWPSize; + int bwp_start = BWP->BWPStart; + int bwp_size = BWP->BWPSize; NR_sched_pucch_t *pucch = &sched_ctrl->sched_pucch[0]; LOG_D(NR_MAC, "In %s: %4d.%2d Trying to allocate pucch, current DAI %d\n", __FUNCTION__, frame, slot, pucch->dai_c); @@ -1875,8 +1878,8 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, sub_frame_t slot) UE_iterator(nrmac->UE_info.list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_BWP_t *BWP = &UE->current_BWP; - const int n_slots_frame = nr_slots_per_frame[BWP->ul_scs]; + NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; + const int n_slots_frame = nr_slots_per_frame[BWP->scs]; if (sched_ctrl->ul_failure==1) continue; NR_PUCCH_Config_t *pucch_Config = NULL; if (sched_ctrl->active_ubwp) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 3c4ca86cbd..49cbcd7a88 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -847,7 +847,7 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; int rbStart = 0; // wrt BWP start - const uint16_t bwpSize = UE->current_BWP.ul_BWPSize; + const uint16_t bwpSize = UE->current_UL_BWP.BWPSize; const uint8_t nrOfLayers = 1; const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_ubwp || ubwpd) ? 1 : 2; LOG_D(NR_MAC,"retInfo->time_domain_allocation = %d, tda = %d\n", retInfo->time_domain_allocation, tda); @@ -1037,7 +1037,7 @@ void pf_ul(module_id_t module_id, LOG_D(NR_MAC,"pf_ul: preparing UL scheduling for UE %04x\n",UE->rnti); NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_BWP_t *BWP = &UE->current_BWP; + NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; int rbStart = 0; // wrt BWP start NR_CellGroupConfig_t *cg = UE->CellGroup; @@ -1045,7 +1045,7 @@ void pf_ul(module_id_t module_id, cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; - const uint16_t bwpSize = BWP->ul_BWPSize; + const uint16_t bwpSize = BWP->BWPSize; NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; const NR_mac_dir_stats_t *stats = &UE->mac_stats.ul; @@ -1235,15 +1235,15 @@ void pf_ul(module_id_t module_id, } else LOG_D(NR_MAC, "%4d.%2d free CCE for UL DCI UE %04x\n",frame,slot, iterator->UE->rnti); - NR_UE_BWP_t *BWP = &iterator->UE->current_BWP; + NR_UE_UL_BWP_t *BWP = &iterator->UE->current_UL_BWP; NR_CellGroupConfig_t *cg = iterator->UE->CellGroup; NR_BWP_UplinkDedicated_t *ubwpd = cg && cg->spCellConfig && cg->spCellConfig->spCellConfigDedicated && cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; - int rbStart = sched_ctrl->active_ubwp ? BWP->ul_BWPStart : 0; - const uint16_t bwpSize = BWP->ul_BWPSize; + int rbStart = sched_ctrl->active_ubwp ? BWP->BWPStart : 0; + const uint16_t bwpSize = BWP->BWPSize; NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; @@ -1347,8 +1347,8 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t * TDAs yet). If the TDA is negative, it means that there is no UL slot to * schedule now (slot + k2 is not UL slot) */ NR_UE_sched_ctrl_t *sched_ctrl = &nr_mac->UE_info.list[0]->UE_sched_ctrl; - NR_UE_BWP_t *BWP = &nr_mac->UE_info.list[0]->current_BWP; - int mu = BWP->ul_scs; + NR_UE_UL_BWP_t *BWP = &nr_mac->UE_info.list[0]->current_UL_BWP; + int mu = BWP->scs; const int temp_tda = get_ul_tda(nr_mac, scc, slot); int K2 = get_K2(scc, scc_sib1, sched_ctrl->active_ubwp, temp_tda, mu); const int sched_frame = (frame + (slot + K2 >= nr_slots_per_frame[mu])) & 1023; @@ -1398,8 +1398,8 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t uint16_t *vrb_map_UL = &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[sched_slot * MAX_BWP_SIZE]; - const uint16_t bwpSize = BWP->ul_BWPSize; - const uint16_t bwpStart = BWP->ul_BWPStart; + const uint16_t bwpSize = BWP->BWPSize; + const uint16_t bwpStart = BWP->BWPStart; NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList = NULL; if (sched_ctrl->active_ubwp) { @@ -1511,7 +1511,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) if (sched_ctrl->ul_failure == 1 && get_softmodem_params()->phy_test==0) continue; NR_CellGroupConfig_t *cg = UE->CellGroup; - NR_UE_BWP_t *current_BWP = &UE->current_BWP; + NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP; NR_BWP_UplinkDedicated_t *ubwpd = cg && cg->spCellConfig && cg->spCellConfig->spCellConfigDedicated && cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? @@ -1642,9 +1642,9 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) /* FAPI: BWP */ - pusch_pdu->bwp_size = current_BWP->ul_BWPSize; - pusch_pdu->bwp_start = current_BWP->ul_BWPStart; - pusch_pdu->subcarrier_spacing = current_BWP->ul_scs; + pusch_pdu->bwp_size = current_BWP->BWPSize; + pusch_pdu->bwp_start = current_BWP->BWPStart; + pusch_pdu->subcarrier_spacing = current_BWP->scs; pusch_pdu->cyclic_prefix = 0; /* FAPI: PUSCH information always included */ @@ -1806,13 +1806,13 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) current_BWP); fill_dci_pdu_rel15(scc, cg, - current_BWP, + &UE->current_DL_BWP, dci_pdu, &uldci_payload, ps->dci_format, rnti_types[0], pusch_pdu->bwp_size, - current_BWP->ul_bwp_id, + current_BWP->bwp_id, coresetid, nr_mac->cset0_bwp_size); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 1eed647565..26679a1b7c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -201,7 +201,7 @@ void config_uldci(const NR_SIB1_t *sib1, int time_domain_assignment, uint8_t tpc, int n_ubwp, - NR_UE_BWP_t *BWP); + NR_UE_UL_BWP_t *BWP); void nr_schedule_pucch(gNB_MAC_INST* nrmac, frame_t frameP, @@ -297,7 +297,7 @@ void fill_pdcch_vrb_map(gNB_MAC_INST *mac, void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, const NR_CellGroupConfig_t *CellGroup, - const NR_UE_BWP_t *BWP, + const NR_UE_DL_BWP_t *BWP, nfapi_nr_dl_dci_pdu_t *pdcch_dci_pdu, dci_pdu_rel15_t *dci_pdu_rel15, int dci_formats, @@ -308,7 +308,7 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, uint16_t cset0_bwp_size); void prepare_dci(const NR_CellGroupConfig_t *CellGroup, - const NR_UE_BWP_t *BWP, + const NR_UE_DL_BWP_t *BWP, dci_pdu_rel15_t *dci_pdu_rel15, nr_dci_format_t format, int bwp_id); @@ -339,7 +339,7 @@ long get_K2(NR_ServingCellConfigCommon_t *scc, int time_domain_assignment, int mu); -void nr_set_pdsch_semi_static(const NR_UE_BWP_t *BWP, +void nr_set_pdsch_semi_static(const NR_UE_DL_BWP_t *BWP, const NR_ServingCellConfigCommon_t *scc, const NR_CellGroupConfig_t *secondaryCellGroup, int tda, @@ -391,11 +391,10 @@ NR_UE_info_t * find_nr_UE(NR_UEs_t* UEs, rnti_t rntiP); int find_nr_RA_id(module_id_t mod_idP, int CC_idP, rnti_t rntiP); void configure_UE_BWP(gNB_MAC_INST *nr_mac, - NR_UE_BWP_t *BWP, NR_ServingCellConfigCommon_t *scc, NR_UE_sched_ctrl_t *sched_ctrl, NR_RA_t *ra, - NR_CellGroupConfig_t *CellGroup); + NR_UE_info_t *UE); NR_UE_info_t* add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConfig_t *CellGroup); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 2d42dbe15e..e38c23cf72 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -91,21 +91,25 @@ typedef struct { int len; } NR_list_t; -typedef struct NR_UE_BWP { - NR_BWP_Id_t dl_bwp_id; - NR_BWP_Id_t ul_bwp_id; +typedef struct NR_UE_DL_BWP { + NR_BWP_Id_t bwp_id; int n_dl_bwp; - int dl_scs; - int ul_scs; - long *dl_cyclicprefix; - long *ul_cyclicprefix; - uint16_t dl_BWPSize; - uint16_t dl_BWPStart; - uint16_t ul_BWPSize; - uint16_t ul_BWPStart; + int scs; + long *cyclicprefix; + uint16_t BWPSize; + uint16_t BWPStart; NR_PDSCH_TimeDomainResourceAllocationList_t *tdaList; NR_PDSCH_Config_t *pdsch_Config; -} NR_UE_BWP_t; + uint8_t mcsTableIdx; +} NR_UE_DL_BWP_t; + +typedef struct NR_UE_UL_BWP { + NR_BWP_Id_t bwp_id; + int scs; + long *cyclicprefix; + uint16_t BWPSize; + uint16_t BWPStart; +} NR_UE_UL_BWP_t; typedef enum { RA_IDLE = 0, @@ -211,7 +215,8 @@ typedef struct { /// CFRA flag bool cfra; // BWP for RA - NR_UE_BWP_t BWP; + NR_UE_DL_BWP_t DL_BWP; + NR_UE_UL_BWP_t UL_BWP; } NR_RA_t; /*! \brief gNB common channels */ @@ -422,7 +427,6 @@ typedef struct NR_pdsch_semi_static { int startSymbolIndex; int nrOfSymbols; uint8_t nrOfLayers; - uint8_t mcsTableIdx; uint8_t dmrs_ports_id; uint8_t N_PRB_DMRS; uint8_t N_DMRS_SLOT; @@ -719,7 +723,8 @@ typedef struct { /// scheduling control info nr_csi_report_t csi_report_template[MAX_CSI_REPORTCONFIG]; NR_UE_sched_ctrl_t UE_sched_ctrl; - NR_UE_BWP_t current_BWP; + NR_UE_DL_BWP_t current_DL_BWP; + NR_UE_UL_BWP_t current_UL_BWP; NR_mac_stats_t mac_stats; NR_CellGroupConfig_t *CellGroup; char cg_buf[32768]; /* arbitrary size */ From f6cbde534391d2a3d73ecbe3a91f2f92c22304c2 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 16 Jun 2022 12:49:13 +0100 Subject: [PATCH 136/267] Add const qualifier in some variables --- .../PHY/NR_ESTIMATION/nr_measurements_gNB.c | 6 ++-- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 30 +++++++++---------- openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 18 +++++------ openair1/SCHED_NR/phy_procedures_nr_gNB.c | 22 ++++++++------ openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 2 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c | 14 ++++----- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 4 +-- openair2/NR_PHY_INTERFACE/NR_IF_Module.c | 4 +-- openair2/RRC/NR/MESSAGES/asn1_msg.c | 2 +- openair2/RRC/NR/MESSAGES/asn1_msg.h | 2 +- openair2/RRC/NR/nr_rrc_config.c | 8 ++--- openair2/RRC/NR/nr_rrc_config.h | 6 ++-- 12 files changed, 61 insertions(+), 57 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index 403a96983c..c1be11c468 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -67,8 +67,8 @@ int nr_est_timing_advance_pusch(PHY_VARS_gNB* gNB, int UE_id) return max_pos - sync_pos; } -int nr_est_timing_advance_srs(NR_DL_FRAME_PARMS *frame_parms, - int32_t **srs_estimated_channel_time) { +int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms, + const int32_t **srs_estimated_channel_time) { int timing_advance = 0; int max_val = 0; @@ -90,7 +90,7 @@ int nr_est_timing_advance_srs(NR_DL_FRAME_PARMS *frame_parms, } // Scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size - uint16_t bw_scaling = frame_parms->ofdm_symbol_size >> 7; + const uint16_t bw_scaling = frame_parms->ofdm_symbol_size >> 7; // do some integer rounding to improve TA accuracy int sync_pos_rounded; diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 448df9b468..f28f68acbd 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -950,7 +950,7 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, }//Antenna loop } -uint32_t calc_power(const int16_t *x, uint32_t size) { +uint32_t calc_power(const int16_t *x, const uint32_t size) { int64_t sum_x = 0; int64_t sum_x2 = 0; for(int k = 0; kframe_parms; + const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; int32_t **srs_ls_estimated_channel = nr_srs_info->srs_ls_estimated_channel; int16_t ch_real[frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length]; @@ -1110,13 +1110,13 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, // Compute noise power - uint8_t signal_power_bits = log2_approx(*signal_power); - uint8_t factor_bits = signal_power_bits < 32 ? 32 - signal_power_bits : 0; // 32 due to input of dB_fixed(uint32_t x) - int32_t factor_dB = dB_fixed(1<first_carrier_offset + srs_pdu->bwp_start*12; - uint8_t srs_symbols_per_rb = srs_pdu->comb_size == 0 ? 6 : 3; - uint8_t n_noise_estimates = frame_parms->nb_antennas_rx*srs_symbols_per_rb; + const uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start*12; + const uint8_t srs_symbols_per_rb = srs_pdu->comb_size == 0 ? 6 : 3; + const uint8_t n_noise_estimates = frame_parms->nb_antennas_rx*srs_symbols_per_rb; uint8_t count_estimates = 0; uint64_t sum_re = 0; uint64_t sum_re2 = 0; diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index 914b0d7385..01af743473 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -55,8 +55,8 @@ void nr_gnb_measurements(PHY_VARS_gNB *gNB, uint8_t ulsch_id, unsigned char harq int nr_est_timing_advance_pusch(PHY_VARS_gNB* phy_vars_gNB, int UE_id); -int nr_est_timing_advance_srs(NR_DL_FRAME_PARMS *frame_parms, - int32_t **srs_estimated_channel_time); +int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms, + const int32_t **srs_estimated_channel_time); void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, NR_DL_FRAME_PARMS *frame_parms, @@ -66,13 +66,13 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, unsigned char symbol, uint32_t nb_re_pusch); -int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, - int frame, - int slot, - nfapi_nr_srs_pdu_t *srs_pdu, - nr_srs_info_t *nr_srs_info, - int32_t *srs_generated_signal, - int32_t **srs_received_signal, +int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, + const int frame, + const int slot, + const nfapi_nr_srs_pdu_t *srs_pdu, + const nr_srs_info_t *nr_srs_info, + const int32_t *srs_generated_signal, + const int32_t **srs_received_signal, int32_t **srs_estimated_channel_freq, int32_t **srs_estimated_channel_time, int32_t **srs_estimated_channel_time_shifted, diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 0198298101..522487c53a 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -633,11 +633,11 @@ void phy_procedures_gNB_common_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) } -int fill_srs_reported_symbol_list(nfapi_nr_srs_indication_reported_symbol_t* reported_symbol_list, - nfapi_nr_srs_pdu_t *srs_pdu, - int N_RB_UL, +int fill_srs_reported_symbol_list(nfapi_nr_srs_indication_reported_symbol_t *reported_symbol_list, + const nfapi_nr_srs_pdu_t *srs_pdu, + const int N_RB_UL, const int8_t *snr_per_rb, - int srs_est) { + const int srs_est) { reported_symbol_list->num_rbs = srs_bandwidth_config[srs_pdu->config_index][srs_pdu->bandwidth_index][0]; @@ -865,13 +865,16 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { generate_srs_nr(srs_pdu, &gNB->frame_parms, gNB->nr_srs_info[i]->srs_generated_signal, gNB->nr_srs_info[i], AMP, frame_rx, slot_rx); } - int srs_est = nr_get_srs_signal(gNB,frame_rx,slot_rx,srs_pdu, gNB->nr_srs_info[i], gNB->nr_srs_info[i]->srs_received_signal); + const int srs_est = nr_get_srs_signal(gNB,frame_rx,slot_rx,srs_pdu, gNB->nr_srs_info[i], gNB->nr_srs_info[i]->srs_received_signal); if (srs_est >= 0) { - nr_srs_channel_estimation(gNB,frame_rx,slot_rx,srs_pdu, + nr_srs_channel_estimation(gNB, + frame_rx, + slot_rx, + srs_pdu, gNB->nr_srs_info[i], gNB->nr_srs_info[i]->srs_generated_signal, - gNB->nr_srs_info[i]->srs_received_signal, + (const int32_t **)gNB->nr_srs_info[i]->srs_received_signal, gNB->nr_srs_info[i]->srs_estimated_channel_freq, gNB->nr_srs_info[i]->srs_estimated_channel_time, gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted, @@ -888,13 +891,14 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { T(T_GNB_PHY_UL_TIME_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), T_BUFFER(gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted[0], gNB->frame_parms.ofdm_symbol_size*sizeof(int32_t))); - uint16_t num_srs = gNB->UL_INFO.srs_ind.number_of_pdus; + const uint16_t num_srs = gNB->UL_INFO.srs_ind.number_of_pdus; gNB->UL_INFO.srs_ind.pdu_list = &gNB->srs_pdu_list[0]; gNB->UL_INFO.srs_ind.sfn = frame_rx; gNB->UL_INFO.srs_ind.slot = slot_rx; gNB->srs_pdu_list[num_srs].handle = srs_pdu->handle; gNB->srs_pdu_list[num_srs].rnti = srs_pdu->rnti; - gNB->srs_pdu_list[num_srs].timing_advance = nr_est_timing_advance_srs(&gNB->frame_parms, gNB->nr_srs_info[i]->srs_estimated_channel_time); + gNB->srs_pdu_list[num_srs].timing_advance = nr_est_timing_advance_srs(&gNB->frame_parms, + (const int32_t **)gNB->nr_srs_info[i]->srs_estimated_channel_time); gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; gNB->srs_pdu_list[num_srs].wide_band_snr = srs_est >= 0 ? (*gNB->nr_srs_info[i]->snr + 64)<<1 : 0xFF; // 0xFF will be set if this field is invalid gNB->srs_pdu_list[num_srs].num_reported_symbols = 1<num_symbols; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 9f7fa89146..ce4b16fdc7 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -928,7 +928,7 @@ bool nr_ue_periodic_srs_scheduling(module_id_t mod_id, frame_t frame, slot_t slo bool srs_scheduled = false; NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id); - NR_BWP_Id_t ul_bwp_id = mac->UL_BWP_Id; + const NR_BWP_Id_t ul_bwp_id = mac->UL_BWP_Id; NR_SRS_Config_t *srs_config = NULL; if (ul_bwp_id > 0 && mac->ULbwp[ul_bwp_id-1]) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index 7a21ad82e8..e737fc7107 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -41,9 +41,9 @@ void nr_configure_srs(nfapi_nr_srs_pdu_t *srs_pdu, int module_id, int CC_id,NR_U NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; const NR_SIB1_t *sib1 = nrmac->common_channels[0].sib1 ? nrmac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, - scc, - sib1); + const NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, + scc, + sib1); srs_pdu->rnti = UE->rnti; srs_pdu->handle = 0; @@ -173,14 +173,14 @@ void nr_schedule_srs(int module_id, frame_t frame) { } const NR_SIB1_t *sib1 = nrmac->common_channels[0].sib1 ? nrmac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, - scc, - sib1); + const NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, + scc, + sib1); uint16_t period = srs_period[srs_resource->resourceType.choice.periodic->periodicityAndOffset_p.present]; uint16_t offset = get_nr_srs_offset(srs_resource->resourceType.choice.periodic->periodicityAndOffset_p); - int n_slots_frame = nr_slots_per_frame[genericParameters->subcarrierSpacing]; + const int n_slots_frame = nr_slots_per_frame[genericParameters->subcarrierSpacing]; // Check if UE will transmit the SRS in this frame if ( ((frame - offset/n_slots_frame)*n_slots_frame)%period == 0) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index e815ffcc47..21045cd21e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -789,7 +789,7 @@ void handle_nr_srs_measurements(const module_id_t module_id, } #endif - NR_UE_info_t* UE = find_nr_UE(&RC.nrmac[module_id]->UE_info, rnti); + NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[module_id]->UE_info, rnti); if (!UE) { LOG_W(NR_MAC, "Could not find UE for RNTI 0x%04x\n", rnti); return; @@ -799,7 +799,7 @@ void handle_nr_srs_measurements(const module_id_t module_id, NR_mac_stats_t *stats = &UE->mac_stats; stats->srs_wide_band_snr = (wide_band_snr>>1)-64; - int ul_prbblack_SNR_threshold = nr_mac->ul_prbblack_SNR_threshold; + const int ul_prbblack_SNR_threshold = nr_mac->ul_prbblack_SNR_threshold; uint16_t *ulprbbl = nr_mac->ulprbbl; memset(ulprbbl, 0, reported_symbol_list[0].num_rbs*sizeof(uint16_t)); diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c index c78a4e926e..47705082d1 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c @@ -230,8 +230,8 @@ void handle_nr_srs(NR_UL_IND_t *UL_info) { const module_id_t module_id = UL_info->module_id; const frame_t frame = UL_info->srs_ind.sfn; const sub_frame_t slot = UL_info->srs_ind.slot; - int num_srs = UL_info->srs_ind.number_of_pdus; - nfapi_nr_srs_indication_pdu_t *srs_list = UL_info->srs_ind.pdu_list; + const int num_srs = UL_info->srs_ind.number_of_pdus; + const nfapi_nr_srs_indication_pdu_t *srs_list = UL_info->srs_ind.pdu_list; for (int i = 0; i < num_srs; i++) { const nfapi_nr_srs_indication_pdu_t *srs_ind = &srs_list[i]; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index a2fb44aac9..fff4043a4d 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -2067,7 +2067,7 @@ void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGr } void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, - int uid, + const int uid, NR_UE_NR_Capability_t *uecap, const gNB_RrcConfigurationReq* configuration) { diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 3b881231b0..bff7dcfce5 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -114,7 +114,7 @@ void fill_initial_cellGroupConfig(int uid, const gNB_RrcConfigurationReq *configuration); void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, - int uid, + const int uid, NR_UE_NR_Capability_t *uecap, const gNB_RrcConfigurationReq *configuration); diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index c71e21f999..fd2c92d867 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -324,7 +324,7 @@ void config_csiim(int do_csirs, int dl_antenna_ports, int curr_bwp, } // TODO: Implement to b_SRS = 1 and b_SRS = 2 -long rrc_get_max_nr_csrs(uint8_t max_rbs, long b_SRS) { +long rrc_get_max_nr_csrs(const uint8_t max_rbs, const long b_SRS) { if(b_SRS>0) { LOG_E(NR_RRC,"rrc_get_max_nr_csrs(): Not implemented yet for b_SRS>0\n"); @@ -349,9 +349,9 @@ long rrc_get_max_nr_csrs(uint8_t max_rbs, long b_SRS) { } void config_srs(NR_SetupRelease_SRS_Config_t *setup_release_srs_Config, - NR_ServingCellConfigCommon_t *servingcellconfigcommon, - int uid, - int do_srs) { + const NR_ServingCellConfigCommon_t *servingcellconfigcommon, + const int uid, + const int do_srs) { setup_release_srs_Config->present = NR_SetupRelease_SRS_Config_PR_setup; diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index 31d8ad9c80..4544f9e92f 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -129,9 +129,9 @@ void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, void config_csiim(int do_csirs, int dl_antenna_ports, int curr_bwp, NR_CSI_MeasConfig_t *csi_MeasConfig); void config_srs(NR_SetupRelease_SRS_Config_t *setup_release_srs_Config, - NR_ServingCellConfigCommon_t *servingcellconfigcommon, - int uid, - int do_srs); + const NR_ServingCellConfigCommon_t *servingcellconfigcommon, + const int uid, + const int do_srs); void set_dl_mcs_table(int scs, NR_UE_NR_Capability_t *cap, NR_SpCellConfig_t *SpCellConfig, NR_BWP_DownlinkDedicated_t *bwp_Dedicated, From 61e42ce9c61a14a827dfe323807b78f6674fa55f Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 16 Jun 2022 13:29:30 +0100 Subject: [PATCH 137/267] Consider the invalid timing advance value case for SRS estimation --- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 522487c53a..fb4e5a85ef 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -897,8 +897,8 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->UL_INFO.srs_ind.slot = slot_rx; gNB->srs_pdu_list[num_srs].handle = srs_pdu->handle; gNB->srs_pdu_list[num_srs].rnti = srs_pdu->rnti; - gNB->srs_pdu_list[num_srs].timing_advance = nr_est_timing_advance_srs(&gNB->frame_parms, - (const int32_t **)gNB->nr_srs_info[i]->srs_estimated_channel_time); + gNB->srs_pdu_list[num_srs].timing_advance = srs_est >= 0 ? nr_est_timing_advance_srs(&gNB->frame_parms, + (const int32_t **)gNB->nr_srs_info[i]->srs_estimated_channel_time) : 0xFFFF; gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; gNB->srs_pdu_list[num_srs].wide_band_snr = srs_est >= 0 ? (*gNB->nr_srs_info[i]->snr + 64)<<1 : 0xFF; // 0xFF will be set if this field is invalid gNB->srs_pdu_list[num_srs].num_reported_symbols = 1<num_symbols; From 66e281094034d6c2a285dded4d2ff93d431485e3 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 17 Jun 2022 12:18:29 +0200 Subject: [PATCH 138/267] moving few parameters from pusch_semistatic to BWP --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 30 ++--- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 21 ++- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 121 ++++++++---------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 103 +++++---------- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 9 +- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 12 +- 6 files changed, 110 insertions(+), 186 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index d29e60b869..ffce9533c5 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -701,14 +701,11 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t NR_BWP_Uplink_t *ubwp = NULL; NR_BWP_UplinkDedicated_t *ubwpd = NULL; - NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = NULL; + NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = UL_BWP->tdaList; if(ra->CellGroup) { ubwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[UL_BWP->bwp_id-1]; ubwpd = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; - pusch_TimeDomainAllocationList = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; - } else - pusch_TimeDomainAllocationList = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; - + } int mu = UL_BWP->scs; uint8_t K2 = *pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->k2; const int sched_frame = frame + (slot + K2 >= nr_slots_per_frame[mu]); @@ -732,10 +729,10 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t } int fh = 0; - int startSymbolAndLength = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; + int startSymbolAndLength = pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; int StartSymbolIndex, NrOfSymbols; SLIV2SL(startSymbolAndLength, &StartSymbolIndex, &NrOfSymbols); - int mappingtype = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->mappingType; + int mappingtype = pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->mappingType; uint16_t *vrb_map_UL = &RC.nrmac[module_idP]->common_channels[CC_id].vrb_map_UL[sched_slot * MAX_BWP_SIZE]; @@ -842,7 +839,6 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t scc, pusch_pdu, &uldci_payload, - NR_UL_DCI_FORMAT_0_0, ra->Msg3_tda_id, ra->msg3_TPC, 0, // not used in format 0_0 @@ -903,9 +899,7 @@ void nr_get_Msg3alloc(module_id_t module_id, int temp_slot = 0; ra->Msg3_tda_id = 16; // initialization to a value above limit - NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList= ubwp ? - ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList: - scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; + NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = UL_BWP->tdaList; const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; const int n_slots_frame = nr_slots_per_frame[mu]; @@ -1115,17 +1109,9 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t int ibwp_size = NRRIV2BW(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); int scs = UL_BWP->scs; - int fh = 0; - int startSymbolAndLength = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; - int mappingtype = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->mappingType; - - if (ra->CellGroup) { - NR_BWP_Uplink_t *ubwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[UL_BWP->bwp_id - 1]; - - startSymbolAndLength = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; - mappingtype = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->mappingType; - fh = ubwp->bwp_Dedicated->pusch_Config->choice.setup->frequencyHopping ? 1 : 0; - } + int fh = (UL_BWP->pusch_Config && UL_BWP->pusch_Config->frequencyHopping) ? 1 : 0; + int startSymbolAndLength = UL_BWP->tdaList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; + int mappingtype = UL_BWP->tdaList->list.array[ra->Msg3_tda_id]->mappingType; LOG_D(NR_MAC, "Frame %d, Slot %d Adding Msg3 UL Config Request for (%d,%d) : (%d,%d,%d) for rnti: %d\n", frameP, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index 66b7f2e720..48eff7794e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -355,8 +355,7 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; const int mu = BWP->scs; - const struct NR_PUSCH_TimeDomainResourceAllocationList *tdaList = - sched_ctrl->active_ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; + const struct NR_PUSCH_TimeDomainResourceAllocationList *tdaList = BWP->tdaList; const int temp_tda = get_ul_tda(nr_mac, scc, slot); if (temp_tda < 0) return false; @@ -364,7 +363,7 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ "time domain assignment %d >= %d\n", temp_tda, tdaList->list.count); - int K2 = get_K2(scc,NULL,sched_ctrl->active_ubwp, temp_tda, mu); + int K2 = get_K2(BWP->tdaList, temp_tda, mu); const int sched_frame = frame + (slot + K2 >= nr_slots_per_frame[mu]); const int sched_slot = (slot + K2) % nr_slots_per_frame[mu]; const int tda = get_ul_tda(nr_mac, scc, sched_slot); @@ -380,22 +379,18 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ if (!is_xlsch_in_slot(ulsch_slot_bitmap, sched_slot)) return false; - const long f = (sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific) ? - sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats : 0; - const int dci_format = f ? NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0; uint8_t num_dmrs_cdm_grps_no_data = 1; if ((target_ul_Nl==4)||(target_ul_Nl==3)) num_dmrs_cdm_grps_no_data = 2; /* we want to avoid a lengthy deduction of DMRS and other parameters in - * every TTI if we can save it, so check whether dci_format, TDA, or + * every TTI if we can save it, so check whether TDA, or * num_dmrs_cdm_grps_no_data has changed and only then recompute */ NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; if (ps->time_domain_allocation != tda - || ps->dci_format != dci_format || ps->nrOfLayers != target_ul_Nl || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) - nr_set_pusch_semi_static(NULL, scc, sched_ctrl->active_ubwp, NULL,dci_format, tda, num_dmrs_cdm_grps_no_data,target_ul_Nl,ps); + nr_set_pusch_semi_static(BWP, scc, sched_ctrl->active_ubwp, NULL, tda, num_dmrs_cdm_grps_no_data,target_ul_Nl,ps); uint16_t rbStart = 0; uint16_t rbSize; @@ -465,10 +460,10 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ /* Calculate TBS from MCS */ ps->nrOfLayers = target_ul_Nl; - sched_pusch->R = nr_get_code_rate_ul(mcs, ps->mcs_table); - sched_pusch->Qm = nr_get_Qm_ul(mcs, ps->mcs_table); - if (ps->pusch_Config->tp_pi2BPSK - && ((ps->mcs_table == 3 && mcs < 2) || (ps->mcs_table == 4 && mcs < 6))) { + sched_pusch->R = nr_get_code_rate_ul(mcs, BWP->mcs_table); + sched_pusch->Qm = nr_get_Qm_ul(mcs, BWP->mcs_table); + if (BWP->pusch_Config->tp_pi2BPSK + && ((BWP->mcs_table == 3 && mcs < 2) || (BWP->mcs_table == 4 && mcs < 6))) { sched_pusch->R >>= 1; sched_pusch->Qm <<= 1; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 8fdf0fa9a1..a9cb4121d7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -593,66 +593,31 @@ void nr_set_pdsch_semi_static(const NR_UE_DL_BWP_t *BWP, LOG_D(NR_MAC,"Filling dmrs info, ps->N_PRB_DMRS %d, ps->dl_dmrs_symb_pos %x, ps->N_DMRS_SLOT %d\n",ps->N_PRB_DMRS,ps->dl_dmrs_symb_pos,ps->N_DMRS_SLOT); } -void nr_set_pusch_semi_static(const NR_SIB1_t *sib1, +void nr_set_pusch_semi_static(const NR_UE_UL_BWP_t *BWP, const NR_ServingCellConfigCommon_t *scc, const NR_BWP_Uplink_t *ubwp, const NR_BWP_UplinkDedicated_t *ubwpd, - long dci_format, int tda, uint8_t num_dmrs_cdm_grps_no_data, uint8_t nrOfLayers, NR_pusch_semi_static_t *ps) { - ps->dci_format = dci_format; ps->time_domain_allocation = tda; - NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList = NULL; - if(ubwp) { - tdaList = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; - } else if(scc) { - tdaList = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; - } else { - tdaList = sib1->servingCellConfigCommon->uplinkConfigCommon->initialUplinkBWP.pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; - } - - const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength; + const int startSymbolAndLength = BWP->tdaList->list.array[tda]->startSymbolAndLength; SLIV2SL(startSymbolAndLength, &ps->startSymbolIndex, &ps->nrOfSymbols); - ps->pusch_Config = ubwp && ubwp->bwp_Dedicated && ubwp->bwp_Dedicated->pusch_Config ? - ubwp->bwp_Dedicated->pusch_Config->choice.setup : (ubwpd ? ubwpd->pusch_Config->choice.setup : NULL); - if (ps->pusch_Config == NULL || !ps->pusch_Config->transformPrecoder) - ps->transform_precoding = !scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder; - else - ps->transform_precoding = *ps->pusch_Config->transformPrecoder; - const int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; - if (ps->transform_precoding) - ps->mcs_table = get_pusch_mcs_table(ps->pusch_Config ? ps->pusch_Config->mcs_Table : NULL, - 0, - ps->dci_format, - NR_RNTI_C, - target_ss, - false); - else { - ps->mcs_table = get_pusch_mcs_table(ps->pusch_Config ? ps->pusch_Config->mcs_TableTransformPrecoder : NULL, - 1, - ps->dci_format, - NR_RNTI_C, - target_ss, - false); - num_dmrs_cdm_grps_no_data = 2; // in case of transform precoding - no Data sent in DMRS symbol - } - ps->nrOfLayers = nrOfLayers; - ps->num_dmrs_cdm_grps_no_data = num_dmrs_cdm_grps_no_data; + ps->num_dmrs_cdm_grps_no_data = BWP->transform_precoding ? num_dmrs_cdm_grps_no_data : 2; /* DMRS calculations */ - ps->mapping_type = tdaList->list.array[tda]->mappingType; - ps->NR_DMRS_UplinkConfig = ps->pusch_Config ? + ps->mapping_type = BWP->tdaList->list.array[tda]->mappingType; + ps->NR_DMRS_UplinkConfig = BWP->pusch_Config ? (ps->mapping_type == NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeA ? - ps->pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup : - ps->pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup) : NULL; + BWP->pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup : + BWP->pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup) : NULL; ps->dmrs_config_type = ps->NR_DMRS_UplinkConfig ? ((ps->NR_DMRS_UplinkConfig->dmrs_Type == NULL ? 0 : 1)) : 0; const pusch_dmrs_AdditionalPosition_t additional_pos = ps->NR_DMRS_UplinkConfig ? (ps->NR_DMRS_UplinkConfig->dmrs_AdditionalPosition == NULL @@ -947,13 +912,13 @@ void config_uldci(const NR_SIB1_t *sib1, const NR_ServingCellConfigCommon_t *scc, const nfapi_nr_pusch_pdu_t *pusch_pdu, dci_pdu_rel15_t *dci_pdu_rel15, - int dci_format, int time_domain_assignment, uint8_t tpc, int n_ubwp, NR_UE_UL_BWP_t *UBWP) { int bwp_id = UBWP->bwp_id; + nr_dci_format_t dci_format = UBWP->dci_format; dci_pdu_rel15->frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size, pusch_pdu->rb_start, UBWP->BWPSize); @@ -964,9 +929,9 @@ void config_uldci(const NR_SIB1_t *sib1, dci_pdu_rel15->rv = pusch_pdu->pusch_data.rv_index; dci_pdu_rel15->harq_pid = pusch_pdu->pusch_data.harq_process_id; dci_pdu_rel15->tpc = tpc; - const NR_BWP_UplinkDedicated_t *ubwpd2 = (ubwp) ? ubwp->bwp_Dedicated : ubwpd; + NR_PUSCH_Config_t *pusch_Config = UBWP->pusch_Config; - if (ubwpd2) AssertFatal(ubwpd2->pusch_Config->choice.setup->resourceAllocation == NR_PUSCH_Config__resourceAllocation_resourceAllocationType1, + if (pusch_Config) AssertFatal(pusch_Config->resourceAllocation == NR_PUSCH_Config__resourceAllocation_resourceAllocationType1, "Only frequency resource allocation type 1 is currently supported\n"); switch (dci_format) { case NR_UL_DCI_FORMAT_0_0: @@ -978,11 +943,9 @@ void config_uldci(const NR_SIB1_t *sib1, // bwp indicator as per table 7.3.1.1.2-1 in 38.212 dci_pdu_rel15->bwp_indicator.val = n_ubwp < 4 ? bwp_id : bwp_id - 1; // SRS resource indicator - if (ubwpd2 && - ubwpd2->pusch_Config && - ubwpd2->pusch_Config->choice.setup && - ubwpd2->pusch_Config->choice.setup->txConfig != NULL) { - AssertFatal(*ubwpd2->pusch_Config->choice.setup->txConfig == NR_PUSCH_Config__txConfig_codebook, + if (pusch_Config && + pusch_Config->txConfig != NULL) { + AssertFatal(*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook, "Non Codebook configuration non supported\n"); dci_pdu_rel15->srs_resource_indicator.val = 0; // taking resource 0 for SRS } @@ -1102,6 +1065,7 @@ void nr_configure_pucch(const NR_SIB1_t *sib1, NR_PUCCH_FormatConfig_t *pucchfmt; NR_PUCCH_ResourceId_t *resource_id = NULL; NR_BWP_Uplink_t *bwp = UE->UE_sched_ctrl.active_ubwp; + NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; long *id0 = NULL; int n_list, n_set; @@ -1113,12 +1077,7 @@ void nr_configure_pucch(const NR_SIB1_t *sib1, uint16_t O_uci = O_csi + O_ack; - NR_PUSCH_Config_t *pusch_Config = NULL; - if(bwp && bwp->bwp_Dedicated && bwp->bwp_Dedicated->pusch_Config) { - pusch_Config = bwp->bwp_Dedicated->pusch_Config->choice.setup; - } else if(bwpd && bwpd->pusch_Config) { - pusch_Config = bwpd->pusch_Config->choice.setup; - } + NR_PUSCH_Config_t *pusch_Config = BWP->pusch_Config; long *pusch_id = pusch_Config ? pusch_Config->dataScramblingIdentityPUSCH : NULL; @@ -1163,8 +1122,6 @@ void nr_configure_pucch(const NR_SIB1_t *sib1, else pucch_pdu->hopping_id = *scc->physCellId; - NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; - pucch_pdu->bwp_size = BWP->BWPSize; pucch_pdu->bwp_start = BWP->BWPStart; pucch_pdu->subcarrier_spacing = BWP->scs; @@ -2289,6 +2246,7 @@ void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr) } } +// main function to configure parameters of current BWP void configure_UE_BWP(gNB_MAC_INST *nr_mac, NR_ServingCellConfigCommon_t *scc, NR_UE_sched_ctrl_t *sched_ctrl, @@ -2366,22 +2324,30 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, ubwpd = servingCellConfig->uplinkConfig->initialUplinkBWP; DL_BWP->pdsch_Config = bwpd->pdsch_Config->choice.setup; + UL_BWP->pusch_Config = ubwpd->pusch_Config->choice.setup; } else { DL_BWP->bwp_id = 0; DL_BWP->bwp_id = 0; target_ss = NR_SearchSpace__searchSpaceType_PR_common; DL_BWP->pdsch_Config = NULL; + UL_BWP->pusch_Config = NULL; } if (old_dl_bwp_id != DL_BWP->bwp_id) LOG_I(NR_MAC, "Switching to DL-BWP %li\n", DL_BWP->bwp_id); + // TDA lists if (DL_BWP->bwp_id>0) DL_BWP->tdaList = dl_bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; else DL_BWP->tdaList = scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; + if(UL_BWP->bwp_id>0) + UL_BWP->tdaList = ul_bwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; + else + UL_BWP->tdaList = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; + // setting generic parameters NR_BWP_t dl_genericParameters = (DL_BWP->bwp_id>0 && dl_bwp) ? dl_bwp->bwp_Common->genericParameters: @@ -2410,7 +2376,12 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, DL_BWP->mcsTableIdx = 2; } else DL_BWP->mcsTableIdx = 0; - LOG_D(NR_MAC,"MCS Table Index: %d\n",DL_BWP->mcsTableIdx); + LOG_D(NR_MAC,"DL MCS Table Index: %d\n",DL_BWP->mcsTableIdx); + + if (UL_BWP->pusch_Config == NULL || !UL_BWP->pusch_Config->transformPrecoder) + UL_BWP->transform_precoding = !scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder; + else + UL_BWP->transform_precoding = *UL_BWP->pusch_Config->transformPrecoder; if(UE) { // setting PDCCH related structures for sched_ctrl @@ -2429,6 +2400,14 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, scc, &dl_genericParameters, nr_mac->type0_PDCCH_CSS_config); + + // set UL DCI format + UL_BWP->dci_format = (sched_ctrl->search_space->searchSpaceType && + sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific) ? + (sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats == NR_SearchSpace__searchSpaceType__ue_Specific__dci_Formats_formats0_1_And_1_1 ? + NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0) : + NR_UL_DCI_FORMAT_0_0; + } if(ra) { @@ -2457,7 +2436,23 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, scc, &dl_genericParameters, &nr_mac->type0_PDCCH_CSS_config[ra->beam_id]); + + UL_BWP->dci_format = NR_UL_DCI_FORMAT_0_0; } + + // Set uplink MCS table + long *mcs_Table = NULL; + if (UL_BWP->pusch_Config) + mcs_Table = UL_BWP->transform_precoding ? + UL_BWP->pusch_Config->mcs_Table : + UL_BWP->pusch_Config->mcs_TableTransformPrecoder; + + UL_BWP->mcs_table = get_pusch_mcs_table(mcs_Table, + UL_BWP->transform_precoding ? 0 : 1, + UL_BWP->dci_format, + NR_RNTI_C, + target_ss, + false); } //------------------------------------------------------------------------------ @@ -2951,8 +2946,8 @@ void nr_csirs_scheduling(int Mod_idP, void nr_mac_update_timers(module_id_t module_id, frame_t frame, sub_frame_t slot) { - NR_UEs_t *UE_info = &RC.nrmac[module_id]->UE_info; + NR_UEs_t *UE_info = &RC.nrmac[module_id]->UE_info; UE_iterator(UE_info->list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; if (sched_ctrl->rrc_processing_timer > 0) { @@ -2960,8 +2955,6 @@ void nr_mac_update_timers(module_id_t module_id, if (sched_ctrl->rrc_processing_timer == 0) { LOG_I(NR_MAC, "(%d.%d) De-activating RRC processing timer for UE %04x\n", frame, slot, UE->rnti); - const NR_SIB1_t *sib1 = RC.nrmac[module_id]->common_channels[0].sib1 ? RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - NR_CellGroupConfig_t *cg = NULL; uper_decode(NULL, &asn_DEF_NR_CellGroupConfig, //might be added prefix later @@ -3034,16 +3027,14 @@ void nr_mac_update_timers(module_id_t module_id, } NR_pusch_semi_static_t *ups = &sched_ctrl->pusch_semi_static; - int dci_format = get_dci_format(sched_ctrl); const uint8_t num_dmrs_cdm_grps_no_data = (ubwp || ubwpd) ? 1 : 2; const uint8_t nrOfLayers = 1; const int utda = get_ul_tda(RC.nrmac[module_id], scc, slot); - nr_set_pusch_semi_static(sib1, + nr_set_pusch_semi_static(&UE->current_UL_BWP, scc, ubwp, ubwpd, - dci_format, utda, num_dmrs_cdm_grps_no_data, nrOfLayers, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 49cbcd7a88..eb23775a24 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -37,15 +37,6 @@ #include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" -int get_dci_format(NR_UE_sched_ctrl_t *sched_ctrl) { - - int dci_format = sched_ctrl->search_space && sched_ctrl->search_space->searchSpaceType && - sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific ? - NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0; - - return(dci_format); -} - const int get_ul_tda(const gNB_MAC_INST *nrmac, const NR_ServingCellConfigCommon_t *scc, int slot) { /* there is a mixed slot only when in TDD */ @@ -760,23 +751,14 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, } } -long get_K2(NR_ServingCellConfigCommon_t *scc, - NR_ServingCellConfigCommonSIB_t *scc_sib1, - NR_BWP_Uplink_t *ubwp, +long get_K2(NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList, int time_domain_assignment, int mu) { - NR_PUSCH_TimeDomainResourceAllocation_t *tda_list = NULL; - if(ubwp) { - tda_list = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[time_domain_assignment]; - } else if(scc) { - tda_list = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[time_domain_assignment]; - } else if(scc_sib1) { - tda_list = scc_sib1->uplinkConfigCommon->initialUplinkBWP.pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[time_domain_assignment]; - } + NR_PUSCH_TimeDomainResourceAllocation_t *tda = tdaList->list.array[time_domain_assignment]; - if (tda_list->k2) - return *tda_list->k2; + if (tda->k2) + return *tda->k2; else if (mu < 2) return 1; else if (mu == 2) @@ -857,17 +839,13 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, * (re-)transmission */ NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; - int dci_format = get_dci_format(sched_ctrl); - if (ps->time_domain_allocation != tda - || ps->dci_format != dci_format || ps->nrOfLayers != nrOfLayers || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) { - nr_set_pusch_semi_static(sib1, + nr_set_pusch_semi_static(&UE->current_UL_BWP, scc, sched_ctrl->active_ubwp, ubwpd, - dci_format, tda, num_dmrs_cdm_grps_no_data, nrOfLayers, @@ -885,12 +863,10 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, LOG_D(NR_MAC, "%s(): retransmission keeping TDA %d and TBS %d\n", __func__, tda, retInfo->tb_size); } else { NR_pusch_semi_static_t temp_ps; - int dci_format = get_dci_format(sched_ctrl); - nr_set_pusch_semi_static(sib1, + nr_set_pusch_semi_static(&UE->current_UL_BWP, scc, sched_ctrl->active_ubwp, ubwpd, - dci_format, tda, num_dmrs_cdm_grps_no_data, nrOfLayers, @@ -988,13 +964,13 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, return true; } -void update_ul_ue_R_Qm(NR_sched_pusch_t *sched_pusch, const NR_pusch_semi_static_t *ps) -{ - const int mcs = sched_pusch->mcs; - sched_pusch->R = nr_get_code_rate_ul(mcs, ps->mcs_table); - sched_pusch->Qm = nr_get_Qm_ul(mcs, ps->mcs_table); +void update_ul_ue_R_Qm(NR_sched_pusch_t *sched_pusch, const NR_PUSCH_Config_t *pusch_Config, const int mcs_table) { - if (ps->pusch_Config && ps->pusch_Config->tp_pi2BPSK && ((ps->mcs_table == 3 && mcs < 2) || (ps->mcs_table == 4 && mcs < 6))) { + const int mcs = sched_pusch->mcs; + sched_pusch->R = nr_get_code_rate_ul(mcs, mcs_table); + sched_pusch->Qm = nr_get_Qm_ul(mcs, mcs_table); + + if (pusch_Config && pusch_Config->tp_pi2BPSK && ((mcs_table == 3 && mcs < 2) || (mcs_table == 4 && mcs < 6))) { sched_pusch->R >>= 1; sched_pusch->Qm <<= 1; } @@ -1127,21 +1103,18 @@ void pf_ul(module_id_t module_id, /* Save PUSCH field */ /* we want to avoid a lengthy deduction of DMRS and other parameters in - * every TTI if we can save it, so check whether dci_format, TDA, or + * every TTI if we can save it, so check whether TDA, or * num_dmrs_cdm_grps_no_data has changed and only then recompute */ const uint8_t nrOfLayers = 1; const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_ubwp || ubwpd) ? 1 : 2; - int dci_format = get_dci_format(sched_ctrl); const int tda = get_ul_tda(nrmac, scc, sched_pusch->slot); if (ps->time_domain_allocation != tda - || ps->dci_format != dci_format || ps->nrOfLayers != nrOfLayers || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) { - nr_set_pusch_semi_static(sib1, + nr_set_pusch_semi_static(BWP, scc, sched_ctrl->active_ubwp, ubwpd, - dci_format, tda, num_dmrs_cdm_grps_no_data, nrOfLayers, @@ -1168,7 +1141,7 @@ void pf_ul(module_id_t module_id, NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; sched_pusch->mcs = min(nrmac->min_grant_mcs, sched_pusch->mcs); - update_ul_ue_R_Qm(sched_pusch, ps); + update_ul_ue_R_Qm(sched_pusch, BWP->pusch_Config, BWP->mcs_table); sched_pusch->rbStart = rbStart; sched_pusch->rbSize = min_rb; sched_pusch->tb_size = nr_compute_tbs(sched_pusch->Qm, @@ -1191,7 +1164,7 @@ void pf_ul(module_id_t module_id, /* Create UE_sched for UEs eligibale for new data transmission*/ /* Calculate coefficient*/ - const uint32_t tbs = ul_pf_tbs[ps->mcs_table][sched_pusch->mcs]; + const uint32_t tbs = ul_pf_tbs[BWP->mcs_table][sched_pusch->mcs]; float coeff_ue = (float) tbs / UE->ul_thr_ue; LOG_D(NR_MAC,"rnti %04x b %d, ul_thr_ue %f, tbs %d, coeff_ue %f\n", UE->rnti, b, UE->ul_thr_ue, tbs, coeff_ue); @@ -1249,27 +1222,24 @@ void pf_ul(module_id_t module_id, /* Save PUSCH field */ /* we want to avoid a lengthy deduction of DMRS and other parameters in - * every TTI if we can save it, so check whether dci_format, TDA, or + * every TTI if we can save it, so check whether TDA, or * num_dmrs_cdm_grps_no_data has changed and only then recompute */ const uint8_t nrOfLayers = 1; const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_ubwp || ubwpd) ? 1 : 2; - int dci_format = get_dci_format(sched_ctrl); const int tda = get_ul_tda(nrmac, scc, sched_pusch->slot); if (ps->time_domain_allocation != tda - || ps->dci_format != dci_format || ps->nrOfLayers != nrOfLayers || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) { - nr_set_pusch_semi_static(sib1, + nr_set_pusch_semi_static(BWP, scc, sched_ctrl->active_ubwp, ubwpd, - dci_format, tda, num_dmrs_cdm_grps_no_data, nrOfLayers, ps); } - update_ul_ue_R_Qm(sched_pusch, ps); + update_ul_ue_R_Qm(sched_pusch, BWP->pusch_Config, BWP->mcs_table); const uint16_t slbitmap = SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols); while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap) @@ -1350,13 +1320,13 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t NR_UE_UL_BWP_t *BWP = &nr_mac->UE_info.list[0]->current_UL_BWP; int mu = BWP->scs; const int temp_tda = get_ul_tda(nr_mac, scc, slot); - int K2 = get_K2(scc, scc_sib1, sched_ctrl->active_ubwp, temp_tda, mu); + int K2 = get_K2(BWP->tdaList, temp_tda, mu); const int sched_frame = (frame + (slot + K2 >= nr_slots_per_frame[mu])) & 1023; const int sched_slot = (slot + K2) % nr_slots_per_frame[mu]; const int tda = get_ul_tda(nr_mac, scc, sched_slot); if (tda < 0) return false; - DevAssert(K2 == get_K2(scc, scc_sib1, sched_ctrl->active_ubwp, tda, mu)); + DevAssert(K2 == get_K2(BWP->tdaList, tda, mu)); if (!is_xlsch_in_slot(nr_mac->ulsch_slot_bitmap[sched_slot / 64], sched_slot)) return false; @@ -1385,9 +1355,9 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t sched_ctrl->sched_pusch.frame = sched_frame; UE_iterator(nr_mac->UE_info.list, UE2) { NR_UE_sched_ctrl_t *sched_ctrl = &UE2->UE_sched_ctrl; - AssertFatal(K2 == get_K2(scc,scc_sib1,sched_ctrl->active_ubwp, tda, mu), + AssertFatal(K2 == get_K2(BWP->tdaList, tda, mu), "Different K2, %d(UE%d) != %ld(UE%04x)\n", - K2, 0, get_K2(scc,scc_sib1,sched_ctrl->active_ubwp, tda, mu), UE2->rnti); + K2, 0, get_K2(BWP->tdaList, tda, mu), UE2->rnti); sched_ctrl->sched_pusch.slot = sched_slot; sched_ctrl->sched_pusch.frame = sched_frame; } @@ -1401,17 +1371,7 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t const uint16_t bwpSize = BWP->BWPSize; const uint16_t bwpStart = BWP->BWPStart; - NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList = NULL; - if (sched_ctrl->active_ubwp) { - tdaList = sched_ctrl->active_ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; - } else if (scc) { - tdaList = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; - } else { - NR_SIB1_t *sib1 = RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1; - tdaList = sib1->servingCellConfigCommon->uplinkConfigCommon->initialUplinkBWP.pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; - } - - const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength; + const int startSymbolAndLength = BWP->tdaList->list.array[tda]->startSymbolAndLength; int startSymbolIndex, nrOfSymbols; SLIV2SL(startSymbolAndLength, &startSymbolIndex, &nrOfSymbols); const uint16_t symb = SL_to_bitmap(startSymbolIndex, nrOfSymbols); @@ -1651,10 +1611,10 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) pusch_pdu->target_code_rate = sched_pusch->R; pusch_pdu->qam_mod_order = sched_pusch->Qm; pusch_pdu->mcs_index = sched_pusch->mcs; - pusch_pdu->mcs_table = ps->mcs_table; - pusch_pdu->transform_precoding = ps->transform_precoding; - if (ps->pusch_Config && ps->pusch_Config->dataScramblingIdentityPUSCH) - pusch_pdu->data_scrambling_id = *ps->pusch_Config->dataScramblingIdentityPUSCH; + pusch_pdu->mcs_table = current_BWP->mcs_table; + pusch_pdu->transform_precoding = current_BWP->transform_precoding; + if (current_BWP->pusch_Config && current_BWP->pusch_Config->dataScramblingIdentityPUSCH) + pusch_pdu->data_scrambling_id = *current_BWP->pusch_Config->dataScramblingIdentityPUSCH; else pusch_pdu->data_scrambling_id = *scc->physCellId; pusch_pdu->nrOfLayers = ps->nrOfLayers; @@ -1690,7 +1650,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) pusch_pdu->rb_start = sched_pusch->rbStart; pusch_pdu->rb_size = sched_pusch->rbSize; pusch_pdu->vrb_to_prb_mapping = 0; - if (ps->pusch_Config==NULL || ps->pusch_Config->frequencyHopping==NULL) + if (current_BWP->pusch_Config==NULL || current_BWP->pusch_Config->frequencyHopping==NULL) pusch_pdu->frequency_hopping = 0; else pusch_pdu->frequency_hopping = 1; @@ -1724,7 +1684,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) else AssertFatal(1==0,"SequenceGroupHopping or sequenceHopping are NOT Supported\n"); - LOG_D(NR_MAC,"TRANSFORM PRECODING IS ENABLED. CDM groups: %d, U: %d MCS table: %d\n", pusch_pdu->num_dmrs_cdm_grps_no_data, pusch_pdu->dfts_ofdm.low_papr_group_number, ps->mcs_table); + LOG_D(NR_MAC,"TRANSFORM PRECODING IS ENABLED. CDM groups: %d, U: %d MCS table: %d\n", pusch_pdu->num_dmrs_cdm_grps_no_data, pusch_pdu->dfts_ofdm.low_papr_group_number, current_BWP->mcs_table); } /*-----------------------------------------------------------------------------*/ @@ -1799,7 +1759,6 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) scc, pusch_pdu, &uldci_payload, - ps->dci_format, ps->time_domain_allocation, UE->UE_sched_ctrl.tpc0, n_ubwp, @@ -1809,7 +1768,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) &UE->current_DL_BWP, dci_pdu, &uldci_payload, - ps->dci_format, + current_BWP->dci_format, rnti_types[0], pusch_pdu->bwp_size, current_BWP->bwp_id, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 26679a1b7c..bc145b6dd9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -197,7 +197,6 @@ void config_uldci(const NR_SIB1_t *sib1, const NR_ServingCellConfigCommon_t *scc, const nfapi_nr_pusch_pdu_t *pusch_pdu, dci_pdu_rel15_t *dci_pdu_rel15, - int dci_format, int time_domain_assignment, uint8_t tpc, int n_ubwp, @@ -333,9 +332,7 @@ NR_SearchSpace_t *get_searchspace(NR_ServingCellConfigCommon_t *scc, NR_BWP_DownlinkDedicated_t *bwp_Dedicated, NR_SearchSpace__searchSpaceType_PR target_ss); -long get_K2(NR_ServingCellConfigCommon_t *scc, - NR_ServingCellConfigCommonSIB_t *scc_sib1, - NR_BWP_Uplink_t *ubwp, +long get_K2(NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList, int time_domain_assignment, int mu); @@ -347,11 +344,10 @@ void nr_set_pdsch_semi_static(const NR_UE_DL_BWP_t *BWP, NR_UE_sched_ctrl_t *sched_ctrl, NR_pdsch_semi_static_t *ps); -void nr_set_pusch_semi_static(const NR_SIB1_t *sib1, +void nr_set_pusch_semi_static(const NR_UE_UL_BWP_t *BWP, const NR_ServingCellConfigCommon_t *scc, const NR_BWP_Uplink_t *ubwp, const NR_BWP_UplinkDedicated_t *ubwpd, - long dci_format, int tda, uint8_t num_dmrs_cdm_grps_no_data, uint8_t nrOfLayers, @@ -499,7 +495,6 @@ uint8_t get_mcs_from_cqi(int mcs_table, int cqi_table, int cqi_idx); uint8_t set_dl_nrOfLayers(NR_UE_sched_ctrl_t *sched_ctrl); -int get_dci_format(NR_UE_sched_ctrl_t *sched_ctrl); const int get_dl_tda(const gNB_MAC_INST *nrmac, const NR_ServingCellConfigCommon_t *scc, int slot); const int get_ul_tda(const gNB_MAC_INST *nrmac, const NR_ServingCellConfigCommon_t *scc, int slot); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index e38c23cf72..ca239ee51e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -109,6 +109,11 @@ typedef struct NR_UE_UL_BWP { long *cyclicprefix; uint16_t BWPSize; uint16_t BWPStart; + NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList; + NR_PUSCH_Config_t *pusch_Config; + uint8_t transform_precoding; + uint8_t mcs_table; + nr_dci_format_t dci_format; } NR_UE_UL_BWP_t; typedef enum { @@ -364,18 +369,11 @@ typedef struct NR_sched_pucch { * recalculate all S/L, MCS table, or DMRS-related parameters over and over * again. Hence, we store them in this struct for easy reference. */ typedef struct NR_pusch_semi_static_t { - int dci_format; int time_domain_allocation; uint8_t nrOfLayers; uint8_t num_dmrs_cdm_grps_no_data; - int startSymbolIndex; int nrOfSymbols; - - NR_PUSCH_Config_t *pusch_Config; - uint8_t transform_precoding; - uint8_t mcs_table; - long mapping_type; NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig; uint16_t dmrs_config_type; From 3cd49db442c07cdbeef2b3e5f29a75c66ddbc50d Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 17 Jun 2022 16:34:01 +0200 Subject: [PATCH 139/267] removing ul active_bwp --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 17 +-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 22 +--- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 11 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 121 ++++++------------ .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 56 ++------ .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 59 +-------- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 14 +- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 8 +- 8 files changed, 68 insertions(+), 240 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index ffce9533c5..6e2af05a13 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -699,13 +699,7 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; NR_UE_UL_BWP_t *UL_BWP = &ra->UL_BWP; - NR_BWP_Uplink_t *ubwp = NULL; - NR_BWP_UplinkDedicated_t *ubwpd = NULL; NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = UL_BWP->tdaList; - if(ra->CellGroup) { - ubwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[UL_BWP->bwp_id-1]; - ubwpd = ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; - } int mu = UL_BWP->scs; uint8_t K2 = *pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->k2; const int sched_frame = frame + (slot + K2 >= nr_slots_per_frame[mu]); @@ -834,14 +828,11 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t const NR_SIB1_t *sib1 = cc->sib1 ? cc->sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; config_uldci(sib1, - ubwp, - ubwpd, scc, pusch_pdu, &uldci_payload, ra->Msg3_tda_id, ra->msg3_TPC, - 0, // not used in format 0_0 &ra->UL_BWP); fill_dci_pdu_rel15(scc, @@ -879,7 +870,6 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t void nr_get_Msg3alloc(module_id_t module_id, int CC_id, NR_ServingCellConfigCommon_t *scc, - NR_BWP_Uplink_t *ubwp, sub_frame_t current_slot, frame_t current_frame, NR_RA_t *ra, @@ -1393,10 +1383,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra nfapi_nr_pdu_t *tx_req = &nr_mac->TX_req[CC_id].pdu_list[nr_mac->TX_req[CC_id].Number_of_PDUs]; // Program UL processing for Msg3 - NR_BWP_Uplink_t *ubwp = ra->CellGroup ? - ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra->UL_BWP.bwp_id-1] : - NULL; - nr_get_Msg3alloc(module_idP, CC_id, scc, ubwp, slotP, frameP, ra, nr_mac->tdd_beam_association); + nr_get_Msg3alloc(module_idP, CC_id, scc, slotP, frameP, ra, nr_mac->tdd_beam_association); nr_add_msg3(module_idP, CC_id, frameP, slotP, ra, (uint8_t *) &tx_req->TLVs[0].value.direct[0]); if(ra->cfra) { @@ -1520,7 +1507,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra } const int delta_PRI=0; - int r_pucch = nr_get_pucch_resource(coreset, sched_ctrl->active_ubwp, NULL, CCEIndex); + int r_pucch = nr_get_pucch_resource(coreset, ra->UL_BWP.pucch_Config, CCEIndex); LOG_D(NR_MAC,"[RAPROC] Msg4 r_pucch %d (CCEIndex %d, nb_of_candidates %d, delta_PRI %d)\n", r_pucch, CCEIndex, nr_of_candidates, delta_PRI); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 70f4a98a99..079bc3da40 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -377,16 +377,10 @@ bool allocate_dl_retransmission(module_id_t module_id, const NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels->ServingCellConfigCommon; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_DL_BWP_t *BWP = &UE->current_DL_BWP; + NR_UE_UL_BWP_t *UBWP = &UE->current_UL_BWP; NR_sched_pdsch_t *retInfo = &sched_ctrl->harq_processes[current_harq_pid].sched_pdsch; NR_CellGroupConfig_t *cg = UE->CellGroup; - NR_BWP_UplinkDedicated_t *ubwpd = - cg && - cg->spCellConfig && - cg->spCellConfig->spCellConfigDedicated && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? - cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; - const int coresetid = sched_ctrl->coreset->controlResourceSetId; const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : BWP->BWPSize; @@ -506,7 +500,7 @@ bool allocate_dl_retransmission(module_id_t module_id, /* Find PUCCH occasion: if it fails, undo CCE allocation (undoing PUCCH * allocation after CCE alloc fail would be more complex) */ - int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, sched_ctrl->active_ubwp, ubwpd, CCEIndex); + int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, UBWP->pucch_Config, CCEIndex); const int alloc = nr_acknack_scheduling(module_id, UE, frame, slot, r_pucch, 0); if (alloc<0) { LOG_D(MAC, @@ -639,19 +633,11 @@ void pf_dl(module_id_t module_id, /* Loop UE_sched to find max coeff and allocate transmission */ while (remainUEs> 0 && n_rb_sched >= min_rbSize && iterator->UE != NULL) { - NR_CellGroupConfig_t *cg = iterator->UE->CellGroup; - - NR_BWP_UplinkDedicated_t *ubwpd = - cg && - cg->spCellConfig && - cg->spCellConfig->spCellConfigDedicated && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? - cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; - NR_UE_sched_ctrl_t *sched_ctrl = &iterator->UE->UE_sched_ctrl; const uint16_t rnti = iterator->UE->rnti; NR_UE_DL_BWP_t *BWP = &iterator->UE->current_DL_BWP; + NR_UE_UL_BWP_t *UBWP = &iterator->UE->current_UL_BWP; const int coresetid = sched_ctrl->coreset->controlResourceSetId; const uint16_t bwpSize = coresetid == 0 ? @@ -697,7 +683,7 @@ void pf_dl(module_id_t module_id, /* Find PUCCH occasion: if it fails, undo CCE allocation (undoing PUCCH * allocation after CCE alloc fail would be more complex) */ - int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, sched_ctrl->active_ubwp, ubwpd, CCEIndex); + int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, UBWP->pucch_Config, CCEIndex); const int alloc = nr_acknack_scheduling(module_id, iterator->UE, frame, slot, r_pucch, 0); if (alloc<0) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index 48eff7794e..64c7447ed9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -280,7 +280,7 @@ void nr_preprocessor_phytest(module_id_t module_id, __func__, UE->rnti); - int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, sched_ctrl->active_ubwp, NULL, CCEIndex); + int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, UE->current_UL_BWP.pucch_Config, CCEIndex); const int alloc = nr_acknack_scheduling(module_id, UE, frame, slot, r_pucch, 0); if (alloc < 0) { LOG_D(MAC, @@ -379,18 +379,13 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ if (!is_xlsch_in_slot(ulsch_slot_bitmap, sched_slot)) return false; - uint8_t num_dmrs_cdm_grps_no_data = 1; - if ((target_ul_Nl==4)||(target_ul_Nl==3)) - num_dmrs_cdm_grps_no_data = 2; - /* we want to avoid a lengthy deduction of DMRS and other parameters in * every TTI if we can save it, so check whether TDA, or * num_dmrs_cdm_grps_no_data has changed and only then recompute */ NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; if (ps->time_domain_allocation != tda - || ps->nrOfLayers != target_ul_Nl - || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) - nr_set_pusch_semi_static(BWP, scc, sched_ctrl->active_ubwp, NULL, tda, num_dmrs_cdm_grps_no_data,target_ul_Nl,ps); + || ps->nrOfLayers != target_ul_Nl) + nr_set_pusch_semi_static(BWP, scc, tda, target_ul_Nl,ps); uint16_t rbStart = 0; uint16_t rbSize; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index a9cb4121d7..ab17aebc6e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -595,10 +595,7 @@ void nr_set_pdsch_semi_static(const NR_UE_DL_BWP_t *BWP, void nr_set_pusch_semi_static(const NR_UE_UL_BWP_t *BWP, const NR_ServingCellConfigCommon_t *scc, - const NR_BWP_Uplink_t *ubwp, - const NR_BWP_UplinkDedicated_t *ubwpd, int tda, - uint8_t num_dmrs_cdm_grps_no_data, uint8_t nrOfLayers, NR_pusch_semi_static_t *ps) { @@ -610,7 +607,11 @@ void nr_set_pusch_semi_static(const NR_UE_UL_BWP_t *BWP, &ps->nrOfSymbols); ps->nrOfLayers = nrOfLayers; - ps->num_dmrs_cdm_grps_no_data = BWP->transform_precoding ? num_dmrs_cdm_grps_no_data : 2; + // TODO setting of cdm groups with no data to be redone for MIMO + if (BWP->transform_precoding || nrOfLayers<3) + ps->num_dmrs_cdm_grps_no_data = (BWP->dci_format == NR_UL_DCI_FORMAT_0_1) ? 1 : (ps->nrOfSymbols == 2 ? 1 : 2); + else + ps->num_dmrs_cdm_grps_no_data = 2; /* DMRS calculations */ ps->mapping_type = BWP->tdaList->list.array[tda]->mappingType; @@ -639,8 +640,8 @@ void nr_set_pusch_semi_static(const NR_UE_UL_BWP_t *BWP, num_dmrs_symb += (ps->ul_dmrs_symb_pos >> i) & 1; ps->num_dmrs_symb = num_dmrs_symb; ps->N_PRB_DMRS = ps->dmrs_config_type == 0 - ? num_dmrs_cdm_grps_no_data * 6 - : num_dmrs_cdm_grps_no_data * 4; + ? ps->num_dmrs_cdm_grps_no_data * 6 + : ps->num_dmrs_cdm_grps_no_data * 4; } #define BLER_UPDATE_FRAME 10 @@ -907,14 +908,11 @@ void nr_configure_css_dci_initial(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu, } void config_uldci(const NR_SIB1_t *sib1, - const NR_BWP_Uplink_t *ubwp, - const NR_BWP_UplinkDedicated_t *ubwpd, const NR_ServingCellConfigCommon_t *scc, const nfapi_nr_pusch_pdu_t *pusch_pdu, dci_pdu_rel15_t *dci_pdu_rel15, int time_domain_assignment, uint8_t tpc, - int n_ubwp, NR_UE_UL_BWP_t *UBWP) { int bwp_id = UBWP->bwp_id; @@ -941,7 +939,7 @@ void config_uldci(const NR_SIB1_t *sib1, LOG_D(NR_MAC,"Configuring DCI Format 0_1\n"); dci_pdu_rel15->dai[0].val = 0; //TODO // bwp indicator as per table 7.3.1.1.2-1 in 38.212 - dci_pdu_rel15->bwp_indicator.val = n_ubwp < 4 ? bwp_id : bwp_id - 1; + dci_pdu_rel15->bwp_indicator.val = UBWP->n_ul_bwp < 4 ? bwp_id : bwp_id - 1; // SRS resource indicator if (pusch_Config && pusch_Config->txConfig != NULL) { @@ -1033,11 +1031,10 @@ void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, } int nr_get_pucch_resource(NR_ControlResourceSet_t *coreset, - NR_BWP_Uplink_t *bwp, - NR_BWP_UplinkDedicated_t *bwpd, + NR_PUCCH_Config_t *pucch_Config, int CCEIndex) { int r_pucch = -1; - if(bwp == NULL && bwpd == NULL) { + if(pucch_Config == NULL) { int n_rb,rb_offset; get_coreset_rballoc(coreset->frequencyDomainResources.buf,&n_rb,&rb_offset); const uint16_t N_cce = n_rb * coreset->duration / NR_NB_REG_PER_CCE; @@ -1048,23 +1045,19 @@ int nr_get_pucch_resource(NR_ControlResourceSet_t *coreset, } // This function configures pucch pdu fapi structure -void nr_configure_pucch(const NR_SIB1_t *sib1, - nfapi_nr_pucch_pdu_t* pucch_pdu, +void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, NR_ServingCellConfigCommon_t *scc, NR_UE_info_t* UE, - NR_BWP_UplinkDedicated_t *bwpd, uint8_t pucch_resource, uint16_t O_csi, uint16_t O_ack, uint8_t O_sr, int r_pucch) { - NR_PUCCH_Config_t *pucch_Config; NR_PUCCH_Resource_t *pucchres; NR_PUCCH_ResourceSet_t *pucchresset; NR_PUCCH_FormatConfig_t *pucchfmt; NR_PUCCH_ResourceId_t *resource_id = NULL; - NR_BWP_Uplink_t *bwp = UE->UE_sched_ctrl.active_ubwp; NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; long *id0 = NULL; @@ -1087,14 +1080,7 @@ void nr_configure_pucch(const NR_SIB1_t *sib1, id0 = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->transformPrecodingDisabled->scramblingID0; else id0 = scc->physCellId; - NR_PUCCH_ConfigCommon_t *pucch_ConfigCommon = NULL; - if(bwp) { - pucch_ConfigCommon = bwp->bwp_Common->pucch_ConfigCommon->choice.setup; - } else if(scc) { - pucch_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup; - } else { - pucch_ConfigCommon = sib1->servingCellConfigCommon->uplinkConfigCommon->initialUplinkBWP.pucch_ConfigCommon->choice.setup; - } + NR_PUCCH_ConfigCommon_t *pucch_ConfigCommon = BWP->pucch_ConfigCommon; // hop flags and hopping id are valid for any BWP switch (pucch_ConfigCommon->pucch_GroupHopping){ @@ -1126,12 +1112,10 @@ void nr_configure_pucch(const NR_SIB1_t *sib1, pucch_pdu->bwp_start = BWP->BWPStart; pucch_pdu->subcarrier_spacing = BWP->scs; pucch_pdu->cyclic_prefix = (BWP->cyclicprefix==NULL) ? 0 : *BWP->cyclicprefix; - if (r_pucch<0 || bwp ){ + + NR_PUCCH_Config_t *pucch_Config = BWP->pucch_Config; + if (r_pucch<0 || pucch_Config){ LOG_D(NR_MAC,"pucch_acknak: Filling dedicated configuration for PUCCH\n"); - // we have either a dedicated BWP or Dedicated PUCCH configuration on InitialBWP - AssertFatal(bwp!=NULL || bwpd!=NULL,"We need one dedicated configuration for a BWP (neither additional or initial BWP has a dedicated configuration)\n"); - pucch_Config = bwp && bwp->bwp_Dedicated && bwp->bwp_Dedicated->pucch_Config ? - bwp->bwp_Dedicated->pucch_Config->choice.setup : bwpd->pucch_Config->choice.setup; AssertFatal(pucch_Config->resourceSetToAddModList!=NULL, "PUCCH resourceSetToAddModList is null\n"); @@ -1273,8 +1257,8 @@ void nr_configure_pucch(const NR_SIB1_t *sib1, LOG_D(NR_MAC,"Configure pucch: pucch_pdu->format_type %d pucch_pdu->bit_len_harq %d, pucch->pdu->bit_len_csi %d\n",pucch_pdu->format_type,pucch_pdu->bit_len_harq,pucch_pdu->bit_len_csi_part1); } else { // this is the default PUCCH configuration, PUCCH format 0 or 1 - LOG_D(NR_MAC,"pucch_acknak: Filling default PUCCH configuration from Tables (r_pucch %d, bwp %p)\n",r_pucch,bwp); - int rsetindex = *scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->pucch_ResourceCommon; + LOG_D(NR_MAC,"pucch_acknak: Filling default PUCCH configuration from Tables (r_pucch %d, pucch_Config %p)\n",r_pucch,pucch_Config); + int rsetindex = *pucch_ConfigCommon->pucch_ResourceCommon; int prb_start, second_hop_prb, nr_of_symb, start_symb; set_r_pucch_parms(rsetindex, r_pucch, @@ -2271,8 +2255,11 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, NR_BWP_Uplink_t *ul_bwp = NULL; NR_BWP_DownlinkDedicated_t *bwpd = NULL; NR_BWP_UplinkDedicated_t *ubwpd = NULL; + NR_CSI_MeasConfig_t *csi_MeasConfig = NULL; DL_BWP->n_dl_bwp = 1; + UL_BWP->n_ul_bwp = 1; int old_dl_bwp_id = DL_BWP->bwp_id; + int old_ul_bwp_id = UL_BWP->bwp_id; int target_ss; @@ -2281,6 +2268,7 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, CellGroup->spCellConfig->spCellConfigDedicated) { const NR_ServingCellConfig_t *servingCellConfig = CellGroup->spCellConfig->spCellConfigDedicated; + csi_MeasConfig = servingCellConfig->csi_MeasConfig ? servingCellConfig->csi_MeasConfig->choice.setup : NULL; target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; // (re)configuring BWP @@ -2304,6 +2292,8 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, } const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList; + if(ubwpList) + UL_BWP->n_ul_bwp = ubwpList->list.count; if (UL_BWP->bwp_id>0) { for (int i=0; ilist.count; i++) { ul_bwp = ubwpList->list.array[i]; @@ -2325,6 +2315,7 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, DL_BWP->pdsch_Config = bwpd->pdsch_Config->choice.setup; UL_BWP->pusch_Config = ubwpd->pusch_Config->choice.setup; + UL_BWP->pucch_Config = ubwpd->pucch_Config->choice.setup; } else { DL_BWP->bwp_id = 0; @@ -2332,10 +2323,13 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, target_ss = NR_SearchSpace__searchSpaceType_PR_common; DL_BWP->pdsch_Config = NULL; UL_BWP->pusch_Config = NULL; + UL_BWP->pucch_Config = NULL; } if (old_dl_bwp_id != DL_BWP->bwp_id) LOG_I(NR_MAC, "Switching to DL-BWP %li\n", DL_BWP->bwp_id); + if (old_ul_bwp_id != UL_BWP->bwp_id) + LOG_I(NR_MAC, "Switching to UL-BWP %li\n", UL_BWP->bwp_id); // TDA lists if (DL_BWP->bwp_id>0) @@ -2383,6 +2377,12 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, else UL_BWP->transform_precoding = *UL_BWP->pusch_Config->transformPrecoder; + if(UL_BWP->bwp_id>0) + UL_BWP->pucch_ConfigCommon = ul_bwp->bwp_Common->pucch_ConfigCommon->choice.setup; + else + UL_BWP->pucch_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup; + + if(UE) { // setting PDCCH related structures for sched_ctrl sched_ctrl->search_space = get_searchspace(scc, @@ -2408,6 +2408,9 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0) : NR_UL_DCI_FORMAT_0_0; + if (csi_MeasConfig) + compute_csi_bitlen (csi_MeasConfig, UE); + } if(ra) { @@ -2480,13 +2483,6 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf else UE->Msg4_ACKed = false; - if (CellGroup && - CellGroup->spCellConfig && - CellGroup->spCellConfig->spCellConfigDedicated && - CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig && - CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup) - compute_csi_bitlen (CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup, UE); - NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; memset(sched_ctrl, 0, sizeof(*sched_ctrl)); sched_ctrl->dl_max_mcs = 28; /* do not limit MCS for individual UEs */ @@ -2523,8 +2519,6 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf "uplinkBWP_ToAddModList has %d BWP!\n", ubwpList->list.count); - sched_ctrl->active_ubwp = ubwpList && UL_BWP->bwp_id > 0 ? ubwpList->list.array[UL_BWP->bwp_id - 1] : NULL; - /* get Number of HARQ processes for this UE */ if (servingCellConfig) AssertFatal(servingCellConfig->pdsch_ServingCellConfig->present == NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup, @@ -2648,7 +2642,6 @@ void get_pdsch_to_harq_feedback(NR_UE_info_t *UE, NR_CellGroupConfig_t *CellGroup = UE->CellGroup; NR_BWP_DownlinkDedicated_t *bwpd=NULL; - NR_BWP_UplinkDedicated_t *ubwpd=NULL; int dl_bwp_id = UE->current_DL_BWP.bwp_id; int ul_bwp_id = UE->current_UL_BWP.bwp_id; @@ -2670,13 +2663,10 @@ void get_pdsch_to_harq_feedback(NR_UE_info_t *UE, CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count,ul_bwp_id); bwpd = CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[dl_bwp_id-1]->bwp_Dedicated; - ubwpd = CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ul_bwp_id-1]->bwp_Dedicated; } else if (CellGroup && CellGroup->spCellConfig && CellGroup->spCellConfig->spCellConfigDedicated) { // this is an initialBWP AssertFatal((bwpd=CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP)!=NULL, "CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP is null\n"); - AssertFatal((ubwpd=CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP)!=NULL, - "CellGroup->spCellConfig->spCellConfigDedicated->uplnikConfig->initialUplinkBWP is null\n"); } NR_SearchSpace_t *ss=NULL; @@ -2714,10 +2704,11 @@ void get_pdsch_to_harq_feedback(NR_UE_info_t *UE, } } else { - AssertFatal(ubwpd!=NULL,"ubwpd shouldn't be null here\n"); - if(ubwpd->pucch_Config->choice.setup->dl_DataToUL_ACK != NULL) { + NR_PUCCH_Config_t *pucch_Config = UE->current_UL_BWP.pucch_Config; + AssertFatal(pucch_Config!=NULL,"pucch_Config shouldn't be null here\n"); + if(pucch_Config->dl_DataToUL_ACK != NULL) { for (int i=0; i<8; i++) { - pdsch_to_harq_feedback[i] = *ubwpd->pucch_Config->choice.setup->dl_DataToUL_ACK->list.array[i]; + pdsch_to_harq_feedback[i] = *pucch_Config->dl_DataToUL_ACK->list.array[i]; if(pdsch_to_harq_feedback[i]>*max_fb_time) *max_fb_time = pdsch_to_harq_feedback[i]; } @@ -2981,28 +2972,10 @@ void nr_mac_update_timers(module_id_t module_id, create_dl_harq_list(sched_ctrl, pdsch); } - // If needed, update the Dedicated BWP - if (spCellConfigDedicated->uplinkConfig && - spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList) { - sched_ctrl->active_ubwp = spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[*spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id - 1]; - if (*spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id != UE->current_UL_BWP.bwp_id) { - LOG_I(NR_MAC, "Changing to UL-BWP %li\n", sched_ctrl->active_ubwp->bwp_Id); - } - } - configure_UE_BWP(RC.nrmac[module_id], scc, sched_ctrl, NULL, UE); // Update coreset/searchspace - sched_ctrl->maxL = 2; - if (cg && - cg->spCellConfig && - cg->spCellConfig->spCellConfigDedicated && - cg->spCellConfig->spCellConfigDedicated->csi_MeasConfig && - cg->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup) { - compute_csi_bitlen (cg->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup, UE); - } - NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; const uint8_t layers = set_dl_nrOfLayers(sched_ctrl); const int tda = get_dl_tda(RC.nrmac[module_id], scc, slot); @@ -3015,28 +2988,14 @@ void nr_mac_update_timers(module_id_t module_id, sched_ctrl, ps); - NR_BWP_Uplink_t *ubwp = sched_ctrl->active_ubwp; - NR_BWP_UplinkDedicated_t *ubwpd = NULL; - if (ubwp) { - ubwpd = sched_ctrl->active_ubwp->bwp_Dedicated; - } else if (cg && - cg->spCellConfig && - cg->spCellConfig->spCellConfigDedicated && - (cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP)) { - ubwpd = cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; - } NR_pusch_semi_static_t *ups = &sched_ctrl->pusch_semi_static; - const uint8_t num_dmrs_cdm_grps_no_data = (ubwp || ubwpd) ? 1 : 2; const uint8_t nrOfLayers = 1; const int utda = get_ul_tda(RC.nrmac[module_id], scc, slot); nr_set_pusch_semi_static(&UE->current_UL_BWP, scc, - ubwp, - ubwpd, utda, - num_dmrs_cdm_grps_no_data, nrOfLayers, ups); } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 559b3cb988..2065dff90a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -80,21 +80,13 @@ static void nr_fill_nfapi_pucch(gNB_MAC_INST *nrmac, pucch->resource_indicator); NR_COMMON_channels_t * common_ch=nrmac->common_channels; NR_ServingCellConfigCommon_t *scc = common_ch->ServingCellConfigCommon; - NR_CellGroupConfig_t *cg=UE->CellGroup; - NR_BWP_UplinkDedicated_t *ubwpd = cg && cg->spCellConfig && cg->spCellConfig->spCellConfigDedicated && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? - cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; + LOG_D(NR_MAC,"%4d.%2d Calling nr_configure_pucch (pucch_Config %p,r_pucch %d) pucch to be scheduled in %4d.%2d\n", + frame,slot,UE->current_UL_BWP.pucch_Config,pucch->r_pucch,pucch->frame,pucch->ul_slot); - LOG_D(NR_MAC,"%4d.%2d Calling nr_configure_pucch (ubwpd %p,r_pucch %d) pucch to be scheduled in %4d.%2d\n", - frame,slot,ubwpd,pucch->r_pucch,pucch->frame,pucch->ul_slot); - - const NR_SIB1_t *sib1 = common_ch->sib1 ? common_ch->sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - nr_configure_pucch(sib1, - pucch_pdu, + nr_configure_pucch(pucch_pdu, scc, UE, - ubwpd, pucch->resource_indicator, pucch->csi_bits, pucch->dai_c, @@ -708,17 +700,7 @@ void nr_csi_meas_reporting(int Mod_idP, const NR_CSI_MeasConfig_t *csi_measconfig = CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup; AssertFatal(csi_measconfig->csi_ReportConfigToAddModList->list.count > 0, "NO CSI report configuration available"); - NR_PUCCH_Config_t *pucch_Config = NULL; - if (sched_ctrl->active_ubwp) { - pucch_Config = sched_ctrl->active_ubwp->bwp_Dedicated->pucch_Config->choice.setup; - } else if (CellGroup && - CellGroup->spCellConfig && - CellGroup->spCellConfig->spCellConfigDedicated && - CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig && - CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP && - CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pucch_Config->choice.setup) { - pucch_Config = CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pucch_Config->choice.setup; - } + NR_PUCCH_Config_t *pucch_Config = UL_BWP->pucch_Config; for (int csi_report_id = 0; csi_report_id < csi_measconfig->csi_ReportConfigToAddModList->list.count; csi_report_id++){ NR_CSI_ReportConfig_t *csirep = csi_measconfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; @@ -1617,18 +1599,7 @@ int nr_acknack_scheduling(int mod_id, * later) * * each UE has dedicated PUCCH Format 0 resources, and we use index 0! */ NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_CellGroupConfig_t *cg = UE->CellGroup; - - NR_PUCCH_Config_t *pucch_Config = NULL; - if (sched_ctrl->active_ubwp) { - pucch_Config = sched_ctrl->active_ubwp->bwp_Dedicated->pucch_Config->choice.setup; - } else if (cg && - cg->spCellConfig && - cg->spCellConfig->spCellConfigDedicated && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { - pucch_Config = cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pucch_Config->choice.setup; - } + NR_PUCCH_Config_t *pucch_Config = BWP->pucch_Config; int bwp_start = BWP->BWPStart; int bwp_size = BWP->BWPSize; @@ -1881,21 +1852,10 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, sub_frame_t slot) NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; const int n_slots_frame = nr_slots_per_frame[BWP->scs]; if (sched_ctrl->ul_failure==1) continue; - NR_PUCCH_Config_t *pucch_Config = NULL; - if (sched_ctrl->active_ubwp) { - pucch_Config = sched_ctrl->active_ubwp->bwp_Dedicated->pucch_Config->choice.setup; - } else if (UE->CellGroup && - UE->CellGroup->spCellConfig && - UE->CellGroup->spCellConfig->spCellConfigDedicated && - UE->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig && - UE->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP && - UE->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pucch_Config->choice.setup) { - pucch_Config = UE->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->pucch_Config->choice.setup; - } + NR_PUCCH_Config_t *pucch_Config = BWP->pucch_Config; - else continue; - if (!pucch_Config->schedulingRequestResourceToAddModList) - continue; + if (!pucch_Config || !pucch_Config->schedulingRequestResourceToAddModList) + continue; AssertFatal(pucch_Config->schedulingRequestResourceToAddModList->list.count>0,"NO SR configuration available"); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index eb23775a24..c3c7529b4e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -822,32 +822,22 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, const int CC_id = 0; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_sched_pusch_t *retInfo = &sched_ctrl->ul_harq_processes[harq_pid].sched_pusch; - NR_CellGroupConfig_t *cg = UE->CellGroup; - - NR_BWP_UplinkDedicated_t *ubwpd = cg && cg->spCellConfig && cg->spCellConfig->spCellConfigDedicated && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? - cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; int rbStart = 0; // wrt BWP start const uint16_t bwpSize = UE->current_UL_BWP.BWPSize; const uint8_t nrOfLayers = 1; - const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_ubwp || ubwpd) ? 1 : 2; LOG_D(NR_MAC,"retInfo->time_domain_allocation = %d, tda = %d\n", retInfo->time_domain_allocation, tda); - LOG_D(NR_MAC,"num_dmrs_cdm_grps_no_data %d, tbs %d\n",num_dmrs_cdm_grps_no_data, retInfo->tb_size); + LOG_D(NR_MAC,"tbs %d\n",retInfo->tb_size); if (tda == retInfo->time_domain_allocation) { /* check whether we need to switch the TDA allocation since tha last * (re-)transmission */ NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; if (ps->time_domain_allocation != tda - || ps->nrOfLayers != nrOfLayers - || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) { + || ps->nrOfLayers != nrOfLayers) { nr_set_pusch_semi_static(&UE->current_UL_BWP, scc, - sched_ctrl->active_ubwp, - ubwpd, tda, - num_dmrs_cdm_grps_no_data, nrOfLayers, ps); } @@ -865,10 +855,7 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, NR_pusch_semi_static_t temp_ps; nr_set_pusch_semi_static(&UE->current_UL_BWP, scc, - sched_ctrl->active_ubwp, - ubwpd, tda, - num_dmrs_cdm_grps_no_data, nrOfLayers, &temp_ps); /* the retransmission will use a different time domain allocation, check @@ -1016,10 +1003,6 @@ void pf_ul(module_id_t module_id, NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; int rbStart = 0; // wrt BWP start - NR_CellGroupConfig_t *cg = UE->CellGroup; - NR_BWP_UplinkDedicated_t *ubwpd = cg && cg->spCellConfig && cg->spCellConfig->spCellConfigDedicated && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? - cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; const uint16_t bwpSize = BWP->BWPSize; NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; @@ -1106,17 +1089,12 @@ void pf_ul(module_id_t module_id, * every TTI if we can save it, so check whether TDA, or * num_dmrs_cdm_grps_no_data has changed and only then recompute */ const uint8_t nrOfLayers = 1; - const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_ubwp || ubwpd) ? 1 : 2; const int tda = get_ul_tda(nrmac, scc, sched_pusch->slot); if (ps->time_domain_allocation != tda - || ps->nrOfLayers != nrOfLayers - || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) { + || ps->nrOfLayers != nrOfLayers) { nr_set_pusch_semi_static(BWP, scc, - sched_ctrl->active_ubwp, - ubwpd, tda, - num_dmrs_cdm_grps_no_data, nrOfLayers, ps); } @@ -1209,13 +1187,7 @@ void pf_ul(module_id_t module_id, else LOG_D(NR_MAC, "%4d.%2d free CCE for UL DCI UE %04x\n",frame,slot, iterator->UE->rnti); NR_UE_UL_BWP_t *BWP = &iterator->UE->current_UL_BWP; - NR_CellGroupConfig_t *cg = iterator->UE->CellGroup; - NR_BWP_UplinkDedicated_t *ubwpd = cg && cg->spCellConfig && cg->spCellConfig->spCellConfigDedicated - && cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? - cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; - - int rbStart = sched_ctrl->active_ubwp ? BWP->BWPStart : 0; const uint16_t bwpSize = BWP->BWPSize; NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; @@ -1225,22 +1197,18 @@ void pf_ul(module_id_t module_id, * every TTI if we can save it, so check whether TDA, or * num_dmrs_cdm_grps_no_data has changed and only then recompute */ const uint8_t nrOfLayers = 1; - const uint8_t num_dmrs_cdm_grps_no_data = (sched_ctrl->active_ubwp || ubwpd) ? 1 : 2; const int tda = get_ul_tda(nrmac, scc, sched_pusch->slot); if (ps->time_domain_allocation != tda - || ps->nrOfLayers != nrOfLayers - || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) { + || ps->nrOfLayers != nrOfLayers) { nr_set_pusch_semi_static(BWP, scc, - sched_ctrl->active_ubwp, - ubwpd, tda, - num_dmrs_cdm_grps_no_data, nrOfLayers, ps); } update_ul_ue_R_Qm(sched_pusch, BWP->pusch_Config, BWP->mcs_table); + int rbStart = 0; const uint16_t slbitmap = SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols); while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap) rbStart++; @@ -1340,7 +1308,7 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t is_xlsch_in_slot(nr_mac->ulsch_slot_bitmap[sched_slot / 64], sched_slot); // FIXME: Avoid mixed slots for initialUplinkBWP - if (sched_ctrl->active_ubwp==NULL && is_mixed_slot) + if (BWP->bwp_id==0 && is_mixed_slot) return false; // Avoid slots with the SRS @@ -1473,10 +1441,6 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) NR_CellGroupConfig_t *cg = UE->CellGroup; NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP; - NR_BWP_UplinkDedicated_t *ubwpd = cg && cg->spCellConfig && cg->spCellConfig->spCellConfigDedicated && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? - cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; - UE->mac_stats.ul.current_bytes = 0; /* dynamic PUSCH values (RB alloc, MCS, hence R, Qm, TBS) that change in @@ -1744,24 +1708,13 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) dci_pdu_rel15_t uldci_payload; memset(&uldci_payload, 0, sizeof(uldci_payload)); - int n_ubwp=1; - if (cg && - cg->spCellConfig && - cg->spCellConfig->spCellConfigDedicated && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList) { - n_ubwp = cg->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count; - } config_uldci(sib1, - sched_ctrl->active_ubwp, - ubwpd, scc, pusch_pdu, &uldci_payload, ps->time_domain_allocation, UE->UE_sched_ctrl.tpc0, - n_ubwp, current_BWP); fill_dci_pdu_rel15(scc, cg, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index bc145b6dd9..3a20147f2b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -134,7 +134,6 @@ int nr_allocate_CCEs(int module_idP, int CC_idP, frame_t frameP, sub_frame_t slo void nr_get_Msg3alloc(module_id_t module_id, int CC_id, NR_ServingCellConfigCommon_t *scc, - NR_BWP_Uplink_t *ubwp, sub_frame_t current_subframe, frame_t current_frame, NR_RA_t *ra, @@ -192,14 +191,11 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, void config_uldci(const NR_SIB1_t *sib1, - const NR_BWP_Uplink_t *ubwp, - const NR_BWP_UplinkDedicated_t *ubwpd, const NR_ServingCellConfigCommon_t *scc, const nfapi_nr_pusch_pdu_t *pusch_pdu, dci_pdu_rel15_t *dci_pdu_rel15, int time_domain_assignment, uint8_t tpc, - int n_ubwp, NR_UE_UL_BWP_t *BWP); void nr_schedule_pucch(gNB_MAC_INST* nrmac, @@ -249,15 +245,12 @@ int nr_is_dci_opportunity(nfapi_nr_search_space_t search_space, */ int nr_get_pucch_resource(NR_ControlResourceSet_t *coreset, - NR_BWP_Uplink_t *bwp, - NR_BWP_UplinkDedicated_t *bwpd, + NR_PUCCH_Config_t *pucch_Config, int CCEIndex); -void nr_configure_pucch(const NR_SIB1_t *sib1, - nfapi_nr_pucch_pdu_t* pucch_pdu, +void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, NR_ServingCellConfigCommon_t *scc, NR_UE_info_t* UE, - NR_BWP_UplinkDedicated_t *bwpd, uint8_t pucch_resource, uint16_t O_csi, uint16_t O_ack, @@ -346,10 +339,7 @@ void nr_set_pdsch_semi_static(const NR_UE_DL_BWP_t *BWP, void nr_set_pusch_semi_static(const NR_UE_UL_BWP_t *BWP, const NR_ServingCellConfigCommon_t *scc, - const NR_BWP_Uplink_t *ubwp, - const NR_BWP_UplinkDedicated_t *ubwpd, int tda, - uint8_t num_dmrs_cdm_grps_no_data, uint8_t nrOfLayers, NR_pusch_semi_static_t *ps); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index ca239ee51e..a8ebde347e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -105,12 +105,15 @@ typedef struct NR_UE_DL_BWP { typedef struct NR_UE_UL_BWP { NR_BWP_Id_t bwp_id; + int n_ul_bwp; int scs; long *cyclicprefix; uint16_t BWPSize; uint16_t BWPStart; NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList; NR_PUSCH_Config_t *pusch_Config; + NR_PUCCH_Config_t *pucch_Config; + NR_PUCCH_ConfigCommon_t *pucch_ConfigCommon; uint8_t transform_precoding; uint8_t mcs_table; nr_dci_format_t dci_format; @@ -581,9 +584,6 @@ typedef struct NR_UE_ul_harq { /*! \brief scheduling control information set through an API */ #define MAX_CSI_REPORTS 48 typedef struct { - /// the currently active BWP in UL - NR_BWP_Uplink_t *active_ubwp; - /// the next active BWP ID in DL NR_BWP_Id_t next_dl_bwp_id; /// the next active BWP ID in UL @@ -598,8 +598,6 @@ typedef struct { /// corresponding to the sched_pusch/sched_pdsch structures below int cce_index; uint8_t aggregation_level; - /// maximum aggregation level for UE, can be used to select level - int maxL; /// PUCCH scheduling information. Array of two: HARQ+SR in the first field, /// CSI in second. This order is important for nr_acknack_scheduling()! NR_sched_pucch_t sched_pucch[2]; From 633370ffc378b4eb4a2ee8d78b2ebf6e77083a89 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 17 Jun 2022 18:50:06 +0200 Subject: [PATCH 140/267] further MAC cleanup with BWPs --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 6 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 2 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 11 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 146 ++++-------------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 10 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 2 +- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 10 +- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 + 8 files changed, 52 insertions(+), 137 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 6e2af05a13..28cc105561 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -844,7 +844,7 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t NR_RNTI_TC, pusch_pdu->bwp_size, UL_BWP->bwp_id, - coresetid, + coreset, nr_mac->cset0_bwp_size); // Mark the corresponding RBs as used @@ -1376,7 +1376,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra NR_RNTI_RA, BWPSize, DL_BWP->bwp_id, - coresetid, + coreset, nr_mac->cset0_bwp_size); // DL TX request @@ -1770,7 +1770,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra NR_RNTI_TC, pdsch_pdu_rel15->BWPSize, DL_BWP->bwp_id, - coresetid, + coreset, nr_mac->cset0_bwp_size); // Add padding header and zero rest out if there is space left diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index a06c3f06ed..1cda0f4898 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -553,7 +553,7 @@ void nr_fill_nfapi_dl_sib1_pdu(int Mod_idP, rnti_type, pdsch_pdu_rel15->BWPSize, 0, - 0, + gNB_mac->sched_ctrlCommon->coreset, gNB_mac->cset0_bwp_size); LOG_D(MAC,"BWPSize: %i\n", pdcch_pdu_rel15->BWPSize); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 079bc3da40..cb26b1da9a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -948,8 +948,6 @@ void nr_schedule_ue_spec(module_id_t module_id, sched_pdsch->pucch_allocation, sched_ctrl->tpc1); - NR_SearchSpace_t *ss = sched_ctrl->search_space; - const int bwp_id = current_BWP->bwp_id; const int coresetid = sched_ctrl->coreset->controlResourceSetId; @@ -1037,7 +1035,7 @@ void nr_schedule_ue_spec(module_id_t module_id, csi_report->codebook_mode); } // TBS_LBRM according to section 5.4.2.1 of 38.212 - long *maxMIMO_Layers = cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers; + long *maxMIMO_Layers = current_BWP->pdsch_servingcellconfig->ext1->maxMIMO_Layers; AssertFatal (maxMIMO_Layers != NULL,"Option with max MIMO layers not configured is not supported\n"); int nl_tbslbrm = *maxMIMO_Layers < 4 ? *maxMIMO_Layers : 4; // Maximum number of PRBs across all configured DL BWPs @@ -1134,20 +1132,17 @@ void nr_schedule_ue_spec(module_id_t module_id, dci_payload.tpc, pucch->timing_indicator); - int dci_format = ss && ss->searchSpaceType && ss->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific ? - NR_DL_DCI_FORMAT_1_1 : NR_DL_DCI_FORMAT_1_0; - const int rnti_type = NR_RNTI_C; fill_dci_pdu_rel15(scc, cg, current_BWP, dci_pdu, &dci_payload, - dci_format, + current_BWP->dci_format, rnti_type, pdsch_pdu->BWPSize, bwp_id, - coresetid, + sched_ctrl->coreset, gNB_mac->cset0_bwp_size); LOG_D(NR_MAC, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index ab17aebc6e..492abdc200 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -556,17 +556,7 @@ void nr_set_pdsch_semi_static(const NR_UE_DL_BWP_t *BWP, const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength; SLIV2SL(startSymbolAndLength, &ps->startSymbolIndex, &ps->nrOfSymbols); - const long f = sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific ? - sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats : 0; - - int dci_format; - if (sched_ctrl->search_space) { - dci_format = f ? NR_DL_DCI_FORMAT_1_1 : NR_DL_DCI_FORMAT_1_0; - } - else { - dci_format = NR_DL_DCI_FORMAT_1_0; - } - if (dci_format == NR_DL_DCI_FORMAT_1_0) { + if (BWP->dci_format == NR_DL_DCI_FORMAT_1_0) { if (ps->nrOfSymbols == 2) ps->numDmrsCdmGrpsNoData = 1; else @@ -1314,23 +1304,12 @@ void set_r_pucch_parms(int rsetindex, void prepare_dci(const NR_CellGroupConfig_t *CellGroup, const NR_UE_DL_BWP_t *BWP, + const NR_ControlResourceSet_t *coreset, dci_pdu_rel15_t *dci_pdu_rel15, - nr_dci_format_t format, - int bwp_id) { + nr_dci_format_t format) { AssertFatal(CellGroup!=NULL,"CellGroup shouldn't be null here\n"); - const NR_PDCCH_Config_t *pdcch_Config = NULL; - - const NR_BWP_DownlinkDedicated_t *bwpd = NULL; - if (bwp_id>0) { - bwpd=CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Dedicated; - } - else { - bwpd=CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP; - } - pdcch_Config = (bwpd->pdcch_Config) ? bwpd->pdcch_Config->choice.setup : NULL; - const NR_PDSCH_Config_t *pdsch_Config = BWP ? BWP->pdsch_Config : NULL; switch(format) { @@ -1369,7 +1348,7 @@ void prepare_dci(const NR_CellGroupConfig_t *CellGroup, if (pdsch_Config->aperiodic_ZP_CSI_RS_ResourceSetsToAddModList != NULL) AssertFatal(1==0,"Aperiodic ZP CSI-RS currently not supported\n"); // transmission configuration indication - if (pdcch_Config->controlResourceSetToAddModList->list.array[0]->tci_PresentInDCI != NULL) + if (coreset->tci_PresentInDCI != NULL) AssertFatal(1==0,"TCI in DCI currently not supported\n"); //srs resource set if (CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->carrierSwitching!=NULL) { @@ -1393,9 +1372,8 @@ void prepare_dci(const NR_CellGroupConfig_t *CellGroup, else dci_pdu_rel15->srs_request.val = 0; // CBGTI and CBGFI - if (CellGroup->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig && - CellGroup->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup && - CellGroup->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup->codeBlockGroupTransmission != NULL) + if (BWP->pdsch_servingcellconfig && + BWP->pdsch_servingcellconfig->codeBlockGroupTransmission != NULL) AssertFatal(1==0,"CBG transmission currently not supported\n"); break; default : @@ -1413,12 +1391,13 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, int rnti_type, int N_RB, int bwp_id, - NR_ControlResourceSetId_t coreset_id, + NR_ControlResourceSet_t *coreset, uint16_t cset0_bwp_size) { uint8_t fsize = 0, pos = 0; uint64_t *dci_pdu = (uint64_t *)pdcch_dci_pdu->Payload; *dci_pdu=0; + NR_ControlResourceSetId_t coreset_id = coreset->controlResourceSetId; int dci_size = nr_dci_size(scc->downlinkConfigCommon->initialDownlinkBWP, scc->uplinkConfigCommon->initialUplinkBWP, CellGroup, dci_pdu_rel15, dci_format, @@ -1426,7 +1405,7 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, pdcch_dci_pdu->PayloadSizeBits = dci_size; AssertFatal(dci_size <= 64, "DCI sizes above 64 bits not yet supported"); if (dci_format == NR_DL_DCI_FORMAT_1_1 || dci_format == NR_UL_DCI_FORMAT_0_1) - prepare_dci(CellGroup, BWP, dci_pdu_rel15, dci_format, bwp_id); + prepare_dci(CellGroup, BWP, coreset, dci_pdu_rel15, dci_format); /// Payload generation switch (dci_format) { @@ -2268,6 +2247,7 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, CellGroup->spCellConfig->spCellConfigDedicated) { const NR_ServingCellConfig_t *servingCellConfig = CellGroup->spCellConfig->spCellConfigDedicated; + DL_BWP->pdsch_servingcellconfig = servingCellConfig->pdsch_ServingCellConfig? servingCellConfig->pdsch_ServingCellConfig->choice.setup : NULL; csi_MeasConfig = servingCellConfig->csi_MeasConfig ? servingCellConfig->csi_MeasConfig->choice.setup : NULL; target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; @@ -2401,6 +2381,12 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, &dl_genericParameters, nr_mac->type0_PDCCH_CSS_config); + // set DL DCI format + DL_BWP->dci_format = (sched_ctrl->search_space->searchSpaceType && + sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific) ? + (sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats == NR_SearchSpace__searchSpaceType__ue_Specific__dci_Formats_formats0_1_And_1_1 ? + NR_DL_DCI_FORMAT_1_1 : NR_DL_DCI_FORMAT_1_0) : + NR_DL_DCI_FORMAT_1_0; // set UL DCI format UL_BWP->dci_format = (sched_ctrl->search_space->searchSpaceType && sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific) ? @@ -2441,6 +2427,7 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, &nr_mac->type0_PDCCH_CSS_config[ra->beam_id]); UL_BWP->dci_format = NR_UL_DCI_FORMAT_0_0; + DL_BWP->dci_format = NR_DL_DCI_FORMAT_1_0; } // Set uplink MCS table @@ -2508,25 +2495,17 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf /* set illegal time domain allocation to force recomputation of all fields */ sched_ctrl->pdsch_semi_static.time_domain_allocation = -1; sched_ctrl->pusch_semi_static.time_domain_allocation = -1; - const NR_ServingCellConfig_t *servingCellConfig = CellGroup && CellGroup->spCellConfig ? CellGroup->spCellConfig->spCellConfigDedicated : NULL; /* Set default BWPs */ sched_ctrl->next_dl_bwp_id = -1; sched_ctrl->next_ul_bwp_id = -1; - const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig ? servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList : NULL; - if (ubwpList) - AssertFatal(ubwpList->list.count <= NR_MAX_NUM_BWP, - "uplinkBWP_ToAddModList has %d BWP!\n", - ubwpList->list.count); + AssertFatal(UL_BWP->n_ul_bwp <= NR_MAX_NUM_BWP, + "uplinkBWP_ToAddModList has %d BWP!\n", + UL_BWP->n_ul_bwp); /* get Number of HARQ processes for this UE */ - if (servingCellConfig) - AssertFatal(servingCellConfig->pdsch_ServingCellConfig->present == NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup, - "no pdsch-ServingCellConfig found for UE %04x\n", - UE->rnti); - const NR_PDSCH_ServingCellConfig_t *pdsch = servingCellConfig ? servingCellConfig->pdsch_ServingCellConfig->choice.setup : NULL; - // pdsch == NULL in SA -> will create default (8) number of HARQ processes - create_dl_harq_list(sched_ctrl, pdsch); + // pdsch_servingcellconfig == NULL in SA -> will create default (8) number of HARQ processes + create_dl_harq_list(sched_ctrl, DL_BWP->pdsch_servingcellconfig); // add all available UL HARQ processes for this UE // nb of ul harq processes not configurable create_nr_list(&sched_ctrl->available_ul_harq, 16); @@ -2635,43 +2614,12 @@ uint8_t nr_get_tpc(int target, uint8_t cqi, int incr) { } -void get_pdsch_to_harq_feedback(NR_UE_info_t *UE, - NR_SearchSpace__searchSpaceType_PR ss_type, +void get_pdsch_to_harq_feedback(NR_PUCCH_Config_t *pucch_Config, + nr_dci_format_t dci_format, int *max_fb_time, uint8_t *pdsch_to_harq_feedback) { - NR_CellGroupConfig_t *CellGroup = UE->CellGroup; - NR_BWP_DownlinkDedicated_t *bwpd=NULL; - int dl_bwp_id = UE->current_DL_BWP.bwp_id; - int ul_bwp_id = UE->current_UL_BWP.bwp_id; - - if (ss_type == NR_SearchSpace__searchSpaceType_PR_ue_Specific) { - AssertFatal(CellGroup!=NULL,"Cellgroup is not defined for UE %04x\n",UE->rnti); - AssertFatal(CellGroup->spCellConfig!=NULL,"Cellgroup->spCellConfig is null\n"); - AssertFatal(CellGroup->spCellConfig->spCellConfigDedicated!=NULL,"CellGroup->spCellConfig->spCellConfigDedicated is null\n"); - } - if (dl_bwp_id>0 && ul_bwp_id>0) { - AssertFatal(CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList!=NULL, - "CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList is null\n"); - AssertFatal(CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList!=NULL, - "CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList is null\n"); - AssertFatal(CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count >= dl_bwp_id, - "CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count %d < bwp_id %d\n", - CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count,dl_bwp_id); - AssertFatal(CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count >= ul_bwp_id, - "CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count %d < bwp_id %d\n", - CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count,ul_bwp_id); - - bwpd = CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[dl_bwp_id-1]->bwp_Dedicated; - } - else if (CellGroup && CellGroup->spCellConfig && CellGroup->spCellConfig->spCellConfigDedicated) { // this is an initialBWP - AssertFatal((bwpd=CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP)!=NULL, - "CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP is null\n"); - } - NR_SearchSpace_t *ss=NULL; - - // common search type uses DCI format 1_0 - if (ss_type == NR_SearchSpace__searchSpaceType_PR_common) { + if (dci_format == NR_DL_DCI_FORMAT_1_0) { for (int i=0; i<8; i++) { pdsch_to_harq_feedback[i] = i+1; if(pdsch_to_harq_feedback[i]>*max_fb_time) @@ -2679,43 +2627,16 @@ void get_pdsch_to_harq_feedback(NR_UE_info_t *UE, } } else { - - // searching for a ue specific search space - int found=0; - AssertFatal(bwpd->pdcch_Config!=NULL,"bwpd->pdcch_Config is null\n"); - AssertFatal(bwpd->pdcch_Config->choice.setup->searchSpacesToAddModList!=NULL, - "bwpd->pdcch_Config->choice.setup->searchSpacesToAddModList is null\n"); - for (int i=0;ipdcch_Config->choice.setup->searchSpacesToAddModList->list.count;i++) { - ss=bwpd->pdcch_Config->choice.setup->searchSpacesToAddModList->list.array[i]; - AssertFatal(ss->controlResourceSetId != NULL,"ss->controlResourceSetId is null\n"); - AssertFatal(ss->searchSpaceType != NULL,"ss->searchSpaceType is null\n"); - if (ss->searchSpaceType->present == ss_type) { - found=1; - break; - } - } - AssertFatal(found==1,"Couldn't find a ue specific searchspace\n"); - - if (ss->searchSpaceType->choice.ue_Specific->dci_Formats == NR_SearchSpace__searchSpaceType__ue_Specific__dci_Formats_formats0_0_And_1_0) { + AssertFatal(pucch_Config!=NULL,"pucch_Config shouldn't be null here\n"); + if(pucch_Config->dl_DataToUL_ACK != NULL) { for (int i=0; i<8; i++) { - pdsch_to_harq_feedback[i] = i+1; + pdsch_to_harq_feedback[i] = *pucch_Config->dl_DataToUL_ACK->list.array[i]; if(pdsch_to_harq_feedback[i]>*max_fb_time) *max_fb_time = pdsch_to_harq_feedback[i]; } } - else { - NR_PUCCH_Config_t *pucch_Config = UE->current_UL_BWP.pucch_Config; - AssertFatal(pucch_Config!=NULL,"pucch_Config shouldn't be null here\n"); - if(pucch_Config->dl_DataToUL_ACK != NULL) { - for (int i=0; i<8; i++) { - pdsch_to_harq_feedback[i] = *pucch_Config->dl_DataToUL_ACK->list.array[i]; - if(pdsch_to_harq_feedback[i]>*max_fb_time) - *max_fb_time = pdsch_to_harq_feedback[i]; - } - } - else - AssertFatal(0==1,"There is no allocated dl_DataToUL_ACK for pdsch to harq feedback\n"); - } + else + AssertFatal(0==1,"There is no allocated dl_DataToUL_ACK for pdsch to harq feedback\n"); } } @@ -2959,21 +2880,18 @@ void nr_mac_update_timers(module_id_t module_id, } NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon; - const NR_ServingCellConfig_t *spCellConfigDedicated = cg && cg->spCellConfig ? cg->spCellConfig->spCellConfigDedicated : NULL; LOG_I(NR_MAC,"Modified rnti %04x with CellGroup\n", UE->rnti); process_CellGroup(cg,&UE->UE_sched_ctrl); NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + configure_UE_BWP(RC.nrmac[module_id], scc, sched_ctrl, NULL, UE); - const NR_PDSCH_ServingCellConfig_t *pdsch = spCellConfigDedicated ? spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup : NULL; if (get_softmodem_params()->sa) { // add all available DL HARQ processes for this UE in SA - create_dl_harq_list(sched_ctrl, pdsch); + create_dl_harq_list(sched_ctrl, UE->current_DL_BWP.pdsch_servingcellconfig); } - configure_UE_BWP(RC.nrmac[module_id], scc, sched_ctrl, NULL, UE); - // Update coreset/searchspace NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 2065dff90a..d4c7a7779d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -1583,7 +1583,7 @@ int nr_acknack_scheduling(int mod_id, const int CC_id = 0; const int minfbtime = RC.nrmac[mod_id]->minRXTXTIMEpdsch; const NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels[CC_id].ServingCellConfigCommon; - NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; + const NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; const int n_slots_frame = nr_slots_per_frame[BWP->scs]; const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; AssertFatal(tdd || RC.nrmac[mod_id]->common_channels[CC_id].frame_type == FDD, "Dynamic TDD not handled yet\n"); @@ -1657,13 +1657,13 @@ int nr_acknack_scheduling(int mod_id, LOG_D(NR_MAC, "In %s: pucch_acknak 1. DL %4d.%2d, UL_ACK %4d.%2d, DAI_C %d\n", __FUNCTION__, frame, slot, pucch->frame, pucch->ul_slot, pucch->dai_c); - NR_SearchSpace__searchSpaceType_PR ss_type = NR_SearchSpace__searchSpaceType_PR_common; + nr_dci_format_t dci_format = NR_DL_DCI_FORMAT_1_0; if(is_common == 0) - ss_type = sched_ctrl->search_space->searchSpaceType->present; + dci_format = UE->current_DL_BWP.dci_format; uint8_t pdsch_to_harq_feedback[8]; int max_fb_time = 0; - get_pdsch_to_harq_feedback(UE, ss_type, &max_fb_time, pdsch_to_harq_feedback); + get_pdsch_to_harq_feedback(pucch_Config, dci_format, &max_fb_time, pdsch_to_harq_feedback); LOG_D(NR_MAC, "In %s: 1b. DL %4d.%2d, UL_ACK %4d.%2d, DAI_C %d\n", __FUNCTION__, frame,slot,pucch->frame,pucch->ul_slot,pucch->dai_c); /* there is a HARQ. Check whether we can use it for this ACKNACK */ @@ -1859,7 +1859,7 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, sub_frame_t slot) AssertFatal(pucch_Config->schedulingRequestResourceToAddModList->list.count>0,"NO SR configuration available"); - for (int SR_resource_id =0; SR_resource_id < pucch_Config->schedulingRequestResourceToAddModList->list.count;SR_resource_id++) { + for (int SR_resource_id = 0; SR_resource_id < pucch_Config->schedulingRequestResourceToAddModList->list.count;SR_resource_id++) { NR_SchedulingRequestResourceConfig_t *SchedulingRequestResourceConfig = pucch_Config->schedulingRequestResourceToAddModList->list.array[SR_resource_id]; int SR_period; int SR_offset; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index c3c7529b4e..30aac48b26 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1725,7 +1725,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) rnti_types[0], pusch_pdu->bwp_size, current_BWP->bwp_id, - coresetid, + coreset, nr_mac->cset0_bwp_size); memset(sched_pusch, 0, sizeof(*sched_pusch)); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 3a20147f2b..5884d6532f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -220,8 +220,8 @@ int nr_acknack_scheduling( int Mod_idP, int r_pucch, int do_common); -void get_pdsch_to_harq_feedback(NR_UE_info_t *UE, - NR_SearchSpace__searchSpaceType_PR ss_type, +void get_pdsch_to_harq_feedback(NR_PUCCH_Config_t *pucch_Config, + nr_dci_format_t dci_format, int *max_fb_time, uint8_t *pdsch_to_harq_feedback); @@ -296,14 +296,14 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, int rnti_types, int N_RB, int bwp_id, - NR_ControlResourceSetId_t coreset_id, + NR_ControlResourceSet_t *coreset, uint16_t cset0_bwp_size); void prepare_dci(const NR_CellGroupConfig_t *CellGroup, const NR_UE_DL_BWP_t *BWP, + const NR_ControlResourceSet_t *coreset, dci_pdu_rel15_t *dci_pdu_rel15, - nr_dci_format_t format, - int bwp_id); + nr_dci_format_t format); void set_r_pucch_parms(int rsetindex, int r_pucch, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index a8ebde347e..7c805e8a90 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -100,7 +100,9 @@ typedef struct NR_UE_DL_BWP { uint16_t BWPStart; NR_PDSCH_TimeDomainResourceAllocationList_t *tdaList; NR_PDSCH_Config_t *pdsch_Config; + NR_PDSCH_ServingCellConfig_t *pdsch_servingcellconfig; uint8_t mcsTableIdx; + nr_dci_format_t dci_format; } NR_UE_DL_BWP_t; typedef struct NR_UE_UL_BWP { From 504ce6d793802208e7f3e51ba7b76ec721509fb2 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Sun, 19 Jun 2022 02:13:33 +0100 Subject: [PATCH 141/267] Fix after merge --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 2c7ec7efa4..34258c737c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -3002,7 +3002,7 @@ void nr_mac_update_timers(module_id_t module_id, cg->spCellConfig->spCellConfigDedicated && cg->spCellConfig->spCellConfigDedicated->csi_MeasConfig && cg->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup) { - compute_csi_bitlen (cg->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup, UE); + compute_csi_bitlen (cg->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup, UE->csi_report_template); } NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; From 2b38c78588cb21d9f8fcb2688fc60d0709c5f27e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Sun, 12 Jun 2022 16:52:01 +0200 Subject: [PATCH 142/267] Add fedora36 to supported distros --- cmake_targets/tools/build_helper | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index 179e2de428..525edfe5fc 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -109,6 +109,7 @@ check_supported_distribution() { "ubuntu18.04") return 0 ;; "ubuntu16.04") return 0 ;; "fedora35") return 0 ;; + "fedora36") return 0 ;; "rhel7") return 0 ;; "rhel7.6") return 0 ;; "rhel7.7") return 0 ;; From dab905519be98c92061a32ccb0f9203becc2b1c2 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Sun, 12 Jun 2022 17:11:36 +0200 Subject: [PATCH 143/267] Remove nscd from additional packages nscd (Name service cache daemon) is not needed for running OAI --- cmake_targets/tools/build_helper | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index 525edfe5fc..95f237ab33 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -624,7 +624,6 @@ check_install_additional_tools (){ android-tools-adb \ wvdial \ sshpass \ - nscd \ bc \ ntp" elif [[ "$OS_DISTRO" == "rhel" ]] || [[ "$OS_DISTRO" == "centos" ]]; then @@ -649,7 +648,6 @@ check_install_additional_tools (){ wvdial \ numpy \ sshpass \ - nscd \ python2-paramiko \ python-pyroute2 \ python-netifaces \ @@ -677,7 +675,6 @@ check_install_additional_tools (){ wvdial \ python-numpy \ sshpass \ - nscd \ python-paramiko \ python-pyroute2 \ python-netifaces \ From 4f44a1026b69b106a0fc48095c403f73f4d99de7 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Sun, 19 Jun 2022 18:01:58 +0200 Subject: [PATCH 144/267] Remove RHEL_RELEASE_CODE define --- openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c | 9 ++------- openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c | 5 ----- openair2/NETWORK_DRIVER/MESH/device.c | 6 +++--- openair2/NETWORK_DRIVER/UE_IP/device.c | 8 ++------ 4 files changed, 7 insertions(+), 21 deletions(-) diff --git a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c index 0b665737a7..fb7c920a1e 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c @@ -41,13 +41,8 @@ #include #include #include -#if RHEL_RELEASE_CODE >= 1796 - #include - #include -#else - #include - #include -#endif +#include +#include #include #include "linear_preprocessing_rec.h" diff --git a/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c b/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c index 7d063e326e..59da43e564 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c @@ -14,13 +14,8 @@ data storage. */ #include #include #include -#if RHEL_RELEASE_CODE >= 1796 -#include -#include -#else #include #include -#endif //#define DEBUG_PREPROC diff --git a/openair2/NETWORK_DRIVER/MESH/device.c b/openair2/NETWORK_DRIVER/MESH/device.c index f63408259c..c1b5401011 100644 --- a/openair2/NETWORK_DRIVER/MESH/device.c +++ b/openair2/NETWORK_DRIVER/MESH/device.c @@ -198,7 +198,7 @@ int nas_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) // End debug information netif_stop_queue(dev); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE>=1796) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) netif_trans_update(dev); #else dev->trans_start = jiffies; @@ -267,7 +267,7 @@ void nas_tx_timeout(struct net_device *dev) printk("TX_TIMEOUT: begin\n"); // (struct nas_priv *)(dev->priv)->stats.tx_errors++; (priv->stats).tx_errors++; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE>=1796) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) netif_trans_update(dev); #else dev->trans_start = jiffies; @@ -285,7 +285,7 @@ static const struct net_device_ops nasmesh_netdev_ops = { .ndo_set_mac_address = NULL, .ndo_set_config = nas_set_config, .ndo_do_ioctl = nas_CTL_ioctl, -#if (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE>=1797 && LINUX_VERSION_CODE <= KERNEL_VERSION(3,11,0)) +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,11,0) .extended.ndo_change_mtu = nas_change_mtu, #else .ndo_change_mtu = nas_change_mtu, diff --git a/openair2/NETWORK_DRIVER/UE_IP/device.c b/openair2/NETWORK_DRIVER/UE_IP/device.c index 0ff9a73925..fa762d1ba9 100644 --- a/openair2/NETWORK_DRIVER/UE_IP/device.c +++ b/openair2/NETWORK_DRIVER/UE_IP/device.c @@ -239,7 +239,7 @@ int ue_ip_hard_start_xmit(struct sk_buff *skb_pP, struct net_device *dev_pP) { // End debug information netif_stop_queue(dev_pP); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= 1796) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) netif_trans_update(dev_pP); #else dev_pP->trans_start = jiffies; @@ -315,7 +315,7 @@ void ue_ip_tx_timeout(struct net_device *dev_pP) printk("[UE_IP_DRV][%s] begin\n", __FUNCTION__); // (ue_ip_priv_t *)(dev_pP->priv_p)->stats.tx_errors++; (priv_p->stats).tx_errors++; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= 1796) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) netif_trans_update(dev_pP); #else dev_pP->trans_start = jiffies; @@ -333,11 +333,7 @@ static const struct net_device_ops ue_ip_netdev_ops = { .ndo_set_mac_address = ue_ip_set_mac_address, .ndo_set_config = ue_ip_set_config, .ndo_do_ioctl = NULL, -#if (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= 1797) - .extended.ndo_change_mtu = ue_ip_change_mtu, -#else .ndo_change_mtu = ue_ip_change_mtu, -#endif .ndo_tx_timeout = ue_ip_tx_timeout, .ndo_change_rx_flags = ue_ip_change_rx_flags, }; From 2bed0352fd7330eddafb480cb258b81716b19faf Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Sun, 19 Jun 2022 18:33:57 +0200 Subject: [PATCH 145/267] f1: remove hardcoded value, set to what is in develop --- openair2/F1AP/f1ap_du_task.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openair2/F1AP/f1ap_du_task.c b/openair2/F1AP/f1ap_du_task.c index 4982f7617b..5212e325b3 100644 --- a/openair2/F1AP/f1ap_du_task.c +++ b/openair2/F1AP/f1ap_du_task.c @@ -126,7 +126,8 @@ void *F1AP_DU_task(void *arg) { LOG_I(F1AP, "DU Task Received F1AP_SETUP_REQ\n"); f1ap_setup_req_t *msgSetup=&F1AP_SETUP_REQ(msg); createF1inst(false, myInstance, msgSetup); - getCxt(DUtype, myInstance)->gtpInst=du_create_gtpu_instance_to_cu("172.21.10.9",//"172.21.9.5", //msgSetup->CU_f1_ip_address.ipv4_address, //"192.168.18.91" +printf("XXXXXXXXXXXXXXX old 172.21.6.9 new %s\n", msgSetup->CU_f1_ip_address.ipv4_address); + getCxt(DUtype, myInstance)->gtpInst=du_create_gtpu_instance_to_cu(msgSetup->CU_f1_ip_address.ipv4_address, //"172.21.6.9", //"172.21.10.9",//"172.21.9.5", //msgSetup->CU_f1_ip_address.ipv4_address, //"192.168.18.91" msgSetup->CUport, msgSetup->DU_f1_ip_address.ipv4_address, msgSetup->DUport); From 2124e43d3afca4440b5d5db90fe9f2079d898acf Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 20 Jun 2022 11:04:03 +0200 Subject: [PATCH 146/267] Correctly use RHEL_RELEASE_CODE for Fedora and RHEL This reverts commit 4f44a1026b69b106a0fc48095c403f73f4d99de7. --- openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c | 10 ++++++++-- .../PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c | 6 ++++++ openair2/NETWORK_DRIVER/MESH/device.c | 12 +++++++++--- openair2/NETWORK_DRIVER/UE_IP/device.c | 13 +++++++++++-- 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c index fb7c920a1e..4ad27fcfbe 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c @@ -41,8 +41,14 @@ #include #include #include -#include -#include +#if defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4) \ + && RHEL_RELEASE_CODE != RHEL_RELEASE_VERSION(9,99) + #include + #include +#else + #include + #include +#endif #include #include "linear_preprocessing_rec.h" diff --git a/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c b/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c index 59da43e564..265e88dc39 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c @@ -14,8 +14,14 @@ data storage. */ #include #include #include +#if defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4) \ + && RHEL_RELEASE_CODE != RHEL_RELEASE_VERSION(9,99) +#include +#include +#else #include #include +#endif //#define DEBUG_PREPROC diff --git a/openair2/NETWORK_DRIVER/MESH/device.c b/openair2/NETWORK_DRIVER/MESH/device.c index c1b5401011..08e1577cea 100644 --- a/openair2/NETWORK_DRIVER/MESH/device.c +++ b/openair2/NETWORK_DRIVER/MESH/device.c @@ -198,7 +198,9 @@ int nas_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) // End debug information netif_stop_queue(dev); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) \ + || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4) \ + && RHEL_RELEASE_CODE != RHEL_RELEASE_VERSION(9,99)) netif_trans_update(dev); #else dev->trans_start = jiffies; @@ -267,7 +269,9 @@ void nas_tx_timeout(struct net_device *dev) printk("TX_TIMEOUT: begin\n"); // (struct nas_priv *)(dev->priv)->stats.tx_errors++; (priv->stats).tx_errors++; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) \ + || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4) \ + && RHEL_RELEASE_CODE != RHEL_RELEASE_VERSION(9,99)) netif_trans_update(dev); #else dev->trans_start = jiffies; @@ -285,7 +289,9 @@ static const struct net_device_ops nasmesh_netdev_ops = { .ndo_set_mac_address = NULL, .ndo_set_config = nas_set_config, .ndo_do_ioctl = nas_CTL_ioctl, -#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,11,0) +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,11,0) \ + || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5) \ + && RHEL_RELEASE_CODE != RHEL_RELEASE_VERSION(9,99)) .extended.ndo_change_mtu = nas_change_mtu, #else .ndo_change_mtu = nas_change_mtu, diff --git a/openair2/NETWORK_DRIVER/UE_IP/device.c b/openair2/NETWORK_DRIVER/UE_IP/device.c index fa762d1ba9..d124be07ae 100644 --- a/openair2/NETWORK_DRIVER/UE_IP/device.c +++ b/openair2/NETWORK_DRIVER/UE_IP/device.c @@ -239,7 +239,9 @@ int ue_ip_hard_start_xmit(struct sk_buff *skb_pP, struct net_device *dev_pP) { // End debug information netif_stop_queue(dev_pP); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) \ + || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4) \ + && RHEL_RELEASE_CODE != RHEL_RELEASE_VERSION(9,99)) netif_trans_update(dev_pP); #else dev_pP->trans_start = jiffies; @@ -315,7 +317,9 @@ void ue_ip_tx_timeout(struct net_device *dev_pP) printk("[UE_IP_DRV][%s] begin\n", __FUNCTION__); // (ue_ip_priv_t *)(dev_pP->priv_p)->stats.tx_errors++; (priv_p->stats).tx_errors++; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) \\ + || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4) \ + && RHEL_RELEASE_CODE != RHEL_RELEASE_VERSION(9,99)) netif_trans_update(dev_pP); #else dev_pP->trans_start = jiffies; @@ -333,7 +337,12 @@ static const struct net_device_ops ue_ip_netdev_ops = { .ndo_set_mac_address = ue_ip_set_mac_address, .ndo_set_config = ue_ip_set_config, .ndo_do_ioctl = NULL, +#if defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5) \ + && RHEL_RELEASE_CODE != RHEL_RELEASE_VERSION(9,99) + .extended.ndo_change_mtu = ue_ip_change_mtu, +#else .ndo_change_mtu = ue_ip_change_mtu, +#endif .ndo_tx_timeout = ue_ip_tx_timeout, .ndo_change_rx_flags = ue_ip_change_rx_flags, }; From 4e69a10cbc131814b96a3b34c411d904936e2eb5 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 20 Jun 2022 11:41:19 +0200 Subject: [PATCH 147/267] change BWP when Msg3_dcch_dtch --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 18 +++++---------- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 22 +++++++++++++------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 57b7d58ad0..89495139da 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1834,19 +1834,11 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra harq->round = 0; harq->ndi ^= 1; - // Pause scheduling according to: - // 3GPP TS 38.331 Section 12 Table 12.1-1: UE performance requirements for RRC procedures for UEs - const NR_COMMON_channels_t *common_channels = &RC.nrmac[module_idP]->common_channels[0]; - const NR_SIB1_t *sib1 = common_channels->sib1 ? common_channels->sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - const NR_ServingCellConfig_t *servingCellConfig = UE->CellGroup ? UE->CellGroup->spCellConfig->spCellConfigDedicated : NULL; - NR_BWP_t *genericParameters = get_dl_bwp_genericParameters(sched_ctrl->active_bwp, - common_channels->ServingCellConfigCommon, - sib1); - uint32_t delay_ms = servingCellConfig && servingCellConfig->downlinkBWP_ToAddModList ? - NR_RRC_SETUP_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS : NR_RRC_SETUP_DELAY_MS; - - sched_ctrl->rrc_processing_timer = (delay_ms << genericParameters->subcarrierSpacing); - LOG_I(NR_MAC, "(%d.%d) Activating RRC processing timer for UE %04x with %d ms\n", frameP, slotP, UE->rnti, delay_ms); + configure_UE_BWP(nr_mac, + scc, + sched_ctrl, + NULL, + UE); // Reset uplink failure flags/counters/timers at MAC so gNB will resume again scheduling resources for this UE UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt = 0; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index bed24dcc36..c363eac31a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2218,13 +2218,21 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, csi_MeasConfig = servingCellConfig->csi_MeasConfig ? servingCellConfig->csi_MeasConfig->choice.setup : NULL; target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; - // (re)configuring BWP - // TODO BWP switching not via RRC reconfiguration - // via RRC if firstActiveXlinkBWP_Id is NULL, MAC stays on the same BWP as before - if (servingCellConfig->firstActiveDownlinkBWP_Id) - DL_BWP->bwp_id = *servingCellConfig->firstActiveDownlinkBWP_Id; - if (servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id) - UL_BWP->bwp_id = *servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id; + if(UE && UE->Msg3_dcch_dtch) { + // switching to initial BWP + DL_BWP->bwp_id = 0; + UL_BWP->bwp_id = 0; + UE->Msg3_dcch_dtch = false; + } + else { + // (re)configuring BWP + // TODO BWP switching not via RRC reconfiguration + // via RRC if firstActiveXlinkBWP_Id is NULL, MAC stays on the same BWP as before + if (servingCellConfig->firstActiveDownlinkBWP_Id) + DL_BWP->bwp_id = *servingCellConfig->firstActiveDownlinkBWP_Id; + if (servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id) + UL_BWP->bwp_id = *servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id; + } const struct NR_ServingCellConfig__downlinkBWP_ToAddModList *bwpList = servingCellConfig->downlinkBWP_ToAddModList; if(bwpList) From a4e2c2b799485008ace47c44837a6265bcc4832c Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 20 Jun 2022 11:58:06 +0200 Subject: [PATCH 148/267] addressing review --- openair2/LAYER2/NR_MAC_UE/config_ue.c | 2 +- openair2/LAYER2/NR_MAC_gNB/config.c | 6 ++--- openair2/RRC/NR/MESSAGES/asn1_msg.c | 2 +- .../CONF/gnb.band66.tm1.25PRB.usrpn300.conf | 3 --- ....sa.band78.fr1.106PRB.usrpb210.4layer.conf | 27 ++----------------- ...gnb.sa.band78.fr1.217PRB.2x2.usrpn300.conf | 3 +-- ...gnb.sa.band78.fr1.273PRB.2x2.usrpn300.conf | 3 +-- 7 files changed, 8 insertions(+), 38 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 1f1b1ece8d..5ffccf28d3 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -344,7 +344,7 @@ void config_common_ue(NR_UE_MAC_INST_t *mac, cfg->ssb_table.ssb_offset_point_a = absolute_diff/(12*scs_scaling) - 10; cfg->ssb_table.ssb_period = *scc->ssb_periodicityServingCell; - // NSA -> take ssb offset from SSC + // NSA -> take ssb offset from SCS cfg->ssb_table.ssb_subcarrier_offset = absolute_diff%(12*scs_scaling); switch (scc->ssb_PositionsInBurst->present) { diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 0e3bce7f24..2fd3357b53 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -343,14 +343,12 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, int pusch_AntennaPorts, uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); RC.nrmac[Mod_idP]->ssb_SubcarrierOffset = absolute_diff%(12*scs_scaling); - int sco; + int sco = 31; // no SIB1 if(get_softmodem_params()->sa) { sco = RC.nrmac[Mod_idP]->ssb_SubcarrierOffset; if(frequency_range == FR1) - sco = sco<ssb_config.scs_common.value; + sco <<= cfg->ssb_config.scs_common.value; // 38.211 section 7.4.3.1 in FR1 it is expresses in terms of 15kHz SCS } - else - sco = 31; // no SIB1 cfg->ssb_table.ssb_offset_point_a.value = absolute_diff/(12*scs_scaling) - 10; //absoluteFrequencySSB is the central frequency of SSB which is made by 20RBs in total cfg->ssb_table.ssb_offset_point_a.tl.tag = NFAPI_NR_CONFIG_SSB_OFFSET_POINT_A_TAG; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 7d33f02dc0..bddc1509c5 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -236,7 +236,7 @@ uint8_t do_MIB_NR(gNB_RRC_INST *rrc,uint32_t frame) { if (get_softmodem_params()->sa) { ssb_subcarrier_offset = absolute_diff%(12*scs_scaling); if(frequency_range == FR1) - ssb_subcarrier_offset = ssb_subcarrier_offset<<*scc->ssbSubcarrierSpacing; + ssb_subcarrier_offset <<= *scc->ssbSubcarrierSpacing; } mib->message.choice.mib->ssb_SubcarrierOffset = ssb_subcarrier_offset&15; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.25PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.25PRB.usrpn300.conf index 6af1356088..022f17e490 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.25PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.25PRB.usrpn300.conf @@ -21,9 +21,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts = 1; - pusch_AntennaPorts = 1; min_rxtxtime = 6; servingCellConfigCommon = ( diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.4layer.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.4layer.conf index 74f2f9c11c..8ff83b5d02 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.4layer.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.4layer.conf @@ -32,10 +32,9 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; - pdsch_AntennaPorts = 4; + pdsch_AntennaPorts_XP = 2; + pdsch_AntennaPorts_N1 = 2; pusch_AntennaPorts = 4; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { @@ -73,15 +72,6 @@ gNBs = #pdcch-ConfigCommon initialDLBWPcontrolResourceSetZero = 12; initialDLBWPsearchSpaceZero = 0; - #pdsch-ConfigCommon - #pdschTimeDomainAllocationList (up to 16 entries) - initialDLBWPk0_0 = 0; #for DL slot - initialDLBWPmappingType_0 = 0; #0=typeA,1=typeB - initialDLBWPstartSymbolAndLength_0 = 40; #this is SS=1,L=13 - - initialDLBWPk0_1 = 0; #for mixed slot - initialDLBWPmappingType_1 = 0; - initialDLBWPstartSymbolAndLength_1 = 57; #this is SS=1,L=5 #uplinkConfigCommon #frequencyInfoUL @@ -136,19 +126,6 @@ gNBs = # 0=unrestricted, 1=restricted type A, 2=restricted type B restrictedSetConfig = 0, - # pusch-ConfigCommon (up to 16 elements) - initialULBWPk2_0 = 6; # used for UL slot - initialULBWPmappingType_0 = 1 - initialULBWPstartSymbolAndLength_0 = 41; # this is SS=0 L=13 - - initialULBWPk2_1 = 6; # used for mixed slot - initialULBWPmappingType_1 = 1; - initialULBWPstartSymbolAndLength_1 = 52; # this is SS=10 L=4 - - initialULBWPk2_2 = 7; # used for Msg.3 during RA - initialULBWPmappingType_2 = 1; - initialULBWPstartSymbolAndLength_2 = 52; # this is SS=10 L=4 - msg3_DeltaPreamble = 1; p0_NominalWithGrant =-90; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.217PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.217PRB.2x2.usrpn300.conf index 763396998d..1f1f64ce3f 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.217PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.217PRB.2x2.usrpn300.conf @@ -27,7 +27,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; pdsch_AntennaPorts_XP = 1; pusch_AntennaPorts = 2; do_CSIRS = 0; @@ -318,4 +317,4 @@ log_config : rrc_log_level ="info"; ngap_log_level ="debug"; f1ap_log_level ="debug"; -}; \ No newline at end of file +}; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.273PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.273PRB.2x2.usrpn300.conf index 3d93f2cfab..24090bef85 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.273PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.273PRB.2x2.usrpn300.conf @@ -27,7 +27,6 @@ gNBs = ////////// Physical parameters: - ssb_SubcarrierOffset = 0; pdsch_AntennaPorts_XP = 1; pusch_AntennaPorts = 2; do_CSIRS = 0; @@ -318,4 +317,4 @@ log_config : rrc_log_level ="info"; ngap_log_level ="debug"; f1ap_log_level ="debug"; -}; \ No newline at end of file +}; From 0fe98c25a2e04c644d6aabdcef9ba192400c9e6f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 20 Jun 2022 13:34:54 +0200 Subject: [PATCH 149/267] Avoid RHEL_RELEASE_VERSION: not defined in Ubuntu --- openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c | 3 +-- .../PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c | 3 +-- openair2/NETWORK_DRIVER/MESH/device.c | 9 +++------ openair2/NETWORK_DRIVER/UE_IP/device.c | 11 ++++------- 4 files changed, 9 insertions(+), 17 deletions(-) diff --git a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c index 4ad27fcfbe..8f5e33d6e0 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c @@ -41,8 +41,7 @@ #include #include #include -#if defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4) \ - && RHEL_RELEASE_CODE != RHEL_RELEASE_VERSION(9,99) +#if defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= 1796 && RHEL_RELEASE_CODE != 2403 #include #include #else diff --git a/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c b/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c index 265e88dc39..83c74389cf 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c @@ -14,8 +14,7 @@ data storage. */ #include #include #include -#if defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4) \ - && RHEL_RELEASE_CODE != RHEL_RELEASE_VERSION(9,99) +#if defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= 1796 && RHEL_RELEASE_CODE != 2403 #include #include #else diff --git a/openair2/NETWORK_DRIVER/MESH/device.c b/openair2/NETWORK_DRIVER/MESH/device.c index 08e1577cea..d86e32e561 100644 --- a/openair2/NETWORK_DRIVER/MESH/device.c +++ b/openair2/NETWORK_DRIVER/MESH/device.c @@ -199,8 +199,7 @@ int nas_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) // End debug information netif_stop_queue(dev); #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) \ - || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4) \ - && RHEL_RELEASE_CODE != RHEL_RELEASE_VERSION(9,99)) + || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= 1796 && RHEL_RELEASE_CODE != 2403) netif_trans_update(dev); #else dev->trans_start = jiffies; @@ -270,8 +269,7 @@ void nas_tx_timeout(struct net_device *dev) // (struct nas_priv *)(dev->priv)->stats.tx_errors++; (priv->stats).tx_errors++; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) \ - || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4) \ - && RHEL_RELEASE_CODE != RHEL_RELEASE_VERSION(9,99)) + || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= 1796 && RHEL_RELEASE_CODE != 2403) netif_trans_update(dev); #else dev->trans_start = jiffies; @@ -290,8 +288,7 @@ static const struct net_device_ops nasmesh_netdev_ops = { .ndo_set_config = nas_set_config, .ndo_do_ioctl = nas_CTL_ioctl, #if LINUX_VERSION_CODE <= KERNEL_VERSION(3,11,0) \ - || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5) \ - && RHEL_RELEASE_CODE != RHEL_RELEASE_VERSION(9,99)) + || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= 1797 && RHEL_RELEASE_CODE != 2403) .extended.ndo_change_mtu = nas_change_mtu, #else .ndo_change_mtu = nas_change_mtu, diff --git a/openair2/NETWORK_DRIVER/UE_IP/device.c b/openair2/NETWORK_DRIVER/UE_IP/device.c index d124be07ae..bf858a0005 100644 --- a/openair2/NETWORK_DRIVER/UE_IP/device.c +++ b/openair2/NETWORK_DRIVER/UE_IP/device.c @@ -240,8 +240,7 @@ int ue_ip_hard_start_xmit(struct sk_buff *skb_pP, struct net_device *dev_pP) { // End debug information netif_stop_queue(dev_pP); #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) \ - || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4) \ - && RHEL_RELEASE_CODE != RHEL_RELEASE_VERSION(9,99)) + || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= 1796 && RHEL_RELEASE_CODE != 2403) netif_trans_update(dev_pP); #else dev_pP->trans_start = jiffies; @@ -317,9 +316,8 @@ void ue_ip_tx_timeout(struct net_device *dev_pP) printk("[UE_IP_DRV][%s] begin\n", __FUNCTION__); // (ue_ip_priv_t *)(dev_pP->priv_p)->stats.tx_errors++; (priv_p->stats).tx_errors++; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) \\ - || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4) \ - && RHEL_RELEASE_CODE != RHEL_RELEASE_VERSION(9,99)) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) \ + || (defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= 1796 && RHEL_RELEASE_CODE != 2403) netif_trans_update(dev_pP); #else dev_pP->trans_start = jiffies; @@ -337,8 +335,7 @@ static const struct net_device_ops ue_ip_netdev_ops = { .ndo_set_mac_address = ue_ip_set_mac_address, .ndo_set_config = ue_ip_set_config, .ndo_do_ioctl = NULL, -#if defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5) \ - && RHEL_RELEASE_CODE != RHEL_RELEASE_VERSION(9,99) +#if defined RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= 1797 && RHEL_RELEASE_CODE != 2403 .extended.ndo_change_mtu = ue_ip_change_mtu, #else .ndo_change_mtu = ue_ip_change_mtu, From d0fa56b1de6f4ec4d44c38dad92b21a4a5185424 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 20 Jun 2022 15:15:11 +0200 Subject: [PATCH 150/267] compilation fix --- openair2/RRC/NR/rrc_gNB.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index ddefb76789..159640ba7a 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -809,6 +809,7 @@ rrc_gNB_generate_defaultRRCReconfiguration( } if (NODE_IS_DU(rrc->node_type) || NODE_IS_MONOLITHIC(rrc->node_type)) { + gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; rrc_mac_config_req_gNB(rrc->module_id, rrc->configuration.ssb_SubcarrierOffset, rrc->configuration.pdsch_AntennaPorts, From 83a9414258d833a7352cb9d7f0b87f636f189a5d Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 20 Jun 2022 18:03:40 +0200 Subject: [PATCH 151/267] srs and csi in BWP structures --- openair1/SIMULATION/NR_PHY/dlsim.c | 1 - .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 4 ---- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 2 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 19 +++++++++---------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c | 12 ++---------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 17 +++++------------ openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 1 - openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 ++ 8 files changed, 19 insertions(+), 39 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 90fbd36004..8d89ff0888 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -304,7 +304,6 @@ void nr_dlsim_preprocessor(module_id_t module_id, nr_set_pdsch_semi_static(BWP, scc, - UE_info->CellGroup, /* tda = */ 0, g_nrOfLayers, sched_ctrl, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 5c1203a12c..c42fba7ab0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -379,7 +379,6 @@ bool allocate_dl_retransmission(module_id_t module_id, NR_UE_DL_BWP_t *BWP = &UE->current_DL_BWP; NR_UE_UL_BWP_t *UBWP = &UE->current_UL_BWP; NR_sched_pdsch_t *retInfo = &sched_ctrl->harq_processes[current_harq_pid].sched_pdsch; - NR_CellGroupConfig_t *cg = UE->CellGroup; const int coresetid = sched_ctrl->coreset->controlResourceSetId; const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : BWP->BWPSize; @@ -416,7 +415,6 @@ bool allocate_dl_retransmission(module_id_t module_id, if (ps->time_domain_allocation != tda) { nr_set_pdsch_semi_static(BWP, scc, - cg, tda, ps->nrOfLayers, sched_ctrl, @@ -429,7 +427,6 @@ bool allocate_dl_retransmission(module_id_t module_id, nr_set_pdsch_semi_static(BWP, scc, - cg, tda, ps->nrOfLayers, sched_ctrl, @@ -710,7 +707,6 @@ void pf_dl(module_id_t module_id, if (ps->nrOfLayers != iterator->UE->layers || ps->time_domain_allocation != tda ) { nr_set_pdsch_semi_static(BWP, scc, - iterator->UE->CellGroup, tda, iterator->UE->layers, sched_ctrl, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index ea681dc1bf..5926b61f4c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -202,7 +202,7 @@ void nr_preprocessor_phytest(module_id_t module_id, NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; ps->nrOfLayers = target_dl_Nl; if (ps->time_domain_allocation != tda || ps->nrOfLayers != target_dl_Nl) - nr_set_pdsch_semi_static(BWP, scc, UE->CellGroup, tda, target_dl_Nl,sched_ctrl , ps); + nr_set_pdsch_semi_static(BWP, scc, tda, target_dl_Nl,sched_ctrl , ps); /* find largest unallocated chunk */ const int bwpSize = BWP->BWPSize; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index c363eac31a..c90955f0aa 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -510,7 +510,6 @@ bool nr_find_nb_rb(uint16_t Qm, void nr_set_pdsch_semi_static(const NR_UE_DL_BWP_t *BWP, const NR_ServingCellConfigCommon_t *scc, - const NR_CellGroupConfig_t *secondaryCellGroup, int tda, uint8_t layers, NR_UE_sched_ctrl_t *sched_ctrl, @@ -2201,7 +2200,6 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, NR_BWP_Uplink_t *ul_bwp = NULL; NR_BWP_DownlinkDedicated_t *bwpd = NULL; NR_BWP_UplinkDedicated_t *ubwpd = NULL; - NR_CSI_MeasConfig_t *csi_MeasConfig = NULL; DL_BWP->n_dl_bwp = 1; UL_BWP->n_ul_bwp = 1; int old_dl_bwp_id = DL_BWP->bwp_id; @@ -2215,7 +2213,6 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, const NR_ServingCellConfig_t *servingCellConfig = CellGroup->spCellConfig->spCellConfigDedicated; DL_BWP->pdsch_servingcellconfig = servingCellConfig->pdsch_ServingCellConfig? servingCellConfig->pdsch_ServingCellConfig->choice.setup : NULL; - csi_MeasConfig = servingCellConfig->csi_MeasConfig ? servingCellConfig->csi_MeasConfig->choice.setup : NULL; target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; if(UE && UE->Msg3_dcch_dtch) { @@ -2271,6 +2268,8 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, DL_BWP->pdsch_Config = bwpd->pdsch_Config->choice.setup; UL_BWP->pusch_Config = ubwpd->pusch_Config->choice.setup; UL_BWP->pucch_Config = ubwpd->pucch_Config->choice.setup; + UL_BWP->srs_Config = ubwpd->srs_Config->choice.setup; + UL_BWP->csi_MeasConfig = servingCellConfig->csi_MeasConfig ? servingCellConfig->csi_MeasConfig->choice.setup : NULL; } else { DL_BWP->bwp_id = 0; @@ -2279,6 +2278,7 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, DL_BWP->pdsch_Config = NULL; UL_BWP->pusch_Config = NULL; UL_BWP->pucch_Config = NULL; + UL_BWP->csi_MeasConfig = NULL; } if (old_dl_bwp_id != DL_BWP->bwp_id) @@ -2369,8 +2369,8 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0) : NR_UL_DCI_FORMAT_0_0; - if (csi_MeasConfig) - compute_csi_bitlen (csi_MeasConfig, UE); + if (UL_BWP->csi_MeasConfig) + compute_csi_bitlen (UL_BWP->csi_MeasConfig, UE); } @@ -2671,13 +2671,13 @@ void nr_csirs_scheduling(int Mod_idP, if (sched_ctrl->rrc_processing_timer > 0) { continue; } - NR_CellGroupConfig_t *CellGroup = UE->CellGroup; + NR_UE_DL_BWP_t *BWP = &UE->current_DL_BWP; + NR_UE_UL_BWP_t *UBWP = &UE->current_UL_BWP; - if (!CellGroup || !CellGroup->spCellConfig || !CellGroup->spCellConfig->spCellConfigDedicated || - !CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig) continue; + if (!UBWP->csi_MeasConfig) continue; - NR_CSI_MeasConfig_t *csi_measconfig = CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup; + NR_CSI_MeasConfig_t *csi_measconfig = UBWP->csi_MeasConfig; if (csi_measconfig->nzp_CSI_RS_ResourceToAddModList != NULL) { @@ -2913,7 +2913,6 @@ void nr_mac_update_timers(module_id_t module_id, nr_set_pdsch_semi_static(&UE->current_DL_BWP, scc, - cg, tda, layers, sched_ctrl, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index 15d06886f5..0344b7e622 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -108,7 +108,6 @@ void nr_schedule_srs(int module_id, frame_t frame) { UE_iterator(UE_info->list, UE) { const int CC_id = 0; - NR_CellGroupConfig_t *cg = UE->CellGroup; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP; @@ -120,16 +119,9 @@ void nr_schedule_srs(int module_id, frame_t frame) { continue; } - NR_SRS_Config_t *srs_config = NULL; - if (cg && - cg->spCellConfig && - cg->spCellConfig->spCellConfigDedicated && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { - srs_config = cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->srs_Config->choice.setup; - } else { + NR_SRS_Config_t *srs_config = current_BWP->srs_Config; + if (!srs_config) continue; - } for(int rs = 0; rs < srs_config->srs_ResourceSetToAddModList->list.count; rs++) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index d4c7a7779d..a8f8ab3f10 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -688,16 +688,14 @@ void nr_csi_meas_reporting(int Mod_idP, sub_frame_t slot) { UE_iterator(RC.nrmac[Mod_idP]->UE_info.list, UE ) { - const NR_CellGroupConfig_t *CellGroup = UE->CellGroup; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_UL_BWP_t *UL_BWP = &UE->current_UL_BWP; const int n_slots_frame = nr_slots_per_frame[UL_BWP->scs]; if ((sched_ctrl->rrc_processing_timer > 0) || (sched_ctrl->ul_failure==1 && get_softmodem_params()->phy_test==0)) { continue; } - if (!CellGroup || !CellGroup->spCellConfig || !CellGroup->spCellConfig->spCellConfigDedicated || - !CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig) continue; - const NR_CSI_MeasConfig_t *csi_measconfig = CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup; + const NR_CSI_MeasConfig_t *csi_measconfig = UL_BWP->csi_MeasConfig; + if (!csi_measconfig) continue; AssertFatal(csi_measconfig->csi_ReportConfigToAddModList->list.count > 0, "NO CSI report configuration available"); NR_PUCCH_Config_t *pucch_Config = UL_BWP->pucch_Config; @@ -1472,15 +1470,10 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, LOG_E(NR_MAC, "%s(): unknown RNTI %04x in PUCCH UCI\n", __func__, uci_234->rnti); return; } - AssertFatal(UE->CellGroup,"Cellgroup is null for UE %04x\n", uci_234->rnti); - AssertFatal(UE->CellGroup->spCellConfig, - "Cellgroup->spCellConfig is null for UE %04x\n", uci_234->rnti); - AssertFatal(UE->CellGroup->spCellConfig->spCellConfigDedicated, - "Cellgroup->spCellConfig->spCellConfigDedicated is null for UE %04x\n", uci_234->rnti); - if ( UE->CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig==NULL) - return; - NR_CSI_MeasConfig_t *csi_MeasConfig = UE->CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup; + NR_CSI_MeasConfig_t *csi_MeasConfig = UE->current_UL_BWP.csi_MeasConfig; + if (csi_MeasConfig==NULL) + return; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; // tpc (power control) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 196951c47d..a178f5aabd 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -331,7 +331,6 @@ long get_K2(NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList, void nr_set_pdsch_semi_static(const NR_UE_DL_BWP_t *BWP, const NR_ServingCellConfigCommon_t *scc, - const NR_CellGroupConfig_t *secondaryCellGroup, int tda, uint8_t layers, NR_UE_sched_ctrl_t *sched_ctrl, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 12b4f75927..a14d8369b5 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -116,6 +116,8 @@ typedef struct NR_UE_UL_BWP { NR_PUSCH_Config_t *pusch_Config; NR_PUCCH_Config_t *pucch_Config; NR_PUCCH_ConfigCommon_t *pucch_ConfigCommon; + NR_CSI_MeasConfig_t *csi_MeasConfig; + NR_SRS_Config_t *srs_Config; uint8_t transform_precoding; uint8_t mcs_table; nr_dci_format_t dci_format; From 9c02189e64aa214dd1adc6d23c3638b2f9880a2b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 21 Jun 2022 08:54:41 +0200 Subject: [PATCH 152/267] Remove nr_bler_data from physims --- openair1/SIMULATION/NR_PHY/dlsim.c | 2 -- openair1/SIMULATION/NR_PHY/prachsim.c | 2 -- openair1/SIMULATION/NR_PHY/ulsim.c | 2 -- 3 files changed, 6 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index bab67e4426..d319ac8a2b 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -242,8 +242,6 @@ int DU_send_INITIAL_UL_RRC_MESSAGE_TRANSFER(module_id_t module_idP, return 0; } -nr_bler_struct nr_bler_data[NR_NUM_MCS]; - void processSlotTX(void *arg) {} //nFAPI P7 dummy functions to avoid linking errors diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index 33717c944d..91a8265ff1 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -227,8 +227,6 @@ nrUE_params_t *get_nrUE_params(void) { return &nrUE_params; } -nr_bler_struct nr_bler_data[NR_NUM_MCS]; - void processSlotTX(void *arg) {} int main(int argc, char **argv){ diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 2a3730c1d4..8a9b4a7a46 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -225,8 +225,6 @@ int DU_send_INITIAL_UL_RRC_MESSAGE_TRANSFER(module_id_t module_idP, return 0; } -nr_bler_struct nr_bler_data[NR_NUM_MCS]; - //nFAPI P7 dummy functions int oai_nfapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req) { return(0); } From a24be049293bafafd1d037939d9e99ca6f0e8208 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 21 Jun 2022 09:52:12 +0200 Subject: [PATCH 153/267] initializing nrofcandidates in dlsim --- openair1/SIMULATION/NR_PHY/dlsim.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 8d89ff0888..b9fed90eab 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -276,9 +276,7 @@ void nr_dlsim_preprocessor(module_id_t module_id, NR_UE_DL_BWP_t *BWP = &UE_info->current_DL_BWP; NR_ServingCellConfigCommon_t *scc = RC.nrmac[0]->common_channels[0].ServingCellConfigCommon; - /* manually set free CCE to 0 */ - - uint8_t nr_of_candidates; + uint8_t nr_of_candidates = 0; if (g_mcsIndex < 4) { find_aggregation_candidates(&sched_ctrl->aggregation_level, &nr_of_candidates, From 2659dce8b830ad9549022ada5b7bfa19cc89dd31 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 21 Jun 2022 13:49:31 +0200 Subject: [PATCH 154/267] removing flag init_UL_tti_req_ahead --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 3 +-- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 11 ++++++----- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 2 +- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 1 - 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index 92867602c8..c87aa68f75 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -68,8 +68,7 @@ void clear_nr_nfapi_information(gNB_MAC_INST * gNB, NR_ServingCellConfigCommon_t *scc = gNB->common_channels->ServingCellConfigCommon; const int num_slots = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; - if(gNB->init_UL_tti_req_ahead == false) - UL_tti_req_ahead_initialization(gNB, scc, num_slots); + UL_tti_req_ahead_initialization(gNB, scc, num_slots, CC_idP); nfapi_nr_dl_tti_request_t *DL_req = &gNB->DL_req[0]; nfapi_nr_dl_tti_pdcch_pdu_rel15_t **pdcch = (nfapi_nr_dl_tti_pdcch_pdu_rel15_t **)gNB->pdcch_pdu_idx[CC_idP]; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index efc83c034f..f0dc29b2db 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2995,18 +2995,19 @@ void schedule_nr_bwp_switch(module_id_t module_id, } } -void UL_tti_req_ahead_initialization(gNB_MAC_INST * gNB, NR_ServingCellConfigCommon_t *scc, int n) { +void UL_tti_req_ahead_initialization(gNB_MAC_INST * gNB, NR_ServingCellConfigCommon_t *scc, int n, int CCid) { - gNB->UL_tti_req_ahead[0] = calloc(n, sizeof(nfapi_nr_ul_tti_request_t)); - AssertFatal(gNB->UL_tti_req_ahead[0], + if(gNB->UL_tti_req_ahead[CCid]) return; + + gNB->UL_tti_req_ahead[CCid] = calloc(n, sizeof(nfapi_nr_ul_tti_request_t)); + AssertFatal(gNB->UL_tti_req_ahead[CCid], "could not allocate memory for RC.nrmac[]->UL_tti_req_ahead[]\n"); /* fill in slot/frame numbers: slot is fixed, frame will be updated by scheduler * consider that scheduler runs sl_ahead: the first sl_ahead slots are * already "in the past" and thus we put frame 1 instead of 0! */ for (int i = 0; i < n; ++i) { - nfapi_nr_ul_tti_request_t *req = &gNB->UL_tti_req_ahead[0][i]; + nfapi_nr_ul_tti_request_t *req = &gNB->UL_tti_req_ahead[CCid][i]; req->SFN = i < (gNB->if_inst->sl_ahead-1); req->Slot = i; } - gNB->init_UL_tti_req_ahead = true; } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 9dbd745c19..6ef11a433d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -522,7 +522,7 @@ int get_mcs_from_bler(const NR_bler_options_t *bler_options, int max_mcs, frame_t frame); -void UL_tti_req_ahead_initialization(gNB_MAC_INST * gNB, NR_ServingCellConfigCommon_t *scc, int n); +void UL_tti_req_ahead_initialization(gNB_MAC_INST * gNB, NR_ServingCellConfigCommon_t *scc, int n, int CCid); void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t frameP, sub_frame_t slotP); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 52ba4bf16a..03a982ab7b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -850,7 +850,6 @@ typedef struct gNB_MAC_INST_s { uint8_t harq_round_max; uint8_t min_grant_prb; uint8_t min_grant_mcs; - bool init_UL_tti_req_ahead; } gNB_MAC_INST; #endif /*__LAYER2_NR_MAC_GNB_H__ */ From 2802418c34b703334ae6eafa453c4c53c211e420 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 21 Jun 2022 16:43:54 +0200 Subject: [PATCH 155/267] remove debug printf --- openair2/F1AP/f1ap_du_task.c | 1 - 1 file changed, 1 deletion(-) diff --git a/openair2/F1AP/f1ap_du_task.c b/openair2/F1AP/f1ap_du_task.c index 5212e325b3..f8cf216220 100644 --- a/openair2/F1AP/f1ap_du_task.c +++ b/openair2/F1AP/f1ap_du_task.c @@ -126,7 +126,6 @@ void *F1AP_DU_task(void *arg) { LOG_I(F1AP, "DU Task Received F1AP_SETUP_REQ\n"); f1ap_setup_req_t *msgSetup=&F1AP_SETUP_REQ(msg); createF1inst(false, myInstance, msgSetup); -printf("XXXXXXXXXXXXXXX old 172.21.6.9 new %s\n", msgSetup->CU_f1_ip_address.ipv4_address); getCxt(DUtype, myInstance)->gtpInst=du_create_gtpu_instance_to_cu(msgSetup->CU_f1_ip_address.ipv4_address, //"172.21.6.9", //"172.21.10.9",//"172.21.9.5", //msgSetup->CU_f1_ip_address.ipv4_address, //"192.168.18.91" msgSetup->CUport, msgSetup->DU_f1_ip_address.ipv4_address, From f6fe86c653a350424a84ba8beb2f3990573f5c0d Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 21 Jun 2022 19:24:04 +0200 Subject: [PATCH 156/267] Fix macros to avoid warnings --- openair3/UTILS/conversions.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/openair3/UTILS/conversions.h b/openair3/UTILS/conversions.h index 00b650a302..a753b8c60d 100644 --- a/openair3/UTILS/conversions.h +++ b/openair3/UTILS/conversions.h @@ -70,8 +70,8 @@ /* Convert an integer on 16 bits to the given bUFFER */ #define INT16_TO_BUFFER(x, buf) \ do { \ - (buf)[0] = (x) >> 8; \ - (buf)[1] = (x); \ + (buf)[0] = (x >> 8) & 0xff; \ + (buf)[1] = (x) & 0xff; \ } while(0) /* Convert an array of char containing vALUE to x */ @@ -84,9 +84,9 @@ do { \ /* Convert an integer on 24 bits to the given bUFFER */ #define INT24_TO_BUFFER(x, buf) \ do { \ - (buf)[0] = (x) >> 16; \ - (buf)[1] = (x) >> 8; \ - (buf)[2] = (x); \ + (buf)[0] = (x >> 16) & 0xff;\ + (buf)[1] = (x >> 8) & 0xff; \ + (buf)[2] = (x) & 0xff; \ } while(0) /* Convert an array of char containing vALUE to x */ @@ -101,10 +101,10 @@ do { \ /* Convert an integer on 32 bits to the given bUFFER */ #define INT32_TO_BUFFER(x, buf) \ do { \ - (buf)[0] = (x) >> 24; \ - (buf)[1] = (x) >> 16; \ - (buf)[2] = (x) >> 8; \ - (buf)[3] = (x); \ + (buf)[0] = (x >> 24) & 0xff;\ + (buf)[1] = (x >> 16) & 0xff;\ + (buf)[2] = (x >> 8) & 0xff; \ + (buf)[3] = (x) & 0xff; \ } while(0) /* Convert an array of char containing vALUE to x */ From 6f481e09f6aceefacca0e547ea7a4bb466a20864 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 22 Jun 2022 16:15:31 +0200 Subject: [PATCH 157/267] abort rtx if RI decreased --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 25 ++++++++++++++++++- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 10 ++------ openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 2 ++ openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 1 + 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 3b5c9ffad4..dce798f24f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -365,6 +365,18 @@ void nr_store_dlsch_buffer(module_id_t module_id, } } +void abort_nr_dl_harq(NR_UE_info_t* UE, int8_t harq_pid) { + + NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_UE_harq_t *harq = &sched_ctrl->harq_processes[harq_pid]; + + harq->ndi ^= 1; + harq->round = 0; + UE->mac_stats.dl.errors++; + add_tail_nr_list(&sched_ctrl->available_dl_harq, harq_pid); + +} + bool allocate_dl_retransmission(module_id_t module_id, frame_t frame, sub_frame_t slot, @@ -378,6 +390,16 @@ bool allocate_dl_retransmission(module_id_t module_id, NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_sched_pdsch_t *retInfo = &sched_ctrl->harq_processes[current_harq_pid].sched_pdsch; NR_CellGroupConfig_t *cg = UE->CellGroup; + NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; + + //TODO remove this and handle retransmission with old nrOfLayers + // once ps structure is removed + if(ps->nrOfLayers < retInfo->nrOfLayers) { + LOG_W(NR_MAC,"Cannot schedule retransmission. RI changed from %d to %d\n", + retInfo->nrOfLayers, ps->nrOfLayers); + abort_nr_dl_harq(UE, current_harq_pid); + return false; + } NR_BWP_DownlinkDedicated_t *bwpd = cg && @@ -401,7 +423,6 @@ bool allocate_dl_retransmission(module_id_t module_id, const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); int rbStart = 0; // start wrt BWPstart - NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; int rbSize = 0; const int tda = get_dl_tda(RC.nrmac[module_id], scc, slot); AssertFatal(tda>=0,"Unable to find PDSCH time domain allocation in list\n"); @@ -1355,6 +1376,8 @@ void nr_schedule_ue_spec(module_id_t module_id, /* save which time allocation has been used, to be used on * retransmissions */ harq->sched_pdsch.time_domain_allocation = ps->time_domain_allocation; + /* save nr of layers for retransmissions */ + harq->sched_pdsch.nrOfLayers = ps->nrOfLayers; // ta command is sent, values are reset if (sched_ctrl->ta_apply) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index d64b9c43db..a9a67141a2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -826,14 +826,8 @@ static void handle_dl_harq(NR_UE_info_t * UE, harq->ndi ^= 1; } else if (harq->round >= harq_round_max - 1) { - add_tail_nr_list(&UE->UE_sched_ctrl.available_dl_harq, harq_pid); - harq->round = 0; - harq->ndi ^= 1; - - NR_mac_stats_t *stats = &UE->mac_stats; - stats->dl.errors++; - LOG_D(NR_MAC, "retransmission error for UE %04x (total %"PRIu64")\n", UE->rnti, stats->dl.errors); - + abort_nr_dl_harq(UE, harq_pid); + LOG_D(NR_MAC, "retransmission error for UE %04x (total %"PRIu64")\n", UE->rnti, UE->mac_stats.dl.errors); } else { LOG_D(PHY,"NACK for: pid %d, ue %04x\n",harq_pid, UE->rnti); add_tail_nr_list(&UE->UE_sched_ctrl.retrans_dl_harq, harq_pid); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 7911275f70..bf36264b9d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -532,4 +532,6 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset void process_CellGroup(NR_CellGroupConfig_t *CellGroup, NR_UE_sched_ctrl_t *sched_ctrl); +void abort_nr_dl_harq(NR_UE_info_t* UE, int8_t harq_pid); + #endif /*__LAYER2_NR_MAC_PROTO_H__*/ diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 7658441aed..049c7547ec 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -440,6 +440,7 @@ typedef struct NR_sched_pdsch { /// only important for retransmissions; otherwise, the TDA in /// NR_pdsch_semi_static_t has precedence int time_domain_allocation; + uint8_t nrOfLayers; } NR_sched_pdsch_t; typedef struct NR_UE_harq { From 586aa46c2c6032ddc29329f7beae27460f687168 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 22 Jun 2022 16:54:35 +0200 Subject: [PATCH 158/267] Set correct master clock rate for N320 --- targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp index 8976284345..cdd8f22b98 100644 --- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp +++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp @@ -1030,9 +1030,13 @@ extern "C" { } if (device_adds[0].get("type") == "n3xx") { - printf("Found USRP n300\n"); + const std::string product = device_adds[0].get("product"); + printf("Found USRP %s\n", product.c_str()); device->type=USRP_N300_DEV; - usrp_master_clock = 122.88e6; + if (product == "n320") + usrp_master_clock = 245.76e6; // N320 does not support 122.88e6 master clock rate + else + usrp_master_clock = 122.88e6; args += boost::str(boost::format(",master_clock_rate=%f") % usrp_master_clock); if ( 0 != system("sysctl -w net.core.rmem_max=62500000 net.core.wmem_max=62500000") ) From 420ce608003ab33de8c9d4ec48347eedf47799af Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 22 Jun 2022 17:54:34 +0100 Subject: [PATCH 159/267] Fix flag related to received CSI-IM FAPI pdu at UE --- openair1/SCHED_NR_UE/fapi_nr_ue_l1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c index 046f67a7d0..f4c863bb40 100644 --- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c @@ -393,7 +393,7 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response){ case FAPI_NR_DL_CONFIG_TYPE_CSI_IM: csiim_config_pdu = &dl_config->dl_config_list[i].csiim_config_pdu.csiim_config_rel15; memcpy((void*)&(csiim_vars->csiim_config_pdu), (void*)csiim_config_pdu, sizeof(fapi_nr_dl_config_csiim_pdu_rel15_t)); - csirs_vars->active = true; + csiim_vars->active = true; break; case FAPI_NR_DL_CONFIG_TYPE_CSI_RS: csirs_config_pdu = &dl_config->dl_config_list[i].csirs_config_pdu.csirs_config_rel15; From 32ec53baa5546241f9961c9e481d19291bfe9486 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 22 Jun 2022 18:10:28 +0100 Subject: [PATCH 160/267] Get CSI-IM pdu at phy layer and add debug logs --- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 5a05e256e2..719d8e11b4 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -41,6 +41,7 @@ //#define NR_CSIRS_DEBUG +//#define NR_CSIIM_DEBUG bool is_csi_rs_in_symbol(fapi_nr_dl_config_csirs_pdu_rel15_t csirs_config_pdu, int symbol) { @@ -600,6 +601,23 @@ int nr_csi_rs_cqi_estimation(uint32_t precoded_sinr, } int nr_ue_csi_im_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t gNB_id) { + + if(!ue->csiim_vars[gNB_id]->active) { + return -1; + } + + fapi_nr_dl_config_csiim_pdu_rel15_t *csiim_config_pdu = (fapi_nr_dl_config_csiim_pdu_rel15_t*)&ue->csiim_vars[gNB_id]->csiim_config_pdu; + +#ifdef NR_CSIIM_DEBUG + LOG_I(NR_PHY, "csiim_config_pdu->bwp_size = %i\n", csiim_config_pdu->bwp_size); + LOG_I(NR_PHY, "csiim_config_pdu->bwp_start = %i\n", csiim_config_pdu->bwp_start); + LOG_I(NR_PHY, "csiim_config_pdu->subcarrier_spacing = %i\n", csiim_config_pdu->subcarrier_spacing); + LOG_I(NR_PHY, "csiim_config_pdu->start_rb = %i\n", csiim_config_pdu->start_rb); + LOG_I(NR_PHY, "csiim_config_pdu->nr_of_rbs = %i\n", csiim_config_pdu->nr_of_rbs); + LOG_I(NR_PHY, "csiim_config_pdu->k_csiim = %i.%i.%i.%i\n", csiim_config_pdu->k_csiim[0], csiim_config_pdu->k_csiim[1], csiim_config_pdu->k_csiim[2], csiim_config_pdu->k_csiim[3]); + LOG_I(NR_PHY, "csiim_config_pdu->l_csiim = %i.%i.%i.%i\n", csiim_config_pdu->l_csiim[0], csiim_config_pdu->l_csiim[1], csiim_config_pdu->l_csiim[2], csiim_config_pdu->l_csiim[3]); +#endif + return 0; } From b9a207a6b40cf532f6d6ccc7372ed6adb56294ec Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 22 Jun 2022 18:38:05 +0100 Subject: [PATCH 161/267] Call nr_slot_fep for CSI-IM symbols --- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 739f6010d4..8bb4181c49 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -1696,6 +1696,19 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue, // do procedures for CSI-IM if ((ue->csiim_vars[gNB_id]) && (ue->csiim_vars[gNB_id]->active == 1)) { + int l_csiim[4] = {-1, -1, -1, -1}; + for(int symb_idx = 0; symb_idx < 4; symb_idx++) { + bool nr_slot_fep_done = false; + for (int symb_idx2 = 0; symb_idx2 < symb_idx; symb_idx2++) { + if (l_csiim[symb_idx2] == ue->csiim_vars[gNB_id]->csiim_config_pdu.l_csiim[symb_idx]) { + nr_slot_fep_done = true; + } + } + l_csiim[symb_idx] = ue->csiim_vars[gNB_id]->csiim_config_pdu.l_csiim[symb_idx]; + if(nr_slot_fep_done == false) { + nr_slot_fep(ue, proc, ue->csiim_vars[gNB_id]->csiim_config_pdu.l_csiim[symb_idx], nr_slot_rx); + } + } nr_ue_csi_im_procedures(ue, proc, gNB_id); ue->csiim_vars[gNB_id]->active = 0; } From a1806c92a2a8350364c39820717fca0876b4fa52 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 22 Jun 2022 20:41:57 +0100 Subject: [PATCH 162/267] Interference plus noise power computation based on CSI-IM --- openair1/PHY/INIT/nr_init_ue.c | 4 ++ openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 76 +++++++++++++++++++++++++++ openair1/PHY/defs_nr_UE.h | 3 ++ openair1/PHY/defs_nr_common.h | 4 ++ 4 files changed, 87 insertions(+) diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 077302b207..ac2b7e21f6 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -381,6 +381,8 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) } } + ue->nr_csi_im_info = (nr_csi_im_info_t *)malloc16_clear(sizeof(nr_csi_im_info_t)); + ue->nr_srs_info = (nr_srs_info_t *)malloc16_clear(sizeof(nr_srs_info_t)); ue->nr_srs_info->sc_list = (uint16_t *) malloc16_clear(6*fp->N_RB_UL*sizeof(uint16_t)); ue->nr_srs_info->srs_generated_signal = (int32_t *) malloc16_clear( (2*(fp->samples_per_frame)+2048)*sizeof(int32_t) ); @@ -530,6 +532,8 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) free_and_zero(ue->nr_csi_rs_info->csi_rs_estimated_channel_freq); free_and_zero(ue->nr_csi_rs_info); + free_and_zero(ue->nr_csi_im_info); + for (int i = 0; i < fp->nb_antennas_rx; i++) { free_and_zero(ue->nr_srs_info->srs_received_signal[i]); free_and_zero(ue->nr_srs_info->srs_ls_estimated_channel[i]); diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 719d8e11b4..e9baf7e722 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -600,6 +600,80 @@ int nr_csi_rs_cqi_estimation(uint32_t precoded_sinr, return 0; } +int nr_csi_im_power_estimation(PHY_VARS_NR_UE *ue, + UE_nr_rxtx_proc_t *proc, + fapi_nr_dl_config_csiim_pdu_rel15_t *csiim_config_pdu, + uint32_t *interference_plus_noise_power) { + + int32_t **rxdataF = ue->common_vars.common_vars_rx_data_per_thread[proc->thread_id].rxdataF; + NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + + uint16_t end_rb = csiim_config_pdu->start_rb + csiim_config_pdu->nr_of_rbs > csiim_config_pdu->bwp_size ? + csiim_config_pdu->bwp_size : csiim_config_pdu->start_rb + csiim_config_pdu->nr_of_rbs; + + int32_t count = 0; + int32_t sum_re = 0; + int32_t sum_im = 0; + int32_t sum2_re = 0; + int32_t sum2_im = 0; + + int l_csiim[4] = {-1, -1, -1, -1}; + + for(int symb_idx = 0; symb_idx < 4; symb_idx++) { + + uint8_t symb = csiim_config_pdu->l_csiim[symb_idx]; + bool done = false; + for (int symb_idx2 = 0; symb_idx2 < symb_idx; symb_idx2++) { + if (l_csiim[symb_idx2] == symb) { + done = true; + } + } + + if (done) { + continue; + } + + l_csiim[symb_idx] = symb; + uint64_t symbol_offset = symb*frame_parms->ofdm_symbol_size; + + for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) { + + c16_t *rx_signal = (c16_t*)&rxdataF[ant_rx][symbol_offset]; + + for (int rb = csiim_config_pdu->start_rb; rb < end_rb; rb++) { + + uint16_t sc0_offset = (frame_parms->first_carrier_offset + rb*NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size; + + for (int sc_idx = 0; sc_idx<4; sc_idx++) { + + uint16_t sc = sc0_offset + csiim_config_pdu->k_csiim[sc_idx]; + +#ifdef NR_CSIIM_DEBUG + LOG_I(NR_PHY, "(ant_rx %i, sc %i) real %i, imag %i\n", ant_rx, rb, rx_signal[sc].r, rx_signal[sc].i); +#endif + + sum_re += rx_signal[sc].r; + sum_im += rx_signal[sc].i; + sum2_re += rx_signal[sc].r*rx_signal[sc].r; + sum2_im += rx_signal[sc].i*rx_signal[sc].i; + count++; + } + } + } + } + + int32_t power_re = sum2_re/count - (sum_re/count)*(sum_re/count); + int32_t power_im = sum2_im/count - (sum_im/count)*(sum_im/count); + + *interference_plus_noise_power = power_re + power_im; + +#ifdef NR_CSIIM_DEBUG + LOG_I(NR_PHY, "interference_plus_noise_power based on CSI-IM = %i\n", *interference_plus_noise_power); +#endif + + return 0; +} + int nr_ue_csi_im_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t gNB_id) { if(!ue->csiim_vars[gNB_id]->active) { @@ -618,6 +692,8 @@ int nr_ue_csi_im_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t LOG_I(NR_PHY, "csiim_config_pdu->l_csiim = %i.%i.%i.%i\n", csiim_config_pdu->l_csiim[0], csiim_config_pdu->l_csiim[1], csiim_config_pdu->l_csiim[2], csiim_config_pdu->l_csiim[3]); #endif + nr_csi_im_power_estimation(ue, proc, csiim_config_pdu, &ue->nr_csi_im_info->interference_plus_noise_power); + return 0; } diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index bd6808c54d..0c8dcc195c 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -881,6 +881,9 @@ typedef struct { /// CSI-RS variables nr_csi_rs_info_t *nr_csi_rs_info; + /// CSI-IM variables + nr_csi_im_info_t *nr_csi_im_info; + //#if defined(UPGRADE_RAT_NR) #if 1 SystemInformationBlockType1_nr_t systemInformationBlockType1_nr; diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index a94bb30787..1d23e48a3b 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -284,6 +284,10 @@ typedef struct { uint8_t *cqi; } nr_csi_rs_info_t; +typedef struct { + uint32_t interference_plus_noise_power; +} nr_csi_im_info_t; + typedef struct NR_DL_FRAME_PARMS NR_DL_FRAME_PARMS; typedef uint32_t (*get_samples_per_slot_t)(int slot, NR_DL_FRAME_PARMS* fp); From 05dde0a30d86cbd1b5d7042564f41544dd43c3b8 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 22 Jun 2022 20:59:19 +0100 Subject: [PATCH 163/267] Compute CQI using CSI-IM --- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 9 +++++---- openair1/PHY/defs_nr_common.h | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index e9baf7e722..6be4d399bf 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -468,7 +468,7 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, nr_csi_rs_info_t *nr_csi_rs_info, int32_t ***csi_rs_estimated_channel_freq, - uint32_t noise_power, + uint32_t interference_plus_noise_power, uint8_t rank_indicator, uint8_t *i1, uint8_t *i2, @@ -487,7 +487,7 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, // The first column is applicable if the UE is reporting a Rank = 1, whereas the second column is applicable if the // UE is reporting a Rank = 2. - if(nr_csi_rs_info->N_ports == 1 || noise_power == 0) { + if(nr_csi_rs_info->N_ports == 1 || interference_plus_noise_power == 0) { return 0; } @@ -542,7 +542,7 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, for(int p = 0; p<4; p++) { int32_t power_re = sum2_re[p] - (sum_re[p]>>nr_csi_rs_info->log2_re)*(sum_re[p]>>nr_csi_rs_info->log2_re); int32_t power_im = sum2_im[p] - (sum_im[p]>>nr_csi_rs_info->log2_re)*(sum_im[p]>>nr_csi_rs_info->log2_re); - tested_precoded_sinr[p] = (power_re+power_im)/(int32_t)noise_power; + tested_precoded_sinr[p] = (power_re+power_im)/(int32_t)interference_plus_noise_power; } if(rank_indicator == 0) { @@ -693,6 +693,7 @@ int nr_ue_csi_im_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t #endif nr_csi_im_power_estimation(ue, proc, csiim_config_pdu, &ue->nr_csi_im_info->interference_plus_noise_power); + ue->nr_csi_im_info->meas_computed = true; return 0; } @@ -754,7 +755,7 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t csirs_config_pdu, ue->nr_csi_rs_info, ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, - *ue->nr_csi_rs_info->noise_power, + ue->nr_csi_im_info->meas_computed ? ue->nr_csi_im_info->interference_plus_noise_power : *ue->nr_csi_rs_info->noise_power, *ue->nr_csi_rs_info->rank_indicator, ue->nr_csi_rs_info->i1, ue->nr_csi_rs_info->i2, diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 1d23e48a3b..c1c94cc2cc 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -285,6 +285,7 @@ typedef struct { } nr_csi_rs_info_t; typedef struct { + bool meas_computed; uint32_t interference_plus_noise_power; } nr_csi_im_info_t; From 4505e780c53f6fabd0ba629377e0931690601bfd Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 23 Jun 2022 11:44:01 +0200 Subject: [PATCH 164/267] nr rlc: minor: update tests Behavior for ack/nack generation has changed not too long ago but the tests were not checked and updated. --- openair2/LAYER2/nr_rlc/tests/test14.txt.gz | Bin 799 -> 787 bytes openair2/LAYER2/nr_rlc/tests/test15.txt.gz | Bin 554 -> 547 bytes openair2/LAYER2/nr_rlc/tests/test8.txt.gz | Bin 319 -> 319 bytes openair2/LAYER2/nr_rlc/tests/test9.txt.gz | Bin 316 -> 316 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/openair2/LAYER2/nr_rlc/tests/test14.txt.gz b/openair2/LAYER2/nr_rlc/tests/test14.txt.gz index 45e54651eb317c3b7695cfcab7428fe43172227b..53cea67c98d98e91baa4bfcd40518b523ef5a21f 100644 GIT binary patch delta 703 zcmV;w0zmzr29pMVABzYGiZ!%i0t0kqb96B@E_8Tw0Ns{5ZyZMugmeFjFSHY3X1eFa zP_W?4iKxghhz#awlMcouFr?x~jT%Z{NMYy5_#3W3{6imf5%(8J{ zCe~mr)?o#!SdR_Zh)vjxE!c`}*p408i8DBhb2z~%&f@|u;u0?73a;WBuHy!7A_lR) zAL9Qw{uryW8Fzp7?Gt#}fp2Dy-&}qd?nniDsDd~|5Jfx^kccECBL%5QLpm~$i5k?R z4i!{Uj|Mb)U-BeLUQM8Y|xa{NYJ~YY;$=4CD?C6qMizfe;CakO_rQ360PRgD{DP zXo-#}L?wD+AVy*$W?~^$Vk36qAWo7YS&}0ONlBhS6iAVjNSRbfmDEU`G)R+d$d>HL zLRPXrpnhqfZs#1UyCtDE+x0%FmiOJh3t{v3wBU zrIa3~R7E3`^$v`!neNjG#$cXXjE-O~d-(i1(?3%$}Cy)UyspA5sW495_LGCU(N zA|o*}qcAF?F*;)~Cetu2(=mmqbxh9;%*ag4eB8h}9rUu>cubA_rP#Q9>^rMGGltIP%7@oQMbOLxeI^oI(c~4>T-$>yXHeMwGrzhwNu!nOWPOAr+E%mz|4S$t2>uqae ly`I~Lhku?Z82!zOdi%n9_riL4VZA9hABzYGOnK#D0t0kqb96B@E_8Tw0Ns{LYhyM4NCCm^MOEKZ=bSpax9>mP-mu=3)#kg~ z{rThj8|)3M(LUX+`va@j9?Uh<1qmfF$t3~1yeB%vosFO z#2T!{I;>z7>#+eFu?d^81zWKV+pz;XaRz5`4ktLpd0fCnT*75s!Bt$tb=<&B#31&! zL;SywKgOzT#@(NN`vhKg;G5awH34cl-io5)8o-96^ro zpHsnJ_7p$=^5cGtJ|6BrjTIk$`uL>4H3%R_26Bf63QF*VK!}7y$b>?ughuFuL6}5C zv_wY~q7pqZ5F;@WGqDgWu@O6Q5GToyEXk3Cq$E#33ZzI%q)aNLN@}D|8l*`!WJ`8r zAuHJ*P`?aNw{wow-I7q7?RuY7%kyqOg|PYi@nn`c|2ZFBaKeJ}6k@yIlf40Af8Xj@ zeVt?Vykq4$XglrL%ZKjYsf~2-nKT@>$!b+`23{)=4~1{gPyRnr{*A_~B;fSMT>eEYZ;s0ssI@?OqfB diff --git a/openair2/LAYER2/nr_rlc/tests/test15.txt.gz b/openair2/LAYER2/nr_rlc/tests/test15.txt.gz index ddb895d56f0fe88f0ceffb9a100359413292f2b7..61fa01663479944ed13d1c30ee2c3adbe5a70cb1 100644 GIT binary patch literal 547 zcmV+;0^I!{iwFpnHMC*^19W9`bTKt9ba-?C&6Q1WQ!x-l_xy^pgbnhH$6r|@Dt2tz zt`MsHp8Zgz3ZbMaf?rRPCa8gss7RDbmgR-VI(K}peQ|bvF=KIC=eI8|HtToq-^`F1 z^FH2PE!vWo*A4e-wdwkMC%73Oa1JLp#d)0J0xsebF5?QW;s)G^TNQTPgg8VHMLc3i zKq8Wmj1;6I12Q5F>BxjSR8U1dYG^5R0;rw92Yulec&zP0%t?>~Q9y*#lC_xS9zdfBS~3-gB4>h*~& zyvG-hsP8+zd-acV{^i-`@YZjx@A{ncx0k!nKKIOS$q%%}?_T`%c({FipNHBg4+`pb zu?pyYKiBgr=(_Jl`B!1waLS)<8<{$x6k^E-Jzeb`}o^ktTj5m l)&+~@IQGS2THf4z+qIy#*M|z^u?2dx;0IK+b^){r001`Y7gzuQ literal 554 zcmV+_0@eK=iwFo?BT%gc&;HC?*=-Ux2N2b{wRPH`S*xPXhegv+>s>u^18z)gh>HzE!ZL=le| z5|D@_BqIgskRBP3iZo=W>c_jtnx ze8eYw#ut2t@9_h^;v0U%9444z9y2Up5ldLc3f5sgHeeNN*f{kk2tf&+V1z)3gha@M zLg)xRVIWk(1ZE^Uq7aqn4-(LQ0?~+p7>S9PiG|n^d*VQ>#6}!RjwB={d6JO=DUuQ? zlM1OL^`wDRNsTm;9a+dq_GBXmawI2mCKqx??#TnWk{fxXIEqk|;weT6zY_S=KDT9e z-7db=^%lKt&`*`_=XyFL?cvjV@kyTXb$9U1=6k&V{Bid3#4g;!XUEygmi=FtHymfL zPi)~meDMJLw!?SJ{&CJfKiM>|?dtNTEjfLAz6;&{nH)eRcJ1CuOUz_X^}+rFTP29vb2E|M*M~ sWUv0;muI7`KBVol{*!mmkK|+cZ5A^}_s6#07RbSZA0L&&0<;ML09iH+!vFvP diff --git a/openair2/LAYER2/nr_rlc/tests/test8.txt.gz b/openair2/LAYER2/nr_rlc/tests/test8.txt.gz index c20d43c63b331c2de77e0484922c1b0c1957eb7c..461ae1aebad7294daa7445179da725cbe6e722d0 100644 GIT binary patch literal 319 zcmV-F0l@wriwFpCHMC*^19W9`bT}?_cys{Gl1od&P!NUp{T1I*H!?GMG|5sd?%cFp ziIhBUq)(OlYzrDN8(2T~Fn?+l7 zTr4Z(a$B@~b3~GHj|ifOApsI15fUR~BtcRnM+&4wwv7&{Q9%_oG(bZ%LSuA{CTNQ0 zXn~e!g*vpx1XIkg01L4Qi?K15U@4Yk1y*7e=CGPT2=w6xz@vL|O}=)E=c?PgH}mdO z*#Vr+Fi^51N=2{ap-B0K+>n@Uyu5b_T zO$|XpIg(j@uFSkyuT;6!a^o7NH}n36|N9B|){pH)zwPBSRnI8A_o*r^>CC8`m(snfHJAzklIA`mw#}x4nF}>KTQXyru2R(zR{ftyZsn R1+Kapy#sK9u$l1#007C*o1g#y diff --git a/openair2/LAYER2/nr_rlc/tests/test9.txt.gz b/openair2/LAYER2/nr_rlc/tests/test9.txt.gz index 27590b7d71c435e04cd19603d90cc0c9c0798597..938fcd6ddcb9a2bcf4bbd2206725a7c35e2a2b79 100644 GIT binary patch delta 298 zcmV+_0oDGz0=xnUABzYGfi<*Zkq8}sNt-Oi;?7Oml}O3YL<&VDX)5~kc8Y;UYo+2s zn8hsS&iT$aGoQ}p8SN%-Hlz7|e|vYGp&5-Yx68KbxL8%l*WP=`inj3($9ouDb2qXk-`73$F%6HGC~92Q}JF_vIs zY=Wg&julvmRhY+WoZ$4~lfa{Y@=d<+%jc^5NN*O>r?MB2Uuz6Vc7jwKkb?Tz_5+eT zO42lt`~fL6c5Z2l>38?L{=vf<98Ztuk%NJxm+vbG@rG8BoG7sVs{%vdK&t$Dwe=0N wn??Vj|NDRLqyO+W(U(?(qwta$x3pbZ`nIjR_4>81z*kqJcO1rN|Na9207W#H^#A|> delta 298 zcmV+_0oDGz0=xnUABzYG2sNf*kq8}sX`3v?;?7Oml}O3YL;^)5X)5~kc8Y;UYo+2s zn8hsS&iT$avzW~nDeWd}HlxLUe|vYGqA86pwyU=6xTs6ya(AeH^Td*Jj|ifOAr6U< z7#SlIWQrt6hU7?r>;^qjp@J%Es6!((M#ty`ouUbvp*dQhCF;=%6HGC~92Q}JF*e2~ z*c3~!49l?sD>08%IKk<|CxJ)*A3zt$L#>;x%4AO-ca?FS@x zl%z=@`2$jD?A+3pv+wSA{ey=!IG!BOBL@T4%l8$8ctfj5P83-ERe>RJAeDYyZ+*l3 wX4!w}|Nfu*=s&zo^rh9{D7<7DEp1m6zHO^+y?*U0@a5I$9m#xc_x=L_0Q8xU(f|Me From 304c92c6391393a599037888be22cf5f8da415f9 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 23 Jun 2022 13:51:36 +0200 Subject: [PATCH 165/267] Fixes in conversions.h --- openair3/UTILS/conversions.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openair3/UTILS/conversions.h b/openair3/UTILS/conversions.h index a753b8c60d..0361c34f33 100644 --- a/openair3/UTILS/conversions.h +++ b/openair3/UTILS/conversions.h @@ -70,7 +70,7 @@ /* Convert an integer on 16 bits to the given bUFFER */ #define INT16_TO_BUFFER(x, buf) \ do { \ - (buf)[0] = (x >> 8) & 0xff; \ + (buf)[0] = ((x) >> 8) & 0xff; \ (buf)[1] = (x) & 0xff; \ } while(0) @@ -84,8 +84,8 @@ do { \ /* Convert an integer on 24 bits to the given bUFFER */ #define INT24_TO_BUFFER(x, buf) \ do { \ - (buf)[0] = (x >> 16) & 0xff;\ - (buf)[1] = (x >> 8) & 0xff; \ + (buf)[0] = ((x) >> 16) & 0xff;\ + (buf)[1] = ((x) >> 8) & 0xff; \ (buf)[2] = (x) & 0xff; \ } while(0) @@ -101,9 +101,9 @@ do { \ /* Convert an integer on 32 bits to the given bUFFER */ #define INT32_TO_BUFFER(x, buf) \ do { \ - (buf)[0] = (x >> 24) & 0xff;\ - (buf)[1] = (x >> 16) & 0xff;\ - (buf)[2] = (x >> 8) & 0xff; \ + (buf)[0] = ((x) >> 24) & 0xff;\ + (buf)[1] = ((x) >> 16) & 0xff;\ + (buf)[2] = ((x) >> 8) & 0xff; \ (buf)[3] = (x) & 0xff; \ } while(0) From 1a4686b021fac4581383ca0823664dee2867744a Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 23 Jun 2022 14:52:05 +0100 Subject: [PATCH 166/267] Remove UE->Msg4_ACKed from condition in nr_schedule_srs --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index e737fc7107..4be176714e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -124,7 +124,7 @@ void nr_schedule_srs(int module_id, frame_t frame) { sched_ctrl->sched_srs.srs_scheduled = false; if((sched_ctrl->ul_failure == 1 && get_softmodem_params()->phy_test==0) || - !UE->Msg4_ACKed || sched_ctrl->rrc_processing_timer > 0) { + sched_ctrl->rrc_processing_timer > 0) { continue; } From 0e04fba03d8b1d3e28e70d57933809a6f570709c Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 23 Jun 2022 14:49:16 +0200 Subject: [PATCH 167/267] Fix build warnings --- openair1/SIMULATION/NR_PHY/dlsim.c | 2 ++ openair1/SIMULATION/NR_PHY/prachsim.c | 2 ++ openair1/SIMULATION/NR_PHY/ulsim.c | 2 ++ openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.c | 2 +- openair2/RRC/NR/rrc_gNB.c | 1 - 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index fec711bc1b..78b253ca2a 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -243,6 +243,8 @@ int DU_send_INITIAL_UL_RRC_MESSAGE_TRANSFER(module_id_t module_idP, void processSlotTX(void *arg) {} +nr_bler_struct nr_bler_data[NR_NUM_MCS]; + //nFAPI P7 dummy functions to avoid linking errors int oai_nfapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req) { return(0); } diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index 91a8265ff1..33717c944d 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -227,6 +227,8 @@ nrUE_params_t *get_nrUE_params(void) { return &nrUE_params; } +nr_bler_struct nr_bler_data[NR_NUM_MCS]; + void processSlotTX(void *arg) {} int main(int argc, char **argv){ diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 22efa35ef9..ffb168fd68 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -225,6 +225,8 @@ int DU_send_INITIAL_UL_RRC_MESSAGE_TRANSFER(module_id_t module_idP, return 0; } +nr_bler_struct nr_bler_data[NR_NUM_MCS]; + //nFAPI P7 dummy functions int oai_nfapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req) { return(0); } diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.c b/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.c index 41d27bda80..97938c6b02 100644 --- a/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.c +++ b/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.c @@ -55,10 +55,10 @@ void read_channel_param(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t * pdu, int slot, return; } +extern nr_bler_struct nr_bler_data[NR_NUM_MCS]; float get_bler_val(uint8_t mcs, int sinr) { // 4th col = dropped packets, 5th col = total packets - nr_bler_struct nr_bler_data[NR_NUM_MCS]; float bler_val = 0.0; CHECK_INDEX(nr_bler_data, mcs); LOG_D(NR_MAC, "sinr %d min %d max %d\n", sinr, diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 98a373086e..20b79362a0 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1426,7 +1426,6 @@ rrc_gNB_process_RRCReconfigurationComplete( NR_DRB_ToReleaseList_t *DRB_Release_configList2 = ue_context_pP->ue_context.DRB_Release_configList2[xid]; NR_DRB_Identity_t *drb_id_p = NULL; // uint8_t nr_DRB2LCHAN[8]; - gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; ue_context_pP->ue_context.ue_reestablishment_timer = 0; From 15656679087734702d93d84f3dfd0db8d0c8ca86 Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 23 Jun 2022 17:42:55 +0200 Subject: [PATCH 168/267] remove rtx from list --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index dce798f24f..d9a0a50b7e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -398,6 +398,7 @@ bool allocate_dl_retransmission(module_id_t module_id, LOG_W(NR_MAC,"Cannot schedule retransmission. RI changed from %d to %d\n", retInfo->nrOfLayers, ps->nrOfLayers); abort_nr_dl_harq(UE, current_harq_pid); + remove_front_nr_list(&sched_ctrl->retrans_dl_harq); return false; } From 07a3634e4523ceb43c18b29eaa52dd8694615b75 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 23 Jun 2022 18:23:23 +0100 Subject: [PATCH 169/267] Change some heap allocations to stack allocations --- openair1/PHY/INIT/nr_init.c | 14 -------------- openair1/PHY/INIT/nr_init_ue.c | 6 ------ openair1/PHY/defs_nr_common.h | 14 +++++++------- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 8 ++++---- 4 files changed, 11 insertions(+), 31 deletions(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 1f2383c60c..bd349d146a 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -613,13 +613,6 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, for (int id=0; idnr_srs_info[id] = (nr_srs_info_t *)malloc16_clear(sizeof(nr_srs_info_t)); - gNB->nr_srs_info[id]->sc_list = (uint16_t *) malloc16_clear(6*fp->N_RB_UL*sizeof(uint16_t)); - gNB->nr_srs_info[id]->srs_generated_signal = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - gNB->nr_srs_info[id]->signal_power = (uint32_t*)malloc16_clear(sizeof(uint32_t)); - gNB->nr_srs_info[id]->noise_power_per_rb = (uint32_t*)malloc16_clear(fp->N_RB_UL*sizeof(uint32_t)); - gNB->nr_srs_info[id]->noise_power = (uint32_t*)malloc16_clear(sizeof(uint32_t)); - gNB->nr_srs_info[id]->snr_per_rb = (int8_t*)malloc16_clear(fp->N_RB_UL*sizeof(int8_t)); - gNB->nr_srs_info[id]->snr = (int8_t*)malloc16_clear(sizeof(int8_t)); gNB->nr_srs_info[id]->srs_received_signal = (int32_t **)malloc16(Prx*sizeof(int32_t*)); gNB->nr_srs_info[id]->srs_ls_estimated_channel = (int32_t **)malloc16(Prx*sizeof(int32_t*)); gNB->nr_srs_info[id]->srs_estimated_channel_freq = (int32_t **)malloc16(Prx*sizeof(int32_t*)); @@ -796,13 +789,6 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_time[i]); free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_time_shifted[i]); } - free_and_zero(gNB->nr_srs_info[id]->sc_list); - free_and_zero(gNB->nr_srs_info[id]->srs_generated_signal); - free_and_zero(gNB->nr_srs_info[id]->signal_power); - free_and_zero(gNB->nr_srs_info[id]->noise_power_per_rb); - free_and_zero(gNB->nr_srs_info[id]->noise_power); - free_and_zero(gNB->nr_srs_info[id]->snr_per_rb); - free_and_zero(gNB->nr_srs_info[id]->snr); free_and_zero(gNB->nr_srs_info[id]->srs_received_signal); free_and_zero(gNB->nr_srs_info[id]->srs_ls_estimated_channel); free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_freq); diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index c6e6ecd463..254a25097c 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -377,9 +377,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) } ue->nr_srs_info = (nr_srs_info_t *)malloc16_clear(sizeof(nr_srs_info_t)); - ue->nr_srs_info->sc_list = (uint16_t *) malloc16_clear(6*fp->N_RB_UL*sizeof(uint16_t)); - ue->nr_srs_info->srs_generated_signal = (int32_t *) malloc16_clear( (2*(fp->samples_per_frame)+2048)*sizeof(int32_t) ); - ue->nr_srs_info->noise_power = (uint32_t*)malloc16_clear(sizeof(uint32_t)); ue->nr_srs_info->srs_received_signal = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) ); ue->nr_srs_info->srs_ls_estimated_channel = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) ); ue->nr_srs_info->srs_estimated_channel_freq = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) ); @@ -527,9 +524,6 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) free_and_zero(ue->nr_srs_info->srs_estimated_channel_time[i]); free_and_zero(ue->nr_srs_info->srs_estimated_channel_time_shifted[i]); } - free_and_zero(ue->nr_srs_info->sc_list); - free_and_zero(ue->nr_srs_info->srs_generated_signal); - free_and_zero(ue->nr_srs_info->noise_power); free_and_zero(ue->nr_srs_info->srs_received_signal); free_and_zero(ue->nr_srs_info->srs_ls_estimated_channel); free_and_zero(ue->nr_srs_info->srs_estimated_channel_freq); diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 657d05fc6e..fe895d1770 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -241,19 +241,19 @@ typedef struct { typedef struct { uint16_t sc_list_length; - uint16_t *sc_list; + uint16_t sc_list[6*273]; uint8_t srs_generated_signal_bits; - int32_t *srs_generated_signal; + int32_t srs_generated_signal[OFDM_SYMBOL_SIZE_SAMPLES_MAX * MAX_NUM_NR_SRS_SYMBOLS]; int32_t **srs_received_signal; int32_t **srs_ls_estimated_channel; int32_t **srs_estimated_channel_freq; int32_t **srs_estimated_channel_time; int32_t **srs_estimated_channel_time_shifted; - uint32_t *signal_power; - uint32_t *noise_power_per_rb; - uint32_t *noise_power; - int8_t *snr_per_rb; - int8_t *snr; + uint32_t signal_power; + uint32_t noise_power_per_rb[273]; + uint32_t noise_power; + int8_t snr_per_rb[273]; + int8_t snr; } nr_srs_info_t; typedef struct { diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index fb4e5a85ef..56ee0d8db2 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -878,11 +878,11 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->nr_srs_info[i]->srs_estimated_channel_freq, gNB->nr_srs_info[i]->srs_estimated_channel_time, gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted, - gNB->nr_srs_info[i]->signal_power, + &gNB->nr_srs_info[i]->signal_power, gNB->nr_srs_info[i]->noise_power_per_rb, - gNB->nr_srs_info[i]->noise_power, + &gNB->nr_srs_info[i]->noise_power, gNB->nr_srs_info[i]->snr_per_rb, - gNB->nr_srs_info[i]->snr); + &gNB->nr_srs_info[i]->snr); } T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), @@ -900,7 +900,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->srs_pdu_list[num_srs].timing_advance = srs_est >= 0 ? nr_est_timing_advance_srs(&gNB->frame_parms, (const int32_t **)gNB->nr_srs_info[i]->srs_estimated_channel_time) : 0xFFFF; gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; - gNB->srs_pdu_list[num_srs].wide_band_snr = srs_est >= 0 ? (*gNB->nr_srs_info[i]->snr + 64)<<1 : 0xFF; // 0xFF will be set if this field is invalid + gNB->srs_pdu_list[num_srs].wide_band_snr = srs_est >= 0 ? (gNB->nr_srs_info[i]->snr + 64)<<1 : 0xFF; // 0xFF will be set if this field is invalid gNB->srs_pdu_list[num_srs].num_reported_symbols = 1<num_symbols; if(!gNB->srs_pdu_list[num_srs].reported_symbol_list) { gNB->srs_pdu_list[num_srs].reported_symbol_list = (nfapi_nr_srs_indication_reported_symbol_t*) calloc(1, gNB->srs_pdu_list[num_srs].num_reported_symbols*sizeof(nfapi_nr_srs_indication_reported_symbol_t)); From c5b8fa5418bceb033a5fa02a758a8760b8dd0e95 Mon Sep 17 00:00:00 2001 From: Ilario FAVERO Date: Thu, 9 Jun 2022 12:53:44 +0200 Subject: [PATCH 170/267] New command line arg for disabling stats: --disable-stats --- executables/nr-gnb.c | 2 +- executables/nr-ue.c | 6 ++++-- executables/softmodem-common.c | 3 +++ executables/softmodem-common.h | 4 ++++ openair2/LAYER2/NR_MAC_gNB/main.c | 4 ++-- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 327c01af6a..bc3dccf4fa 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -466,7 +466,7 @@ void init_gNB_Tpool(int inst) { pushNotifiedFIFO(gNB->L1_tx_free,msgL1Tx); // to unblock the process in the beginning } - if (!get_softmodem_params()->emulate_l1) + if ((!get_softmodem_params()->emulate_l1) && (!IS_SOFTMODEM_NOSTATS_BIT)) threadCreate(&proc->L1_stats_thread,nrL1_stats_thread,(void*)gNB,"L1_stats",-1,OAI_PRIORITY_RT_LOW); threadCreate(&proc->pthread_tx_reorder, tx_reorder_thread, (void *)gNB, "thread_tx_reorder", -1, OAI_PRIORITY_RT_MAX); diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 01e6c62138..7b39dfdcaa 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -1109,8 +1109,10 @@ void init_NR_UE_threads(int nb_inst) { LOG_I(PHY,"Intializing UE Threads for instance %d (%p,%p)...\n",inst,PHY_vars_UE_g[inst],PHY_vars_UE_g[inst][0]); threadCreate(&threads[inst], UE_thread, (void *)UE, "UEthread", -1, OAI_PRIORITY_RT_MAX); - pthread_t stat_pthread; - threadCreate(&stat_pthread, nrL1_UE_stats_thread, UE, "L1_UE_stats", -1, OAI_PRIORITY_RT_LOW); + if (!IS_SOFTMODEM_NOSTATS_BIT) { + pthread_t stat_pthread; + threadCreate(&stat_pthread, nrL1_UE_stats_thread, UE, "L1_UE_stats", -1, OAI_PRIORITY_RT_LOW); + } } } diff --git a/executables/softmodem-common.c b/executables/softmodem-common.c index c78fc70243..bf30cab847 100644 --- a/executables/softmodem-common.c +++ b/executables/softmodem-common.c @@ -85,6 +85,7 @@ char *get_softmodem_function(uint64_t *sofmodemfunc_mask_ptr) { } void get_common_options(uint32_t execmask) { + int32_t stats_disabled = 0; uint32_t online_log_messages=0; uint32_t glog_level=0 ; uint32_t start_telnetsrv = 0, start_telnetclt = 0; @@ -149,6 +150,8 @@ void get_common_options(uint32_t execmask) { if(worker_config != NULL) set_worker_conf(worker_config); nfapi_setmode(nfapi_mode); + if (stats_disabled) + set_softmodem_optmask(SOFTMODEM_NOSTATS_BIT); } void softmodem_printresources(int sig, telnet_printfunc_t pf) { struct rusage usage; diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h index 0310453ca0..a2ba680234 100644 --- a/executables/softmodem-common.h +++ b/executables/softmodem-common.h @@ -101,6 +101,7 @@ extern "C" #define CONFIG_HLP_NFAPI "Change the nFAPI mode for NR\n" #define CONFIG_L1_EMULATOR "Run in L1 emulated mode (disable PHY layer)\n" #define CONFIG_HLP_CONTINUOUS_TX "perform continuous transmission, even in TDD mode (to work around USRP issues)\n" +#define CONFIG_HLP_STATS_DISABLE "disable globally the stats generation and persistence" /*-----------------------------------------------------------------------------------------------------------------------------------------------------*/ /* command line parameters common to eNodeB and UE */ @@ -171,6 +172,7 @@ extern int usrp_tx_thread; {"non-stop", CONFIG_HLP_NONSTOP, PARAMFLAG_BOOL, iptr:&NON_STOP, defintval:0, TYPE_INT, 0}, \ {"emulate-l1", CONFIG_L1_EMULATOR, PARAMFLAG_BOOL, iptr:&EMULATE_L1, defintval:0, TYPE_INT, 0}, \ {"continuous-tx", CONFIG_HLP_CONTINUOUS_TX,PARAMFLAG_BOOL, iptr:&CONTINUOUS_TX, defintval:0, TYPE_INT, 0}, \ + {"disable-stats", CONFIG_HLP_STATS_DISABLE, PARAMFLAG_BOOL, iptr:&stats_disabled, defintval:0, TYPE_INT, 0}, \ } #define CONFIG_HLP_NSA "Enable NSA mode \n" @@ -217,6 +219,7 @@ extern int usrp_tx_thread; #define SOFTMODEM_GNB_BIT (1<<21) #define SOFTMODEM_4GUE_BIT (1<<22) #define SOFTMODEM_5GUE_BIT (1<<23) +#define SOFTMODEM_NOSTATS_BIT (1<<24) #define SOFTMODEM_FUNC_BITS (SOFTMODEM_ENB_BIT | SOFTMODEM_GNB_BIT | SOFTMODEM_5GUE_BIT | SOFTMODEM_4GUE_BIT) #define MAPPING_SOFTMODEM_FUNCTIONS {{"enb",SOFTMODEM_ENB_BIT},{"gnb",SOFTMODEM_GNB_BIT},{"4Gue",SOFTMODEM_4GUE_BIT},{"5Gue",SOFTMODEM_5GUE_BIT}} @@ -234,6 +237,7 @@ extern int usrp_tx_thread; #define IS_SOFTMODEM_GNB_BIT ( get_softmodem_optmask() & SOFTMODEM_GNB_BIT) #define IS_SOFTMODEM_4GUE_BIT ( get_softmodem_optmask() & SOFTMODEM_4GUE_BIT) #define IS_SOFTMODEM_5GUE_BIT ( get_softmodem_optmask() & SOFTMODEM_5GUE_BIT) +#define IS_SOFTMODEM_NOSTATS_BIT ( get_softmodem_optmask() & SOFTMODEM_NOSTATS_BIT) typedef struct { uint64_t optmask; diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 9b9fd4e76c..c05af4d4a8 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -211,8 +211,8 @@ void mac_top_init_gNB(void) RC.nrmac[i]->pre_processor_dl = nr_init_fr1_dlsch_preprocessor(i, 0); RC.nrmac[i]->pre_processor_ul = nr_init_fr1_ulsch_preprocessor(i, 0); } - pthread_create(&RC.nrmac[i]->stats_thread,NULL,nrmac_stats_thread,(void*)RC.nrmac[i]); - + if (!IS_SOFTMODEM_NOSTATS_BIT) + pthread_create(&RC.nrmac[i]->stats_thread, NULL, nrmac_stats_thread, (void*)RC.nrmac[i]); }//END for (i = 0; i < RC.nb_nr_macrlc_inst; i++) AssertFatal(rlc_module_init(1) == 0,"Could not initialize RLC layer\n"); From a9faf533b4c0d264e3ed22c24a010bce857e2d0d Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Fri, 24 Jun 2022 14:29:35 +0100 Subject: [PATCH 171/267] Fix SA with COTS UE in monolithic mode after merge --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 5 ----- openair2/RRC/NR/L2_nr_interface.c | 8 -------- openair2/RRC/NR/nr_rrc_proto.h | 6 ------ openair2/RRC/NR/rrc_gNB.c | 10 +++++----- 4 files changed, 5 insertions(+), 24 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index b87edc9926..6daa68afed 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1530,11 +1530,6 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra if (ra->Msg4_frame == frameP && ra->Msg4_slot == slotP ) { - if (nr_mac_rrc_check_RRCSetup(module_idP, ra->rnti) <= 0){ - ra->Msg4_frame++; - return; - } - uint8_t time_domain_assignment = 0; uint8_t mcsIndex = 0; diff --git a/openair2/RRC/NR/L2_nr_interface.c b/openair2/RRC/NR/L2_nr_interface.c index 7d315bf766..161d1cd847 100644 --- a/openair2/RRC/NR/L2_nr_interface.c +++ b/openair2/RRC/NR/L2_nr_interface.c @@ -306,14 +306,6 @@ int8_t nr_mac_rrc_bwp_switch_req(const module_id_t module_idP, return 0; } -int8_t nr_mac_rrc_check_RRCSetup(const module_id_t Mod_idP, - const rnti_t rnti) { - struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[Mod_idP], rnti); - char payload_size = ue_context_p->ue_context.Srb0.Tx_buffer.payload_size; - return payload_size; - -} - int8_t nr_mac_rrc_data_ind(const module_id_t module_idP, const int CC_id, const frame_t frameP, diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 40de8b8049..d569b91aa8 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -163,12 +163,6 @@ nr_rrc_data_req( const pdcp_transmission_mode_t modeP ); -int8_t nr_mac_rrc_check_RRCSetup( - const module_id_t Mod_idP, - const rnti_t rnti - -); - int nr_rrc_mac_remove_ue(module_id_t mod_idP, rnti_t rntiP); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 20b79362a0..3d95081336 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -600,8 +600,7 @@ rrc_gNB_process_RRCSetupComplete( void rrc_gNB_generate_defaultRRCReconfiguration( const protocol_ctxt_t *const ctxt_pP, - rrc_gNB_ue_context_t *ue_context_pP, - NR_CellGroupConfig_t *cellGroupConfig + rrc_gNB_ue_context_t *ue_context_pP ) //----------------------------------------------------------------------------- { @@ -716,6 +715,7 @@ rrc_gNB_generate_defaultRRCReconfiguration( } gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; + gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; memset(buffer, 0, sizeof(buffer)); size = do_RRCReconfiguration(ctxt_pP, buffer, sizeof(buffer), xid, @@ -730,7 +730,7 @@ rrc_gNB_generate_defaultRRCReconfiguration( &rrc->carrier, &rrc->configuration, NULL, - cellGroupConfig); + ue_p->masterCellGroup); free(ue_context_pP->ue_context.nas_pdu.buffer); @@ -2778,7 +2778,7 @@ rrc_gNB_decode_dcch( if (ue_context_p->ue_context.established_pdu_sessions_flag == 1) { rrc_gNB_generate_dedicatedRRCReconfiguration(ctxt_pP, ue_context_p, NULL); } else { - rrc_gNB_generate_defaultRRCReconfiguration(ctxt_pP, ue_context_p, NULL); + rrc_gNB_generate_defaultRRCReconfiguration(ctxt_pP, ue_context_p); } } else{ @@ -3711,7 +3711,7 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, const ch if (ue_context_p->ue_context.established_pdu_sessions_flag == 1) { rrc_gNB_generate_dedicatedRRCReconfiguration(&ctxt, ue_context_p, cellGroupConfig); } else { - rrc_gNB_generate_defaultRRCReconfiguration(&ctxt, ue_context_p, NULL); + rrc_gNB_generate_defaultRRCReconfiguration(&ctxt, ue_context_p); } free(cellGroupConfig->rlc_BearerToAddModList); From 0b91791f674376c97d70c52fe0a2efa7e8798d80 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 24 Jun 2022 17:53:20 +0200 Subject: [PATCH 172/267] Use (std) bool instead of custom bool types OAI is riddled with boolean_t, FALSE, TRUE, etc. This makes no sense, as there is a standard bool type, and could lead to nasty bugs if a definition of a bool is non-standard (0 == false, true == !false). This commit removes all non-standard bools in the whole project. --- nfapi/oai_integration/nfapi_vnf.c | 4 +- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 4 +- openair1/PHY/LTE_TRANSPORT/defs_NB_IoT.h | 2 +- .../PHY/NR_UE_TRANSPORT/nr_transport_ue.h | 2 +- openair1/PHY/TOOLS/calibration_scope.c | 4 +- openair1/PHY/TOOLS/nr_phy_scope.c | 4 +- openair1/PHY/defs_common.h | 6 +- openair1/SCHED_UE/phy_procedures_lte_ue.c | 2 +- .../NR_UE_PHY/unit_tests/src/pucch_uci_test.c | 96 ++++---- openair2/COMMON/commonDef.h | 21 -- openair2/COMMON/mac_rlc_primitives.h | 2 +- openair2/COMMON/platform_types.h | 61 ++--- openair2/ENB_APP/enb_config.c | 38 ++-- openair2/ENB_APP/enb_config_eMTC.c | 70 +++--- openair2/ENB_APP/flexran_agent_ran_api.c | 8 +- openair2/F1AP/dummy_enb.c | 26 +-- openair2/F1AP/f1ap_common.h | 7 - openair2/F1AP/f1ap_du_rrc_message_transfer.c | 18 +- openair2/F1AP/f1ap_du_ue_context_management.c | 24 +- openair2/LAYER2/MAC/config.c | 14 +- openair2/LAYER2/MAC/defs_NB_IoT.h | 11 +- openair2/LAYER2/MAC/eNB_scheduler.c | 44 ++-- openair2/LAYER2/MAC/eNB_scheduler_RA.c | 2 +- openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 2 +- openair2/LAYER2/MAC/eNB_scheduler_fairRR.c | 24 +- .../LAYER2/MAC/eNB_scheduler_primitives.c | 24 +- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 8 +- openair2/LAYER2/MAC/mac.h | 34 +-- openair2/LAYER2/MAC/mac_extern.h | 2 +- openair2/LAYER2/MAC/mac_proto.h | 17 +- openair2/LAYER2/MAC/pre_processor.c | 2 +- openair2/LAYER2/MAC/ue_procedures.c | 28 +-- openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h | 2 +- openair2/LAYER2/NR_MAC_UE/config_ue.c | 2 +- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 4 +- openair2/LAYER2/NR_MAC_UE/mac_proto.h | 18 +- openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c | 2 +- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 14 +- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 14 +- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 1 - openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 208 +++++++++--------- openair2/LAYER2/PDCP_v10.1.0/pdcp.h | 121 +++++----- .../LAYER2/PDCP_v10.1.0/pdcp_primitives.c | 33 +-- .../LAYER2/PDCP_v10.1.0/pdcp_primitives.h | 19 +- .../PDCP_v10.1.0/pdcp_sequence_manager.c | 36 +-- .../PDCP_v10.1.0/pdcp_sequence_manager.h | 16 +- openair2/LAYER2/PDCP_v10.1.0/pdcp_util.c | 6 +- openair2/LAYER2/PDCP_v10.1.0/pdcp_util.h | 4 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c | 2 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h | 8 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c | 10 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c | 10 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h | 4 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c | 2 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c | 82 ++++--- .../LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h | 24 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c | 35 ++- .../LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h | 6 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c | 11 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h | 4 +- .../RLC/AM_v9.3.0/rlc_am_status_report.c | 16 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.c | 2 +- .../AM_v9.3.0/rlc_am_timer_poll_retransmit.c | 2 +- openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.c | 12 +- openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.h | 13 +- openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_entity.h | 7 +- openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c | 7 +- openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h | 17 +- .../RLC/UM_v9.3.0/rlc_um_control_primitives.c | 2 +- openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_entity.h | 11 +- openair2/LAYER2/RLC/rlc.c | 15 +- openair2/LAYER2/RLC/rlc.h | 2 +- openair2/LAYER2/RLC/rlc_mac.c | 4 +- openair2/LAYER2/RLC/rlc_rrc.c | 10 +- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 146 ++++++------ openair2/M2AP/m2ap_common.h | 5 - openair2/RRC/LITE/rrc_common.c | 2 +- openair2/RRC/LTE/L2_interface.c | 2 +- openair2/RRC/LTE/L2_interface_common.c | 4 +- openair2/RRC/LTE/L2_interface_ue.c | 2 +- openair2/RRC/LTE/MESSAGES/asn1_msg.c | 12 +- openair2/RRC/LTE/defs_NB_IoT.h | 2 +- openair2/RRC/LTE/rrc_UE.c | 9 +- openair2/RRC/LTE/rrc_defs.h | 4 +- openair2/RRC/LTE/rrc_eNB.c | 65 +++--- openair2/RRC/LTE/rrc_eNB_GTPV1U.c | 48 ++-- openair2/RRC/LTE/rrc_eNB_GTPV1U.h | 19 +- openair2/RRC/LTE/rrc_eNB_S1AP.c | 52 +++-- openair2/RRC/LTE/rrc_proto.h | 4 +- openair2/RRC/NR/L2_nr_interface.c | 6 +- openair2/RRC/NR/nr_rrc_defs.h | 2 +- openair2/RRC/NR/nr_rrc_proto.h | 47 ++-- openair2/RRC/NR/rrc_gNB.c | 41 ++-- openair2/RRC/NR/rrc_gNB_NGAP.c | 24 +- openair2/RRC/NR_UE/L2_interface_ue.c | 2 +- openair2/RRC/NR_UE/rrc_UE.c | 2 +- openair2/SDAP/nr_sdap/nr_sdap.c | 52 ++--- openair2/SDAP/nr_sdap/nr_sdap.h | 27 ++- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 33 ++- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 35 ++- openair2/X2AP/x2ap_common.h | 5 - openair3/M3AP/m3ap_common.h | 5 - openair3/NAS/COMMON/UTIL/nas_timer.c | 20 +- openair3/NAS/COMMON/UTIL/socket.c | 8 +- openair3/NAS/COMMON/UTIL/stty.c | 14 +- openair3/NAS/TEST/AS_SIMULATOR/as_simulator.c | 16 +- openair3/NAS/TEST/NETWORK/network_simulator.c | 8 +- openair3/NAS/TEST/USER/user_simulator.c | 4 +- openair3/NAS/UE/API/USER/at_command.c | 18 +- openair3/NAS/UE/API/USER/at_error.c | 6 +- openair3/NAS/UE/API/USER/at_response.c | 6 +- openair3/NAS/UE/EMM/Attach.c | 36 +-- openair3/NAS/UE/EMM/Authentication.c | 12 +- openair3/NAS/UE/EMM/Detach.c | 9 +- openair3/NAS/UE/EMM/EmmStatusHdl.c | 3 +- openair3/NAS/UE/EMM/Identification.c | 3 +- openair3/NAS/UE/EMM/IdleMode.c | 28 +-- openair3/NAS/UE/EMM/LowerLayer.c | 8 +- openair3/NAS/UE/EMM/LowerLayer.h | 2 +- openair3/NAS/UE/EMM/LowerLayer_defs.h | 2 +- .../SAP/EmmDeregisteredAttemptingToAttach.c | 2 +- .../EMM/SAP/EmmDeregisteredLimitedService.c | 2 +- .../UE/EMM/SAP/EmmDeregisteredNormalService.c | 2 +- openair3/NAS/UE/EMM/SAP/EmmRegistered.c | 2 +- .../NAS/UE/EMM/SAP/EmmRegisteredInitiated.c | 2 +- openair3/NAS/UE/EMM/SAP/emm_as.c | 6 +- openair3/NAS/UE/EMM/SAP/emm_asDef.h | 4 +- openair3/NAS/UE/EMM/SAP/emm_esmDef.h | 4 +- openair3/NAS/UE/EMM/SAP/emm_regDef.h | 4 +- openair3/NAS/UE/EMM/SecurityModeControl.c | 8 +- openair3/NAS/UE/EMM/emmData.h | 6 +- openair3/NAS/UE/EMM/emm_main.c | 36 +-- openair3/NAS/UE/EMM/emm_main.h | 4 +- openair3/NAS/UE/EMM/emm_proc.h | 6 +- .../ESM/DedicatedEpsBearerContextActivation.c | 18 +- .../ESM/DefaultEpsBearerContextActivation.c | 22 +- .../NAS/UE/ESM/EpsBearerContextDeactivation.c | 20 +- openair3/NAS/UE/ESM/EsmStatusHdl.c | 6 +- openair3/NAS/UE/ESM/PdnConnectivity.c | 28 +-- openair3/NAS/UE/ESM/PdnDisconnect.c | 10 +- openair3/NAS/UE/ESM/SAP/esm_sap.c | 40 ++-- openair3/NAS/UE/ESM/SAP/esm_sapDef.h | 6 +- openair3/NAS/UE/ESM/SAP/esm_send.c | 2 +- openair3/NAS/UE/ESM/SAP/esm_send.h | 4 +- openair3/NAS/UE/ESM/esmData.h | 9 +- openair3/NAS/UE/ESM/esm_ebr.c | 17 +- openair3/NAS/UE/ESM/esm_ebr.h | 8 +- openair3/NAS/UE/ESM/esm_ebr_context.c | 26 +-- openair3/NAS/UE/ESM/esm_ebr_context.h | 2 +- openair3/NAS/UE/ESM/esm_main.c | 28 +-- openair3/NAS/UE/ESM/esm_main.h | 7 +- openair3/NAS/UE/ESM/esm_proc.h | 37 ++-- openair3/NAS/UE/ESM/esm_pt.c | 8 +- openair3/NAS/UE/ESM/esm_pt.h | 4 +- openair3/NAS/UE/UEprocess.c | 4 +- openair3/NAS/UE/nas_proc.c | 80 +++---- openair3/NAS/UE/nas_proc.h | 8 +- openair3/NAS/UE/nas_proc_defs.h | 4 +- openair3/NAS/UE/nas_ue_task.c | 6 +- openair3/NAS/UE/nas_user.c | 22 +- openair3/NAS/UE/nas_user.h | 2 +- openair3/NGAP/ngap_common.h | 7 - openair3/S1AP/s1ap_common.h | 7 - openair3/S1AP/s1ap_eNB_trace.c | 2 +- openair3/ocp-gtpu/gtp_itf.cpp | 4 +- openair3/ocp-gtpu/gtp_itf.h | 48 ++-- targets/ARCH/COMMON/common_lib.h | 4 +- targets/ARCH/IRIS/USERSPACE/LIB/iris_lib.cpp | 2 +- targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp | 6 +- targets/ARCH/iqplayer/iqplayer_lib.c | 2 +- targets/ARCH/rfsimulator/stored_node.c | 2 +- targets/RT/USER/lte-enb.c | 4 +- targets/RT/USER/lte-ru.c | 2 +- targets/TEST/PDCP/test_pdcp.c | 66 +++--- targets/TEST/PDCP/test_pdcp.h | 14 +- targets/TEST/PDCP/with_rlc/test_pdcp_rlc.c | 12 +- 176 files changed, 1414 insertions(+), 1573 deletions(-) diff --git a/nfapi/oai_integration/nfapi_vnf.c b/nfapi/oai_integration/nfapi_vnf.c index d13dc5d1c5..8cc1bda782 100644 --- a/nfapi/oai_integration/nfapi_vnf.c +++ b/nfapi/oai_integration/nfapi_vnf.c @@ -217,7 +217,7 @@ void oai_create_enb(void) { } // This will cause phy_config_request to be installed. That will result in RRC configuring the PHY - // that will result in eNB->configured being set to TRUE. + // that will result in eNB->configured being set to true. // See we need to wait for that to happen otherwise the NFAPI message exchanges won't contain the right parameter values if (RC.eNB[0][0]->if_inst==0 || RC.eNB[0][0]->if_inst->PHY_config_req==0 || RC.eNB[0][0]->if_inst->schedule_response==0) { NFAPI_TRACE(NFAPI_TRACE_INFO, "RC.eNB[0][0]->if_inst->PHY_config_req is not installed - install it\n"); @@ -267,7 +267,7 @@ void oai_create_gnb(void) { // This will cause phy_config_request to be installed. That will result in RRC configuring the PHY - // that will result in gNB->configured being set to TRUE. + // that will result in gNB->configured being set to true. // See we need to wait for that to happen otherwise the NFAPI message exchanges won't contain the right parameter values if (RC.gNB[0]->if_inst==0 || RC.gNB[0]->if_inst->NR_PHY_config_req==0 || RC.gNB[0]->if_inst->NR_Schedule_response==0) { NFAPI_TRACE(NFAPI_TRACE_INFO, "RC.gNB[0][0]->if_inst->NR_PHY_config_req is not installed - install it\n"); diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 1bbe9eb39a..dc73a56568 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -1997,7 +1997,7 @@ int get_narrowband_index(int N_RB_UL,int rb) { void fill_ulsch(PHY_VARS_eNB *eNB,int UE_id,nfapi_ul_config_ulsch_pdu *ulsch_pdu,int frame,int subframe) { uint8_t harq_pid; //uint8_t UE_id; - boolean_t new_ulsch = (find_ulsch(ulsch_pdu->ulsch_pdu_rel8.rnti,eNB,SEARCH_EXIST)==-1) ? TRUE : FALSE; + const bool new_ulsch = find_ulsch(ulsch_pdu->ulsch_pdu_rel8.rnti,eNB,SEARCH_EXIST) == -1; //AssertFatal((UE_id=find_ulsch(ulsch_pdu->ulsch_pdu_rel8.rnti,eNB,SEARCH_EXIST_OR_FREE))>=0, // "No existing/free UE ULSCH for rnti %x\n",ulsch_pdu->ulsch_pdu_rel8.rnti); LTE_eNB_ULSCH_t *ulsch=eNB->ulsch[UE_id]; @@ -2063,7 +2063,7 @@ void fill_ulsch(PHY_VARS_eNB *eNB,int UE_id,nfapi_ul_config_ulsch_pdu *ulsch_pdu if ((ulsch->harq_processes[harq_pid]->status == SCH_IDLE) || (ulsch->harq_processes[harq_pid]->ndi != ulsch_pdu->ulsch_pdu_rel8.new_data_indication) || - (new_ulsch == TRUE)) { + (new_ulsch == true)) { ulsch->harq_processes[harq_pid]->status = ACTIVE; ulsch->harq_processes[harq_pid]->TBS = ulsch_pdu->ulsch_pdu_rel8.size<<3; ulsch->harq_processes[harq_pid]->Msc_initial = 12*ulsch_pdu->ulsch_pdu_rel8.number_of_resource_blocks; diff --git a/openair1/PHY/LTE_TRANSPORT/defs_NB_IoT.h b/openair1/PHY/LTE_TRANSPORT/defs_NB_IoT.h index 3574ba6740..d90216c3e6 100644 --- a/openair1/PHY/LTE_TRANSPORT/defs_NB_IoT.h +++ b/openair1/PHY/LTE_TRANSPORT/defs_NB_IoT.h @@ -509,7 +509,7 @@ typedef struct { /// Position of first CCE of the dci int firstCCE; /// flag to indicate that this is a RA response - boolean_t ra_flag; + bool ra_flag; /// rnti rnti_t rnti; /// Format diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h index 7ecba40c3a..fd8eada245 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h @@ -342,7 +342,7 @@ typedef struct { /// Position of first CCE of the dci int firstCCE; /// flag to indicate that this is a RA response - boolean_t ra_flag; + bool ra_flag; /// rnti rnti_t rnti; /// rnti type diff --git a/openair1/PHY/TOOLS/calibration_scope.c b/openair1/PHY/TOOLS/calibration_scope.c index da1acb5175..d3397b033f 100644 --- a/openair1/PHY/TOOLS/calibration_scope.c +++ b/openair1/PHY/TOOLS/calibration_scope.c @@ -34,7 +34,7 @@ typedef struct OAIgraph { int h; int waterFallh; double *waterFallAvg; - boolean_t initDone; + bool initDone; int iteration; void (*funct) (struct OAIgraph *graph, calibData_t *); } OAIgraph_t; @@ -159,7 +159,7 @@ static void oai_xygraph_getbuff(OAIgraph_t *graph, float **x, float **y, int len *y=old_y; } -static void oai_xygraph(OAIgraph_t *graph, float *x, float *y, int len, int layer, boolean_t NoAutoScale) { +static void oai_xygraph(OAIgraph_t *graph, float *x, float *y, int len, int layer, bool NoAutoScale) { fl_redraw_object(graph->graph); if ( NoAutoScale && graph->iteration%NoAutoScale == 0) { diff --git a/openair1/PHY/TOOLS/nr_phy_scope.c b/openair1/PHY/TOOLS/nr_phy_scope.c index 723813fbb6..d4b28361d2 100644 --- a/openair1/PHY/TOOLS/nr_phy_scope.c +++ b/openair1/PHY/TOOLS/nr_phy_scope.c @@ -60,7 +60,7 @@ typedef struct OAIgraph { int h; int waterFallh; double *waterFallAvg; - boolean_t initDone; + bool initDone; int iteration; void (*gNBfunct) (struct OAIgraph *graph, scopeData_t *p, int UE_id); void (*nrUEfunct)(scopeGraphData_t **data, struct OAIgraph *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id); @@ -208,7 +208,7 @@ static void oai_xygraph_getbuff(OAIgraph_t *graph, float **x, float **y, int len *y=old_y; } -static void oai_xygraph(OAIgraph_t *graph, float *x, float *y, int len, int layer, boolean_t NoAutoScale) { +static void oai_xygraph(OAIgraph_t *graph, float *x, float *y, int len, int layer, bool NoAutoScale) { fl_redraw_object(graph->graph); if ( NoAutoScale && graph->iteration%NoAutoScale == 0) { diff --git a/openair1/PHY/defs_common.h b/openair1/PHY/defs_common.h index 47e17cc935..c93e3a7de9 100644 --- a/openair1/PHY/defs_common.h +++ b/openair1/PHY/defs_common.h @@ -754,7 +754,7 @@ typedef struct { /// Position of first CCE of the dci int firstCCE; /// flag to indicate that this is a RA response - boolean_t ra_flag; + bool ra_flag; /// rnti rnti_t rnti; /// harq_pid @@ -775,7 +775,7 @@ typedef struct { /// Position of first CCE of the dci int firstCCE; /// flag to indicate that this is a RA response - boolean_t ra_flag; + bool ra_flag; /// rnti rnti_t rnti; /// Format @@ -806,7 +806,7 @@ typedef struct { /// Position of first CCE of the dci int firstCCE; /// flag to indicate that this is a RA response - boolean_t ra_flag; + bool ra_flag; /// rnti rnti_t rnti; /// Format diff --git a/openair1/SCHED_UE/phy_procedures_lte_ue.c b/openair1/SCHED_UE/phy_procedures_lte_ue.c index aa0ff0db80..cdf4cf39f9 100644 --- a/openair1/SCHED_UE/phy_procedures_lte_ue.c +++ b/openair1/SCHED_UE/phy_procedures_lte_ue.c @@ -460,7 +460,7 @@ void ue_compute_srs_occasion(PHY_VARS_UE *ue, is_pucch2_subframe = (is_ri_TXOp(ue,proc,eNB_id) && (ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.ri_ConfigIndex>0)) || is_pucch2_subframe; // check ACK/SR transmission - if(frame_parms->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission == FALSE) { + if(frame_parms->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission == false) { if(is_SR_TXOp(ue,proc,eNB_id)) { uint32_t SR_payload = 0; diff --git a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pucch_uci_test.c b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pucch_uci_test.c index 31fe15a6de..12d50065fa 100644 --- a/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pucch_uci_test.c +++ b/openair1/SIMULATION/NR_UE_PHY/unit_tests/src/pucch_uci_test.c @@ -165,7 +165,7 @@ void common_pucch_configuration(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int pucch_in int test_pucch_basic_error(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *proc) { int v_return = 0; - bool reset_harq = FALSE; + bool reset_harq = false; printf("%s", tst_separator); @@ -175,7 +175,7 @@ int test_pucch_basic_error(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *pr common_pucch_configuration(ue, gNB_id, TST_PUCCH_COMMON_CONFIG_INDEX_KO); - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != FALSE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != false) { v_return = -1; } @@ -186,7 +186,7 @@ int test_pucch_basic_error(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *pr printf("\n => Test : Error due to acknownlegment not set \n"); - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != FALSE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != false) { v_return = -1; } @@ -194,7 +194,7 @@ int test_pucch_basic_error(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *pr printf("\n => Test : Error due to DAI not set \n"); - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != FALSE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != false) { v_return = -1; } @@ -202,7 +202,7 @@ int test_pucch_basic_error(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *pr harq_status->vDAI_DL = NR_DL_MAX_DAI + 1; - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != FALSE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != false) { v_return = -1; } @@ -210,7 +210,7 @@ int test_pucch_basic_error(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *pr harq_status->vDAI_DL = 0; - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != FALSE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != false) { v_return = -1; } @@ -218,7 +218,7 @@ int test_pucch_basic_error(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *pr harq_status->send_harq_status = 1; /* ack ready to be send */ - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != FALSE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != false) { v_return = -1; } @@ -228,7 +228,7 @@ int test_pucch_basic_error(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *pr harq_status->vDAI_DL = 1; - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != FALSE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != false) { v_return = -1; } @@ -236,7 +236,7 @@ int test_pucch_basic_error(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *pr printf("\n => Test : Error due to PUCCH format with multiple cells not already implemented \n"); - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != FALSE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != false) { v_return = -1; } @@ -260,7 +260,7 @@ int test_pucch_basic_error(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *pr int test_pucch_common_config_single_transport_block(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *proc) { int v_return = 0; - bool reset_harq = FALSE; + bool reset_harq = false; printf("%s", tst_separator); @@ -273,7 +273,7 @@ int test_pucch_common_config_single_transport_block(PHY_VARS_NR_UE *ue, int gNB_ printf("\n => Test : PUCCH format from common config in prach mode: one positive downlink ACKnowledgment \n"); - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { v_return = -1; } @@ -281,7 +281,7 @@ int test_pucch_common_config_single_transport_block(PHY_VARS_NR_UE *ue, int gNB_ printf("\n => Test : PUCCH format from common config in prach mode: one negative downlink ACKnowledgment \n"); - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { v_return = -1; } @@ -304,7 +304,7 @@ int test_pucch_common_config_single_transport_block(PHY_VARS_NR_UE *ue, int gNB_ printf("\n => Test : PUCCH format from common config in dedicated mode: two positive downlink ACKnowledgments \n"); - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { v_return = -1; } @@ -312,7 +312,7 @@ int test_pucch_common_config_single_transport_block(PHY_VARS_NR_UE *ue, int gNB_ printf("\n => Test : PUCCH format from common config in dedicated mode: one positive and one negative downlink ACKnowledgments \n"); - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { v_return = -1; } @@ -320,22 +320,22 @@ int test_pucch_common_config_single_transport_block(PHY_VARS_NR_UE *ue, int gNB_ printf("\n => Test : PUCCH format from common config in dedicated mode: two negative downlink ACKnowledgments \n"); - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { v_return = -1; } harq_status->ack = DL_ACK; - reset_harq = TRUE; + reset_harq = true; printf("\n => Test : PUCCH format from common config in dedicated mode: no resource is found \n"); - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != FALSE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != false) { v_return = -1; } printf("\n => Test : PUCCH format from common config in dedicated mode: no PUCCH after reset of pending harq ACKnowledgments \n"); - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != FALSE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != false) { v_return = -1; } @@ -362,7 +362,7 @@ void init_pucch_dedicated_configuration(PHY_VARS_NR_UE *ue, uint8_t gNB_id) int i,j; /* set cell group parameters which are supported */ - ue->cell_group_config.physicalCellGroupConfig.harq_ACK_SpatialBundlingPUCCH = FALSE; + ue->cell_group_config.physicalCellGroupConfig.harq_ACK_SpatialBundlingPUCCH = false; ue->cell_group_config.physicalCellGroupConfig.pdsch_HARQ_ACK_Codebook = dynamic; ue->PDSCH_ServingCellConfig.codeBlockGroupTransmission = NULL; @@ -554,7 +554,7 @@ int test_pucch_dedicated_single_transport_block(PHY_VARS_NR_UE *ue, int gNB_id, #define TST_NB_STEP_SINGLE_TRANSPORT_BLOCK (4) int v_return = 0; - int reset_harq = FALSE; + int reset_harq = false; int dl_harq_pid[TST_NB_STEP_SINGLE_TRANSPORT_BLOCK] = {TST_DL_HARQ_PID_FIRST, TST_DL_HARQ_PID_SECOND, TST_DL_HARQ_PID_THIRD, TST_DL_HARQ_PID_FOURTH }; int pucch_resource_indicator[TST_NB_STEP_SINGLE_TRANSPORT_BLOCK][2] = { { 0, 4 }, { 1, 0 } , { 1, 3 } , { 5, 7 } }; NR_UE_HARQ_STATUS_t *harq_status; @@ -575,7 +575,7 @@ int test_pucch_dedicated_single_transport_block(PHY_VARS_NR_UE *ue, int gNB_id, printf("\n => Test : PUCCH format from dedicated config : pucch resource indicator is invalid \n"); - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != FALSE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != false) { v_return = -1; } @@ -595,14 +595,14 @@ int test_pucch_dedicated_single_transport_block(PHY_VARS_NR_UE *ue, int gNB_id, /* reset ack context on last test */ if ((i == (TST_NB_STEP_SINGLE_TRANSPORT_BLOCK-1)) && (j == 1)) { - reset_harq = TRUE; + reset_harq = true; } harq_status->pucch_resource_indicator = pucch_resource_indicator[i][j]; printf("\n => Test : PUCCH format from dedicated config with 1 transport block : with %d downlink ACKnowledgments and pucch resource indicator %d \n", i+1, pucch_resource_indicator[i][j]); - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { v_return = -1; } } @@ -627,11 +627,11 @@ int test_pucch_dedicated_single_transport_block(PHY_VARS_NR_UE *ue, int gNB_id, harq_status->pucch_resource_indicator = pucch_resource_indicator[i][0]; } - reset_harq = TRUE; + reset_harq = true; printf("\n => Test : PUCCH format from dedicated config with 1 transport block and missed PDSCH : with %d downlink ACKnowledgments and pucch resource indicator %d \n", i+1, pucch_resource_indicator[3][0]); - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { v_return = -1; } @@ -659,7 +659,7 @@ int test_pucch_dedicated_two_transport_blocks(PHY_VARS_NR_UE *ue, int gNB_id, UE #define TST_NB_STEP_TWO_TRANSPORT_BLOCKS (4) int v_return = 0; - int reset_harq = FALSE; + int reset_harq = false; int dl_harq_pid[TST_NB_STEP_TWO_TRANSPORT_BLOCKS] = {TST_DL_HARQ_PID_FIRST, TST_DL_HARQ_PID_SECOND, TST_DL_HARQ_PID_THIRD, TST_DL_HARQ_PID_FOURTH }; int pucch_resource_indicator[TST_NB_STEP_TWO_TRANSPORT_BLOCKS][2] = { { 0, 1 }, { 3, 7 } , { 2 , 4 } , { 4 , 6 } }; NR_UE_HARQ_STATUS_t *harq_status; @@ -694,7 +694,7 @@ int test_pucch_dedicated_two_transport_blocks(PHY_VARS_NR_UE *ue, int gNB_id, UE /* reset ack context on last test */ if ((i == (TST_NB_STEP_TWO_TRANSPORT_BLOCKS-1)) && (j == 1)) { - reset_harq = TRUE; + reset_harq = true; } harq_status = &ue->dlsch[proc->thread_id][gNB_id][0]->harq_processes[dl_harq_pid[i]].harq_ack; @@ -703,7 +703,7 @@ int test_pucch_dedicated_two_transport_blocks(PHY_VARS_NR_UE *ue, int gNB_id, UE printf("\n => Test : PUCCH format from dedicated config with 2 transport blocks : with %d downlink ACKnowledgments and pucch resource indicator %d \n", i+1, pucch_resource_indicator[i][j]); - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { printf("Test fail \n"); v_return = -1; } @@ -714,7 +714,7 @@ int test_pucch_dedicated_two_transport_blocks(PHY_VARS_NR_UE *ue, int gNB_id, UE /* some transport blocks have been missed and they need to be nack by UE in order to be retransmitted by the network */ /* here first and third block receptions have been missed */ - reset_harq = TRUE; + reset_harq = true; for (int i = 1; i < TST_NB_STEP_TWO_TRANSPORT_BLOCKS; i = i + 1) { @@ -743,7 +743,7 @@ int test_pucch_dedicated_two_transport_blocks(PHY_VARS_NR_UE *ue, int gNB_id, UE printf("\n => Test : PUCCH format from dedicated config with 2 transport blocks and 1 missed PDSCH : with %d downlink ACKnowledgments and pucch resource indicator %d \n", 4, pucch_resource_indicator[3][0]); - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { printf("Test fail \n"); v_return = -1; } @@ -775,7 +775,7 @@ int test_pucch_dedicated_two_transport_blocks(PHY_VARS_NR_UE *ue, int gNB_id, UE } } - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { printf("Test fail \n"); v_return = -1; } @@ -907,7 +907,7 @@ int test_sr_alone_dedicated(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *p tst_scheduling_request_payload = 0; - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != FALSE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != false) { printf("Test fail \n"); v_return = -1; } @@ -916,7 +916,7 @@ int test_sr_alone_dedicated(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *p tst_scheduling_request_payload = 1; - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { printf("Test fail \n"); v_return = -1; } @@ -929,7 +929,7 @@ int test_sr_alone_dedicated(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *p tst_scheduling_request_payload = 1; - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { printf("Test fail \n"); v_return = -1; } @@ -958,7 +958,7 @@ int test_sr_alone_dedicated(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *p int test_sr_ack_dedicated(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *proc) { int v_return = 0; - int reset_harq = 0; + bool reset_harq = false; int sr_config_id = 0; int sr_resource_id = 0; int sr_offset = 0; @@ -988,7 +988,7 @@ int test_sr_ack_dedicated(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *pro tst_scheduling_request_payload = 0; /* set sr payload */ - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { printf("Test fail \n"); v_return = -1; } @@ -997,7 +997,7 @@ int test_sr_ack_dedicated(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *pro tst_scheduling_request_payload = 1; /* set sr payload */ - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { printf("Test fail \n"); v_return = -1; } @@ -1006,7 +1006,7 @@ int test_sr_ack_dedicated(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *pro harq_status->pucch_resource_indicator = pucch_resource_indicator[1]; - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { printf("Test fail \n"); v_return = -1; } @@ -1027,7 +1027,7 @@ int test_sr_ack_dedicated(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *pro tst_scheduling_request_payload = 1; /* set sr payload */ - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { printf("Test fail \n"); v_return = -1; } @@ -1035,9 +1035,9 @@ int test_sr_ack_dedicated(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *pro printf("\n => Test : PUCCH format from dedicated config with a positive scheduling request and two positive acks \n"); harq_status->pucch_resource_indicator = pucch_resource_indicator[1]; - reset_harq = TRUE; + reset_harq = true; - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { printf("Test fail \n"); v_return = -1; } @@ -1065,7 +1065,7 @@ int test_sr_ack_dedicated(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *pro int test_csi_dedicated(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *proc) { int v_return = 0; - int reset_harq = FALSE; + int reset_harq = false; int sr_config_id = 0; int sr_resource_id = 0; int sr_offset = 0; @@ -1079,7 +1079,7 @@ int test_csi_dedicated(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *proc) printf("\n => Test : PUCCH format from dedicated config with CSI alone \n"); - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { printf("Test fail \n"); v_return = -1; } @@ -1102,7 +1102,7 @@ int test_csi_dedicated(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *proc) ue->pucch_config_dedicated_nr[gNB_id].formatConfig[2-1]->simultaneousHARQ_ACK_CSI = enable_feature; /* format 2 */ - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { printf("Test fail \n"); v_return = -1; } @@ -1115,9 +1115,9 @@ int test_csi_dedicated(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *proc) tst_scheduling_request_payload = 0; /* set sr payload */ - reset_harq = TRUE; + reset_harq = true; - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { printf("Test fail \n"); v_return = -1; } @@ -1126,7 +1126,7 @@ int test_csi_dedicated(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *proc) harq_status->pucch_resource_indicator = pucch_resource_indicator[4]; - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { printf("Test fail \n"); v_return = -1; } @@ -1135,7 +1135,7 @@ int test_csi_dedicated(PHY_VARS_NR_UE *ue, int gNB_id, UE_nr_rxtx_proc_t *proc) printf("\n => Test : PUCCH format from dedicated config with positive SR and CSI \n"); - if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != TRUE) { + if (pucch_procedures_ue_nr(ue, gNB_id, proc, reset_harq) != true) { printf("Test fail \n"); v_return = -1; } diff --git a/openair2/COMMON/commonDef.h b/openair2/COMMON/commonDef.h index b37230cdd4..e18db881f0 100644 --- a/openair2/COMMON/commonDef.h +++ b/openair2/COMMON/commonDef.h @@ -43,27 +43,6 @@ Description Contains global common definitions #include #include -/* boolean_t is also defined in openair2/COMMON/platform_types.h - * let's protect potential redefinition - */ - -#ifndef _BOOLEAN_T_DEFINED_ -#define _BOOLEAN_T_DEFINED_ - -typedef signed char boolean_t; - -#if !defined(TRUE) -#define TRUE (boolean_t)0x01 -#endif - -#if !defined(FALSE) -#define FALSE (boolean_t)0x00 -#endif - -#define BOOL_NOT(b) (b^TRUE) - -#endif /* _BOOLEAN_T_DEFINED_ */ - #define NAS_UE_ID_FMT "0x%06x" /****************************************************************************/ diff --git a/openair2/COMMON/mac_rlc_primitives.h b/openair2/COMMON/mac_rlc_primitives.h index 4e3e22781c..3d6dcc8100 100644 --- a/openair2/COMMON/mac_rlc_primitives.h +++ b/openair2/COMMON/mac_rlc_primitives.h @@ -145,7 +145,7 @@ struct mac_tx_tb_management { struct mac_rx_tb_management { unsigned char *data_ptr; tb_size_t tb_size; // in bits - boolean_t valid_checksum; + bool valid_checksum; unsigned char first_bit; // 0 if data starts on byte boundary(b7), 1 if b6, 2 if b5, etc }; diff --git a/openair2/COMMON/platform_types.h b/openair2/COMMON/platform_types.h index 67300da308..f229721993 100644 --- a/openair2/COMMON/platform_types.h +++ b/openair2/COMMON/platform_types.h @@ -32,35 +32,12 @@ #if !defined(NAS_NETLINK) #include +#include #else #include typedef void * intptr_t; #endif -//----------------------------------------------------------------------------- -// GENERIC TYPES -//----------------------------------------------------------------------------- - -/* boolean_t is also defined in openair2/COMMON/commonDef.h, - * let's protect potential redefinition - */ -#ifndef _BOOLEAN_T_DEFINED_ - #define _BOOLEAN_T_DEFINED_ - - typedef signed char boolean_t; - - #if !defined(TRUE) - #define TRUE (boolean_t)0x01 - #endif - - #if !defined(FALSE) - #define FALSE (boolean_t)0x00 - #endif - - #define BOOL_NOT(b) (b^TRUE) - -#endif /* _BOOLEAN_T_DEFINED_ */ - //----------------------------------------------------------------------------- // GENERIC ACCESS STRATUM TYPES //----------------------------------------------------------------------------- @@ -77,25 +54,25 @@ typedef int16_t smodule_id_t; typedef long rb_id_t; typedef long srb_id_t; -typedef boolean_t MBMS_flag_t; -#define MBMS_FLAG_NO FALSE -#define MBMS_FLAG_YES TRUE +typedef bool MBMS_flag_t; +#define MBMS_FLAG_NO false +#define MBMS_FLAG_YES true -typedef boolean_t eNB_flag_t; -#define ENB_FLAG_NO FALSE -#define ENB_FLAG_YES TRUE +typedef bool eNB_flag_t; +#define ENB_FLAG_NO false +#define ENB_FLAG_YES true -typedef boolean_t gNB_flag_t; -#define GNB_FLAG_NO FALSE -#define GNB_FLAG_YES TRUE +typedef bool gNB_flag_t; +#define GNB_FLAG_NO false +#define GNB_FLAG_YES true -typedef boolean_t srb_flag_t; -#define SRB_FLAG_NO FALSE -#define SRB_FLAG_YES TRUE +typedef bool srb_flag_t; +#define SRB_FLAG_NO false +#define SRB_FLAG_YES true -typedef boolean_t sl_discovery_flag_t; -#define SL_DISCOVERY_FLAG_NO FALSE -#define SL_DISCOVERY_FLAG_YES TRUE +typedef bool sl_discovery_flag_t; +#define SL_DISCOVERY_FLAG_NO false +#define SL_DISCOVERY_FLAG_YES true typedef enum link_direction_e { UNKNOWN_DIR = 0, @@ -152,8 +129,8 @@ typedef uint16_t rlc_usn_t; typedef int32_t rlc_buffer_occupancy_t; typedef signed int rlc_op_status_t; -#define SDU_CONFIRM_NO FALSE -#define SDU_CONFIRM_YES TRUE +#define SDU_CONFIRM_NO false +#define SDU_CONFIRM_YES true //----------------------------------------------------------------------------- // PDCP TYPES //----------------------------------------------------------------------------- @@ -242,7 +219,7 @@ typedef struct protocol_ctxt_s { frame_t frame; /*!< \brief LTE frame number.*/ sub_frame_t subframe; /*!< \brief LTE sub frame number.*/ eNB_index_t eNB_index; /*!< \brief valid for UE indicating the index of connected eNB(s) */ - boolean_t brOption; + bool brOption; } protocol_ctxt_t; // warning time hardcoded #define PROTOCOL_CTXT_TIME_MILLI_SECONDS(CtXt_h) ((CtXt_h)->frame*10+(CtXt_h)->subframe) diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index f4550f63a1..00ffd4cc13 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -583,9 +583,9 @@ int RCconfig_RRC(uint32_t i, eNB_RRC_INST *rrc, int macrlc_has_f1) { "Failed to parse eNB configuration file %s, enb %u define %s: ENABLE,DISABLE!\n", RC.config_file_name, i, ENB_CONFIG_STRING_PRACH_HIGH_SPEED); else if (strcmp(ccparams_lte.prach_high_speed, "ENABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].prach_high_speed = TRUE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].prach_high_speed = true; } else if (strcmp(ccparams_lte.prach_high_speed, "DISABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].prach_high_speed = FALSE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].prach_high_speed = false; } else AssertFatal (0, "Failed to parse eNB configuration file %s, enb %u unknown value \"%s\" for prach_config choice: ENABLE,DISABLE !\n", @@ -689,9 +689,9 @@ int RCconfig_RRC(uint32_t i, eNB_RRC_INST *rrc, int macrlc_has_f1) { "Failed to parse eNB configuration file %s, enb %u define %s: ENABLE,DISABLE!\n", RC.config_file_name, i, ENB_CONFIG_STRING_PUSCH_ENABLE64QAM); else if (strcmp(ccparams_lte.pusch_enable64QAM, "ENABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].pusch_enable64QAM = TRUE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].pusch_enable64QAM = true; } else if (strcmp(ccparams_lte.pusch_enable64QAM, "DISABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].pusch_enable64QAM = FALSE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].pusch_enable64QAM = false; } else AssertFatal (0, "Failed to parse eNB configuration file %s, enb %u unknown value \"%s\" for pusch_enable64QAM choice: ENABLE,DISABLE!\n", @@ -702,9 +702,9 @@ int RCconfig_RRC(uint32_t i, eNB_RRC_INST *rrc, int macrlc_has_f1) { "Failed to parse eNB configuration file %s, enb %u define %s: ENABLE,DISABLE!\n", RC.config_file_name, i, ENB_CONFIG_STRING_PUSCH_GROUP_HOPPING_EN); else if (strcmp(ccparams_lte.pusch_groupHoppingEnabled, "ENABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].pusch_groupHoppingEnabled = TRUE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].pusch_groupHoppingEnabled = true; } else if (strcmp(ccparams_lte.pusch_groupHoppingEnabled, "DISABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].pusch_groupHoppingEnabled= FALSE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].pusch_groupHoppingEnabled= false; } else AssertFatal (0, "Failed to parse eNB configuration file %s, enb %u unknown value \"%s\" for pusch_groupHoppingEnabled choice: ENABLE,DISABLE!\n", @@ -723,9 +723,9 @@ int RCconfig_RRC(uint32_t i, eNB_RRC_INST *rrc, int macrlc_has_f1) { "Failed to parse eNB configuration file %s, enb %u define %s: ENABLE,DISABLE!\n", RC.config_file_name, i, ENB_CONFIG_STRING_PUSCH_SEQUENCE_HOPPING_EN); else if (strcmp(ccparams_lte.pusch_sequenceHoppingEnabled, "ENABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].pusch_sequenceHoppingEnabled = TRUE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].pusch_sequenceHoppingEnabled = true; } else if (strcmp(ccparams_lte.pusch_sequenceHoppingEnabled, "DISABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].pusch_sequenceHoppingEnabled = FALSE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].pusch_sequenceHoppingEnabled = false; } else AssertFatal (0, "Failed to parse eNB configuration file %s, enb %u unknown value \"%s\" for pusch_sequenceHoppingEnabled choice: ENABLE,DISABLE!\n", @@ -766,15 +766,15 @@ int RCconfig_RRC(uint32_t i, eNB_RRC_INST *rrc, int macrlc_has_f1) { RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].phich_duration,ccparams_lte.phich_duration); if (strcmp(ccparams_lte.srs_enable, "ENABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].srs_enable= TRUE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].srs_enable= true; } else if (strcmp(ccparams_lte.srs_enable, "DISABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].srs_enable= FALSE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].srs_enable= false; } else AssertFatal (0, "Failed to parse eNB configuration file %s, enb %u unknown value \"%s\" for srs_BandwidthConfig choice: ENABLE,DISABLE !\n", RC.config_file_name, i, ccparams_lte.srs_enable); - if (RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].srs_enable== TRUE) { + if (RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].srs_enable== true) { RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].srs_BandwidthConfig= ccparams_lte.srs_BandwidthConfig; if ((ccparams_lte.srs_BandwidthConfig < 0) || @@ -791,18 +791,18 @@ int RCconfig_RRC(uint32_t i, eNB_RRC_INST *rrc, int macrlc_has_f1) { RC.config_file_name, i, ccparams_lte.srs_SubframeConfig); if (strcmp(ccparams_lte.srs_ackNackST, "ENABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].srs_ackNackST= TRUE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].srs_ackNackST= true; } else if (strcmp(ccparams_lte.srs_ackNackST, "DISABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].srs_ackNackST= FALSE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].srs_ackNackST= false; } else AssertFatal (0, "Failed to parse eNB configuration file %s, enb %u unknown value \"%s\" for srs_BandwidthConfig choice: ENABLE,DISABLE !\n", RC.config_file_name, i, ccparams_lte.srs_ackNackST); if (strcmp(ccparams_lte.srs_MaxUpPts, "ENABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].srs_MaxUpPts= TRUE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].srs_MaxUpPts= true; } else if (strcmp(ccparams_lte.srs_MaxUpPts, "DISABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].srs_MaxUpPts= FALSE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].srs_MaxUpPts= false; } else AssertFatal (0, "Failed to parse eNB configuration file %s, enb %u unknown value \"%s\" for srs_MaxUpPts choice: ENABLE,DISABLE !\n", @@ -921,7 +921,7 @@ int RCconfig_RRC(uint32_t i, eNB_RRC_INST *rrc, int macrlc_has_f1) { RC.config_file_name, i, ccparams_lte.rach_numberOfRA_Preambles); if (strcmp(ccparams_lte.rach_preamblesGroupAConfig, "ENABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].rach_preamblesGroupAConfig= TRUE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].rach_preamblesGroupAConfig= true; RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].rach_sizeOfRA_PreamblesGroupA= (ccparams_lte.rach_sizeOfRA_PreamblesGroupA/4)-1; if ((ccparams_lte.rach_numberOfRA_Preambles <4) || @@ -976,7 +976,7 @@ int RCconfig_RRC(uint32_t i, eNB_RRC_INST *rrc, int macrlc_has_f1) { "Failed to parse eNB configuration file %s, enb %u unknown value \"%s\" for rach_messagePowerOffsetGroupB choice: minusinfinity,dB0,dB5,dB8,dB10,dB12,dB15,dB18!\n", RC.config_file_name, i, ccparams_lte.rach_messagePowerOffsetGroupB); } else if (strcmp(ccparams_lte.rach_preamblesGroupAConfig, "DISABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].rach_preamblesGroupAConfig= FALSE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].rach_preamblesGroupAConfig= false; } else AssertFatal (0, "Failed to parse eNB configuration file %s, enb %u unknown value \"%s\" for rach_preamblesGroupAConfig choice: ENABLE,DISABLE !\n", @@ -1254,9 +1254,9 @@ int RCconfig_RRC(uint32_t i, eNB_RRC_INST *rrc, int macrlc_has_f1) { "Failed to parse eNB configuration file %s, enb %u define %s: TRUE,FALSE!\n", RC.config_file_name, i, ENB_CONFIG_STRING_MBMS_DEDICATED_SERVING_CELL); else if (strcmp(ccparams_lte.mbms_dedicated_serving_cell, "ENABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].mbms_dedicated_serving_cell = TRUE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].mbms_dedicated_serving_cell = true; } else if (strcmp(ccparams_lte.mbms_dedicated_serving_cell, "DISABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].mbms_dedicated_serving_cell = FALSE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig[j].mbms_dedicated_serving_cell = false; } else { AssertFatal (0, "Failed to parse eNB configuration file %s, enb %u unknown value \"%s\" for mbms_dedicated_serving_cell choice: TRUE or FALSE !\n", diff --git a/openair2/ENB_APP/enb_config_eMTC.c b/openair2/ENB_APP/enb_config_eMTC.c index 2e71f17e9d..e4ff458886 100644 --- a/openair2/ENB_APP/enb_config_eMTC.c +++ b/openair2/ENB_APP/enb_config_eMTC.c @@ -61,18 +61,18 @@ void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, in if (!strcmp(eMTCconfig->cellSelectionInfoCE_r13, "ENABLE")) { - RRC_CONFIGURATION_REQ(msg_p).cellSelectionInfoCE_r13[cc_idx] = TRUE; + RRC_CONFIGURATION_REQ(msg_p).cellSelectionInfoCE_r13[cc_idx] = true; RRC_CONFIGURATION_REQ(msg_p).q_RxLevMinCE_r13[cc_idx]= eMTCconfig->q_RxLevMinCE_r13; // RRC_CONFIGURATION_REQ(msg_p).q_QualMinRSRQ_CE_r13[cc_idx]= calloc(1, sizeof(long)); // *RRC_CONFIGURATION_REQ(msg_p).q_QualMinRSRQ_CE_r13[cc_idx]= q_QualMinRSRQ_CE_r13; } else { - RRC_CONFIGURATION_REQ(msg_p).cellSelectionInfoCE_r13[cc_idx] = FALSE; + RRC_CONFIGURATION_REQ(msg_p).cellSelectionInfoCE_r13[cc_idx] = false; } if (!strcmp(eMTCconfig->bandwidthReducedAccessRelatedInfo_r13, "ENABLE")) { - RRC_CONFIGURATION_REQ(msg_p).bandwidthReducedAccessRelatedInfo_r13[cc_idx] = TRUE; + RRC_CONFIGURATION_REQ(msg_p).bandwidthReducedAccessRelatedInfo_r13[cc_idx] = true; @@ -106,7 +106,7 @@ void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, in } } else { - RRC_CONFIGURATION_REQ(msg_p).bandwidthReducedAccessRelatedInfo_r13[cc_idx] = FALSE; + RRC_CONFIGURATION_REQ(msg_p).bandwidthReducedAccessRelatedInfo_r13[cc_idx] = false; } char schedulingInfoBrPath[MAX_OPTNAME_SIZE * 2]; @@ -127,10 +127,10 @@ void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, in RRC_CONFIGURATION_REQ(msg_p).fdd_DownlinkOrTddSubframeBitmapBR_r13[cc_idx] = CALLOC(1, sizeof(BOOLEAN_t)); if (!strcmp(eMTCconfig->fdd_DownlinkOrTddSubframeBitmapBR_r13, "subframePattern40-r13")) { - *RRC_CONFIGURATION_REQ(msg_p).fdd_DownlinkOrTddSubframeBitmapBR_r13[cc_idx] = FALSE; + *RRC_CONFIGURATION_REQ(msg_p).fdd_DownlinkOrTddSubframeBitmapBR_r13[cc_idx] = false; RRC_CONFIGURATION_REQ(msg_p).fdd_DownlinkOrTddSubframeBitmapBR_val_r13[cc_idx] = eMTCconfig->fdd_DownlinkOrTddSubframeBitmapBR_val_r13; } else { - *RRC_CONFIGURATION_REQ(msg_p).fdd_DownlinkOrTddSubframeBitmapBR_r13[cc_idx] = TRUE; + *RRC_CONFIGURATION_REQ(msg_p).fdd_DownlinkOrTddSubframeBitmapBR_r13[cc_idx] = true; RRC_CONFIGURATION_REQ(msg_p).fdd_DownlinkOrTddSubframeBitmapBR_val_r13[cc_idx] = eMTCconfig->fdd_DownlinkOrTddSubframeBitmapBR_val_r13; } @@ -156,18 +156,18 @@ void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, in if (!strcmp(eMTCconfig->freqHoppingParametersDL_r13, "ENABLE")) { - RRC_CONFIGURATION_REQ(msg_p).freqHoppingParametersDL_r13[cc_idx] = TRUE; + RRC_CONFIGURATION_REQ(msg_p).freqHoppingParametersDL_r13[cc_idx] = true; if (!strcmp(eMTCconfig->interval_DLHoppingConfigCommonModeA_r13, "interval-TDD-r13")) - RRC_CONFIGURATION_REQ(msg_p).interval_DLHoppingConfigCommonModeA_r13[cc_idx] = FALSE; + RRC_CONFIGURATION_REQ(msg_p).interval_DLHoppingConfigCommonModeA_r13[cc_idx] = false; else - RRC_CONFIGURATION_REQ(msg_p).interval_DLHoppingConfigCommonModeA_r13[cc_idx] = TRUE; + RRC_CONFIGURATION_REQ(msg_p).interval_DLHoppingConfigCommonModeA_r13[cc_idx] = true; RRC_CONFIGURATION_REQ(msg_p).interval_DLHoppingConfigCommonModeA_r13_val[cc_idx] = eMTCconfig->interval_DLHoppingConfigCommonModeA_r13_val; if (!strcmp(eMTCconfig->interval_DLHoppingConfigCommonModeB_r13, "interval-TDD-r13")) - RRC_CONFIGURATION_REQ(msg_p).interval_DLHoppingConfigCommonModeB_r13[cc_idx] = FALSE; + RRC_CONFIGURATION_REQ(msg_p).interval_DLHoppingConfigCommonModeB_r13[cc_idx] = false; else - RRC_CONFIGURATION_REQ(msg_p).interval_DLHoppingConfigCommonModeB_r13[cc_idx] = TRUE; + RRC_CONFIGURATION_REQ(msg_p).interval_DLHoppingConfigCommonModeB_r13[cc_idx] = true; RRC_CONFIGURATION_REQ(msg_p).interval_DLHoppingConfigCommonModeB_r13_val[cc_idx] = eMTCconfig->interval_DLHoppingConfigCommonModeB_r13_val; RRC_CONFIGURATION_REQ(msg_p).mpdcch_pdsch_HoppingNB_r13[cc_idx] = calloc(1, sizeof(long)); @@ -188,7 +188,7 @@ void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, in } else { - RRC_CONFIGURATION_REQ(msg_p).freqHoppingParametersDL_r13[cc_idx] = FALSE; + RRC_CONFIGURATION_REQ(msg_p).freqHoppingParametersDL_r13[cc_idx] = false; } /** ------------------------------SIB2/3 BR------------------------------------------ */ @@ -213,9 +213,9 @@ void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, in "Failed to parse eNB configuration file %s, enb %d define %s: ENABLE,DISABLE!\n", config_fname, cell_idx,ENB_CONFIG_STRING_PRACH_HIGH_SPEED); else if (strcmp(eMTCconfig->ccparams.prach_high_speed, "ENABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].prach_high_speed = TRUE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].prach_high_speed = true; } else if (strcmp(eMTCconfig->ccparams.prach_high_speed, "DISABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].prach_high_speed = FALSE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].prach_high_speed = false; } else AssertFatal (0, "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for prach_config choice: ENABLE,DISABLE !\n", @@ -310,9 +310,9 @@ void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, in "Failed to parse eNB configuration file %s, enb %d define %s: ENABLE,DISABLE!\n", config_fname, cell_idx,ENB_CONFIG_STRING_PUSCH_ENABLE64QAM); else if (strcmp(eMTCconfig->ccparams.pusch_enable64QAM, "ENABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].pusch_enable64QAM = TRUE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].pusch_enable64QAM = true; } else if (strcmp(eMTCconfig->ccparams.pusch_enable64QAM, "DISABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].pusch_enable64QAM = FALSE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].pusch_enable64QAM = false; } else AssertFatal (0, "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for pusch_enable64QAM choice: ENABLE,DISABLE!\n", @@ -323,9 +323,9 @@ void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, in "Failed to parse eNB configuration file %s, enb %d define %s: ENABLE,DISABLE!\n", config_fname, cell_idx,ENB_CONFIG_STRING_PUSCH_GROUP_HOPPING_EN); else if (strcmp(eMTCconfig->ccparams.pusch_groupHoppingEnabled, "ENABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].pusch_groupHoppingEnabled = TRUE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].pusch_groupHoppingEnabled = true; } else if (strcmp(eMTCconfig->ccparams.pusch_groupHoppingEnabled, "DISABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].pusch_groupHoppingEnabled= FALSE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].pusch_groupHoppingEnabled= false; } else AssertFatal (0, "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for pusch_groupHoppingEnabled choice: ENABLE,DISABLE!\n", @@ -343,9 +343,9 @@ void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, in "Failed to parse eNB configuration file %s, enb %d define %s: ENABLE,DISABLE!\n", config_fname, cell_idx,ENB_CONFIG_STRING_PUSCH_SEQUENCE_HOPPING_EN); else if (strcmp(eMTCconfig->ccparams.pusch_sequenceHoppingEnabled, "ENABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].pusch_sequenceHoppingEnabled = TRUE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].pusch_sequenceHoppingEnabled = true; } else if (strcmp(eMTCconfig->ccparams.pusch_sequenceHoppingEnabled, "DISABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].pusch_sequenceHoppingEnabled = FALSE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].pusch_sequenceHoppingEnabled = false; } else AssertFatal (0, "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for pusch_sequenceHoppingEnabled choice: ENABLE,DISABLE!\n", @@ -385,15 +385,15 @@ void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, in RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].phich_duration,eMTCconfig->ccparams.phich_duration); if (strcmp(eMTCconfig->ccparams.srs_enable, "ENABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].srs_enable= TRUE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].srs_enable= true; } else if (strcmp(eMTCconfig->ccparams.srs_enable, "DISABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].srs_enable= FALSE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].srs_enable= false; } else AssertFatal (0, "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for srs_BandwidthConfig choice: ENABLE,DISABLE !\n", config_fname, cell_idx,eMTCconfig->ccparams.srs_enable); - if (RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].srs_enable== TRUE) { + if (RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].srs_enable== true) { RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].srs_BandwidthConfig= eMTCconfig->ccparams.srs_BandwidthConfig; if ((eMTCconfig->ccparams.srs_BandwidthConfig < 0) || (eMTCconfig->ccparams.srs_BandwidthConfig >7)) @@ -408,18 +408,18 @@ void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, in config_fname, cell_idx,eMTCconfig->ccparams.srs_SubframeConfig); if (strcmp(eMTCconfig->ccparams.srs_ackNackST, "ENABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].srs_ackNackST= TRUE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].srs_ackNackST= true; } else if (strcmp(eMTCconfig->ccparams.srs_ackNackST, "DISABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].srs_ackNackST= FALSE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].srs_ackNackST= false; } else AssertFatal (0, "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for srs_BandwidthConfig choice: ENABLE,DISABLE !\n", config_fname, cell_idx,eMTCconfig->ccparams.srs_ackNackST); if (strcmp(eMTCconfig->ccparams.srs_MaxUpPts, "ENABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].srs_MaxUpPts= TRUE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].srs_MaxUpPts= true; } else if (strcmp(eMTCconfig->ccparams.srs_MaxUpPts, "DISABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].srs_MaxUpPts= FALSE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].srs_MaxUpPts= false; } else AssertFatal (0, "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for srs_MaxUpPts choice: ENABLE,DISABLE !\n", @@ -535,7 +535,7 @@ void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, in config_fname, cell_idx,eMTCconfig->ccparams.rach_numberOfRA_Preambles); if (strcmp(eMTCconfig->ccparams.rach_preamblesGroupAConfig, "ENABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].rach_preamblesGroupAConfig= TRUE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].rach_preamblesGroupAConfig= true; RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].rach_sizeOfRA_PreamblesGroupA= (eMTCconfig->ccparams.rach_sizeOfRA_PreamblesGroupA/4)-1; if ((eMTCconfig->ccparams.rach_numberOfRA_Preambles <4) || (eMTCconfig->ccparams.rach_numberOfRA_Preambles>60) || ((eMTCconfig->ccparams.rach_numberOfRA_Preambles&3)!=0)) @@ -588,7 +588,7 @@ void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, in "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for rach_messagePowerOffsetGroupB choice: minusinfinity,dB0,dB5,dB8,dB10,dB12,dB15,dB18!\n", config_fname, cell_idx,eMTCconfig->ccparams.rach_messagePowerOffsetGroupB); } else if (strcmp(eMTCconfig->ccparams.rach_preamblesGroupAConfig, "DISABLE") == 0) { - RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].rach_preamblesGroupAConfig= FALSE; + RRC_CONFIGURATION_REQ (msg_p).radioresourceconfig_BR[cc_idx].rach_preamblesGroupAConfig= false; } else AssertFatal (0, "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for rach_preamblesGroupAConfig choice: ENABLE,DISABLE !\n", @@ -847,14 +847,14 @@ void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, in if (!strcmp(eMTCconfig->prach_ConfigCommon_v1310, "ENABLE")) { - RRC_CONFIGURATION_REQ(msg_p).radioresourceconfig_BR[cc_idx].prach_ConfigCommon_v1310 = TRUE; + RRC_CONFIGURATION_REQ(msg_p).radioresourceconfig_BR[cc_idx].prach_ConfigCommon_v1310 = true; RRC_CONFIGURATION_REQ(msg_p).radioresourceconfig_BR[cc_idx].mpdcch_startSF_CSS_RA_r13 = calloc(1, sizeof(BOOLEAN_t)); if (!strcmp(eMTCconfig->mpdcch_startSF_CSS_RA_r13, "tdd-r13")) { - *RRC_CONFIGURATION_REQ(msg_p).radioresourceconfig_BR[cc_idx].mpdcch_startSF_CSS_RA_r13 = FALSE; + *RRC_CONFIGURATION_REQ(msg_p).radioresourceconfig_BR[cc_idx].mpdcch_startSF_CSS_RA_r13 = false; } else { - *RRC_CONFIGURATION_REQ(msg_p).radioresourceconfig_BR[cc_idx].mpdcch_startSF_CSS_RA_r13 = TRUE; + *RRC_CONFIGURATION_REQ(msg_p).radioresourceconfig_BR[cc_idx].mpdcch_startSF_CSS_RA_r13 = true; } if (!strcmp(eMTCconfig->mpdcch_startSF_CSS_RA_r13_val, "v1")) { @@ -882,7 +882,7 @@ void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, in RRC_CONFIGURATION_REQ(msg_p).radioresourceconfig_BR[cc_idx].prach_HoppingOffset_r13 = calloc(1, sizeof(long)); *RRC_CONFIGURATION_REQ(msg_p).radioresourceconfig_BR[cc_idx].prach_HoppingOffset_r13 = eMTCconfig->prach_HoppingOffset_r13; } else { - RRC_CONFIGURATION_REQ(msg_p).radioresourceconfig_BR[cc_idx].prach_ConfigCommon_v1310 = FALSE; + RRC_CONFIGURATION_REQ(msg_p).radioresourceconfig_BR[cc_idx].prach_ConfigCommon_v1310 = false; } @@ -1169,7 +1169,7 @@ void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, in /** PCCH CONFIG V1310 */ - RRC_CONFIGURATION_REQ(msg_p).pcch_config_v1310[cc_idx] = TRUE; + RRC_CONFIGURATION_REQ(msg_p).pcch_config_v1310[cc_idx] = true; RRC_CONFIGURATION_REQ(msg_p).paging_narrowbands_r13[cc_idx] = eMTCconfig->paging_narrowbands_r13; RRC_CONFIGURATION_REQ(msg_p).mpdcch_numrepetition_paging_r13[cc_idx] = eMTCconfig->mpdcch_numrepetition_paging_r13; @@ -1220,7 +1220,7 @@ void fill_eMTC_configuration(MessageDef *msg_p, ccparams_eMTC_t *eMTCconfig, in /** SIB2 FREQ HOPPING PARAMETERS R13 */ - RRC_CONFIGURATION_REQ(msg_p).sib2_freq_hoppingParameters_r13_exists[cc_idx] = TRUE; + RRC_CONFIGURATION_REQ(msg_p).sib2_freq_hoppingParameters_r13_exists[cc_idx] = true; char sib2FreqHoppingParametersR13Path[MAX_OPTNAME_SIZE*2 + 16]; sprintf(sib2FreqHoppingParametersR13Path, "%s.%s", brparamspath, ENB_CONFIG_STRING_SIB2_FREQ_HOPPINGPARAMETERS_R13); diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c index 9926ec9e20..3113c07798 100644 --- a/openair2/ENB_APP/flexran_agent_ran_api.c +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -127,7 +127,7 @@ int flexran_get_mac_ue_id_rnti(mid_t mod_id, rnti_t rnti) { /* get the (active) UE with RNTI i */ for (n = 0; n < MAX_MOBILES_PER_ENB; ++n) { - if (RC.mac[mod_id]->UE_info.active[n] == TRUE + if (RC.mac[mod_id]->UE_info.active[n] == true && rnti == UE_RNTI(mod_id, n)) { return n; } @@ -143,7 +143,7 @@ int flexran_get_mac_ue_id(mid_t mod_id, int i) { /* get the (i+1)'th active UE */ for (n = 0; n < MAX_MOBILES_PER_ENB; ++n) { - if (RC.mac[mod_id]->UE_info.active[n] == TRUE) { + if (RC.mac[mod_id]->UE_info.active[n] == true) { if (i == 0) return n; @@ -580,7 +580,7 @@ uint8_t flexran_get_n_SB(mid_t mod_id, uint8_t cc_id) { Protocol__FlexQam flexran_get_enable64QAM(mid_t mod_id, uint8_t cc_id) { if (!phy_is_present(mod_id, cc_id)) return 0; - if (RC.eNB[mod_id][cc_id]->frame_parms.pusch_config_common.enable64QAM == TRUE) + if (RC.eNB[mod_id][cc_id]->frame_parms.pusch_config_common.enable64QAM == true) return PROTOCOL__FLEX_QAM__FLEQ_MOD_64QAM; else return PROTOCOL__FLEX_QAM__FLEQ_MOD_16QAM; @@ -3585,7 +3585,7 @@ int flexran_set_new_plmn_id(mid_t mod_id, int CC_id, size_t n_plmn, Protocol__Fl int CC_id, BOOLEAN_t brOption, RrcConfigurationReq *configuration); - carrier->sizeof_SIB1 = do_SIB1(carrier, mod_id, CC_id, FALSE, conf); + carrier->sizeof_SIB1 = do_SIB1(carrier, mod_id, CC_id, false, conf); if (carrier->sizeof_SIB1 < 0) return -1337; /* SIB1 encoding failed, hell will probably break loose */ diff --git a/openair2/F1AP/dummy_enb.c b/openair2/F1AP/dummy_enb.c index 9085fdb57c..8e185c951d 100644 --- a/openair2/F1AP/dummy_enb.c +++ b/openair2/F1AP/dummy_enb.c @@ -32,18 +32,18 @@ void apply_macrlc_config(gNB_RRC_INST *rrc, abort(); } -boolean_t sdap_data_req(protocol_ctxt_t *ctxt_p, - const srb_flag_t srb_flag, - const rb_id_t rb_id, - const mui_t mui, - const confirm_t confirm, - const sdu_size_t sdu_buffer_size, - unsigned char *const sdu_buffer, - const pdcp_transmission_mode_t pt_mode, - const uint32_t *sourceL2Id, - const uint32_t *destinationL2Id, - const uint8_t qfi, - const boolean_t rqi, - const int pdusession_id) { +bool sdap_data_req(protocol_ctxt_t *ctxt_p, + const srb_flag_t srb_flag, + const rb_id_t rb_id, + const mui_t mui, + const confirm_t confirm, + const sdu_size_t sdu_buffer_size, + unsigned char *const sdu_buffer, + const pdcp_transmission_mode_t pt_mode, + const uint32_t *sourceL2Id, + const uint32_t *destinationL2Id, + const uint8_t qfi, + const bool rqi, + const int pdusession_id) { abort(); } diff --git a/openair2/F1AP/f1ap_common.h b/openair2/F1AP/f1ap_common.h index 66451530a6..6b64e1b59e 100644 --- a/openair2/F1AP/f1ap_common.h +++ b/openair2/F1AP/f1ap_common.h @@ -363,13 +363,6 @@ # error "You are compiling f1ap with the wrong version of ASN1C" #endif -#ifndef FALSE - #define FALSE (0) -#endif -#ifndef TRUE - #define TRUE (!FALSE) -#endif - #define F1AP_UE_ID_FMT "0x%06"PRIX32 #include "assertions.h" diff --git a/openair2/F1AP/f1ap_du_rrc_message_transfer.c b/openair2/F1AP/f1ap_du_rrc_message_transfer.c index a9f82f42b3..e158e9519a 100644 --- a/openair2/F1AP/f1ap_du_rrc_message_transfer.c +++ b/openair2/F1AP/f1ap_du_rrc_message_transfer.c @@ -509,7 +509,7 @@ int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, LOG_I(F1AP, "Received DL RRC Transfer on srb_id %ld\n", srb_id); rlc_op_status_t rlc_status; - boolean_t ret = TRUE; + bool ret = true; mem_block_t *pdcp_pdu_p = NULL; pdcp_pdu_p = get_free_mem_block(rrc_dl_sdu_len, __func__); @@ -539,27 +539,27 @@ int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, switch (rlc_status) { case RLC_OP_STATUS_OK: //LOG_I(F1AP, "Data sending request over RLC succeeded!\n"); - ret=TRUE; + ret=true; break; case RLC_OP_STATUS_BAD_PARAMETER: LOG_W(F1AP, "Data sending request over RLC failed with 'Bad Parameter' reason!\n"); - ret= FALSE; + ret= false; break; case RLC_OP_STATUS_INTERNAL_ERROR: LOG_W(F1AP, "Data sending request over RLC failed with 'Internal Error' reason!\n"); - ret= FALSE; + ret= false; break; case RLC_OP_STATUS_OUT_OF_RESSOURCES: LOG_W(F1AP, "Data sending request over RLC failed with 'Out of Resources' reason!\n"); - ret= FALSE; + ret= false; break; default: LOG_W(F1AP, "RLC returned an unknown status code after PDCP placed the order to send some data (Status Code:%d)\n", rlc_status); - ret= FALSE; + ret= false; break; } // switch case @@ -667,9 +667,9 @@ int DU_send_UL_RRC_MESSAGE_TRANSFER(instance_t instance, UE_sched_ctrl_t *UE_scheduling_control = &(RC.mac[instance]->UE_info.UE_sched_ctrl[UE_id_mac]); - if (UE_scheduling_control->cdrx_waiting_ack == TRUE) { - UE_scheduling_control->cdrx_waiting_ack = FALSE; - UE_scheduling_control->cdrx_configured = TRUE; // Set to TRUE when RRC Connection Reconfiguration Complete is received + if (UE_scheduling_control->cdrx_waiting_ack == true) { + UE_scheduling_control->cdrx_waiting_ack = false; + UE_scheduling_control->cdrx_configured = true; // Set to TRUE when RRC Connection Reconfiguration Complete is received LOG_I(F1AP, "CDRX configuration activated after RRC Connection Reconfiguration Complete reception\n"); } diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index 6dbe820465..74e0200f09 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -42,16 +42,16 @@ #include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h" #include -boolean_t lteDURecvCb( protocol_ctxt_t *ctxt_pP, - const srb_flag_t srb_flagP, - const rb_id_t rb_idP, - const mui_t muiP, - const confirm_t confirmP, - const sdu_size_t sdu_buffer_sizeP, - unsigned char *const sdu_buffer_pP, - const pdcp_transmission_mode_t modeP, - const uint32_t *sourceL2Id, - const uint32_t *destinationL2Id) { +bool lteDURecvCb(protocol_ctxt_t *ctxt_pP, + const srb_flag_t srb_flagP, + const rb_id_t rb_idP, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_buffer_sizeP, + unsigned char *const sdu_buffer_pP, + const pdcp_transmission_mode_t modeP, + const uint32_t *sourceL2Id, + const uint32_t *destinationL2Id) { // The buffer comes from the stack in gtp-u thread, we have a make a separate buffer to enqueue in a inter-thread message queue mem_block_t *sdu=get_free_mem_block(sdu_buffer_sizeP, __func__); memcpy(sdu->data, sdu_buffer_pP, sdu_buffer_sizeP); @@ -704,7 +704,7 @@ int DU_send_UE_CONTEXT_RELEASE_REQUEST(instance_t instance, LOG_E(F1AP,"Not found rnti: %x\n", rnti); } else { for (int n = 0; n < MAX_MOBILES_PER_ENB; ++n) { - if (RC.mac[instance]->UE_info.active[n] == TRUE + if (RC.mac[instance]->UE_info.active[n] == true && rnti == UE_RNTI(instance, n)) { UE_out_of_sync = RC.mac[instance]->UE_info.UE_sched_ctrl[n].ul_out_of_sync; break; @@ -856,7 +856,7 @@ int DU_handle_UE_CONTEXT_RELEASE_COMMAND(instance_t instance, if(RC.rrc && RC.rrc[instance]->node_type == ngran_eNB_DU){ for (int n = 0; n < MAX_MOBILES_PER_ENB; ++n) { - if (RC.mac[instance]->UE_info.active[n] == TRUE + if (RC.mac[instance]->UE_info.active[n] == true && rnti == UE_RNTI(instance, n)) { UE_out_of_sync = RC.mac[instance]->UE_info.UE_sched_ctrl[n].ul_out_of_sync; break; diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index d22485d23f..52a9048cd0 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -1104,7 +1104,7 @@ void eNB_Config_Local_DRX(instance_t Mod_id, /* Get struct to modify */ UE_scheduling_control = &(UE_info_mac->UE_sched_ctrl[UE_id]); - UE_scheduling_control->cdrx_configured = FALSE; // will be set to true when no error + UE_scheduling_control->cdrx_configured = false; // will be set to true when no error /* Check drx_Configuration */ if (drx_Configuration == NULL) { @@ -1119,9 +1119,9 @@ void eNB_Config_Local_DRX(instance_t Mod_id, } /* Modify scheduling control structure according to DRX configuration: doesn't support every configurations! */ - UE_scheduling_control->cdrx_configured = FALSE; // will be set to true when receiving RRC Reconfiguration Complete - UE_scheduling_control->cdrx_waiting_ack = TRUE; // waiting for RRC Reconfiguration Complete message - UE_scheduling_control->in_active_time = FALSE; + UE_scheduling_control->cdrx_configured = false; // will be set to true when receiving RRC Reconfiguration Complete + UE_scheduling_control->cdrx_waiting_ack = true; // waiting for RRC Reconfiguration Complete message + UE_scheduling_control->in_active_time = false; UE_scheduling_control->dci0_ongoing_timer = 0; UE_scheduling_control->on_duration_timer = 0; struct LTE_DRX_Config__setup *choiceSetup = &drx_Configuration->choice.setup; @@ -1297,13 +1297,13 @@ void eNB_Config_Local_DRX(instance_t Mod_id, } if (choiceSetup->shortDRX == NULL) { - UE_scheduling_control->in_short_drx_cycle = FALSE; + UE_scheduling_control->in_short_drx_cycle = false; UE_scheduling_control->drx_shortCycle_timer_value = 0; UE_scheduling_control->short_drx_cycle_duration = 0; UE_scheduling_control->drx_shortCycle_timer = 0; UE_scheduling_control->drx_shortCycle_timer_thres = -1; } else { - UE_scheduling_control->in_short_drx_cycle = FALSE; + UE_scheduling_control->in_short_drx_cycle = false; UE_scheduling_control->drx_shortCycle_timer_value = (uint8_t) choiceSetup->shortDRX->drxShortCycleTimer; switch (choiceSetup->shortDRX->shortDRX_Cycle) { @@ -1380,7 +1380,7 @@ void eNB_Config_Local_DRX(instance_t Mod_id, UE_scheduling_control->drx_shortCycle_timer_thres = UE_scheduling_control->drx_shortCycle_timer_value * UE_scheduling_control->short_drx_cycle_duration; } - UE_scheduling_control->in_long_drx_cycle = FALSE; + UE_scheduling_control->in_long_drx_cycle = false; UE_scheduling_control->drx_longCycle_timer = 0; switch (choiceSetup->longDRX_CycleStartOffset.present) { diff --git a/openair2/LAYER2/MAC/defs_NB_IoT.h b/openair2/LAYER2/MAC/defs_NB_IoT.h index d4945f0182..abe780741c 100644 --- a/openair2/LAYER2/MAC/defs_NB_IoT.h +++ b/openair2/LAYER2/MAC/defs_NB_IoT.h @@ -243,7 +243,6 @@ typedef struct { // -1:No UE in list int tail; int num_UEs; - //boolean_t active[MAX_MAX_MOBILES_PER_ENB_NB_IoT]; } UE_list_NB_IoT_t; @@ -403,7 +402,7 @@ typedef struct schedule_result{ // pointer to DCI void *DCI_pdu; // when all the procedure related to this DCI, enable this flag - boolean_t DCI_release; + bool DCI_release; // Indicate the channel which to transmit channel_NB_IoT_t channel; // rnti @@ -452,7 +451,7 @@ typedef enum ce_level_e{ /*! \brief eNB template for the Random access information */ typedef struct RA_TEMPLATE_NB_IoT_s{ - boolean_t active; + bool active; uint32_t msg3_retransmit_count; uint32_t msg4_retransmit_count; uint16_t ta; @@ -461,8 +460,8 @@ typedef struct RA_TEMPLATE_NB_IoT_s{ rnti_t ue_rnti; rnti_t ra_rnti; struct RA_TEMPLATE_NB_IoT_s *next, *prev; - boolean_t wait_msg4_ack; - boolean_t wait_msg3_ack; + bool wait_msg4_ack; + bool wait_msg3_ack; uint8_t rar_buffer[7]; } RA_TEMPLATE_NB_IoT; @@ -530,7 +529,7 @@ typedef struct { uint32_t pdus_in_buffer; /*!< \brief Number of PDUs buffered in RLC protocol instance (OBSOLETE). */ uint32_t head_sdu_creation_time; /*!< \brief Head SDU creation time. */ uint32_t head_sdu_remaining_size_to_send; /*!< \brief remaining size of sdu: could be the total size or the remaining size of already segmented sdu */ - boolean_t head_sdu_is_segmented; /*!< \brief 0 if head SDU has not been segmented, 1 if already segmented */ + bool head_sdu_is_segmented; /*!< \brief 0 if head SDU has not been segmented, 1 if already segmented */ } mac_rlc_status_resp_NB_IoT_t; // global variables diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index d647eff7cb..53ab98a33f 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -135,7 +135,7 @@ void schedule_SRS(module_id_t module_idP, UE_scheduling_control = &(UE_info->UE_sched_ctrl[UE_id]); /* Test if Active Time not running since 6+ subframes */ - if (UE_scheduling_control->cdrx_configured == TRUE && UE_scheduling_control->in_active_time == FALSE) { + if (UE_scheduling_control->cdrx_configured == true && UE_scheduling_control->in_active_time == false) { /* * TODO: 6+ subframes condition not checked here */ @@ -204,7 +204,7 @@ void schedule_CSI(module_id_t module_idP, cc = &eNB->common_channels[CC_id]; for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) { - if (UE_info->active[UE_id] == FALSE) { + if (UE_info->active[UE_id] == false) { continue; } @@ -223,9 +223,9 @@ void schedule_CSI(module_id_t module_idP, */ UE_scheduling_control = &(UE_info->UE_sched_ctrl[UE_id]); - if (UE_scheduling_control->cdrx_configured == TRUE) { + if (UE_scheduling_control->cdrx_configured == true) { /* Test if CQI masking activated */ - if (UE_scheduling_control->cqi_mask_boolean == TRUE) { + if (UE_scheduling_control->cqi_mask_boolean == true) { // CQI masking => test if onDurationTime not running since 6+ subframe if (UE_scheduling_control->on_duration_timer == 0) { /* @@ -234,7 +234,7 @@ void schedule_CSI(module_id_t module_idP, continue; } } else { // No CQI masking => test if Active Time not running since 6+ subframe - if (UE_scheduling_control->in_active_time == FALSE) { + if (UE_scheduling_control->in_active_time == false) { /* * TODO: 6+ subframes condition not checked here */ @@ -677,8 +677,8 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, } /* Set and increment CDRX related timers */ - if (UE_scheduling_control->cdrx_configured == TRUE) { - boolean_t harq_active_time_condition = FALSE; + if (UE_scheduling_control->cdrx_configured == true) { + bool harq_active_time_condition = false; UE_TEMPLATE *UE_template = NULL; unsigned long active_time_condition = 0; // variable used only for tracing purpose @@ -721,7 +721,7 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id]++; if (UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id] > 5) { - harq_active_time_condition = TRUE; + harq_active_time_condition = true; UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id] = 0; active_time_condition = 5; // for tracing purpose } @@ -747,24 +747,24 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, /* When timer expires switch into short or long DRX cycle */ if (UE_scheduling_control->drx_shortCycle_timer_thres > 0) { - UE_scheduling_control->in_short_drx_cycle = TRUE; + UE_scheduling_control->in_short_drx_cycle = true; UE_scheduling_control->drx_shortCycle_timer = 0; - UE_scheduling_control->in_long_drx_cycle = FALSE; + UE_scheduling_control->in_long_drx_cycle = false; } else { - UE_scheduling_control->in_long_drx_cycle = TRUE; + UE_scheduling_control->in_long_drx_cycle = true; } } } /* Short DRX Cycle */ - if (UE_scheduling_control->in_short_drx_cycle == TRUE) { + if (UE_scheduling_control->in_short_drx_cycle == true) { UE_scheduling_control->drx_shortCycle_timer++; /* When the Short DRX cycles are over, switch to long DRX cycle */ if (UE_scheduling_control->drx_shortCycle_timer > UE_scheduling_control->drx_shortCycle_timer_thres) { UE_scheduling_control->drx_shortCycle_timer = 0; - UE_scheduling_control->in_short_drx_cycle = FALSE; - UE_scheduling_control->in_long_drx_cycle = TRUE; + UE_scheduling_control->in_short_drx_cycle = false; + UE_scheduling_control->in_long_drx_cycle = true; UE_scheduling_control->drx_longCycle_timer = 0; } } else { @@ -772,7 +772,7 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, } /* Long DRX Cycle */ - if (UE_scheduling_control->in_long_drx_cycle == TRUE) { + if (UE_scheduling_control->in_long_drx_cycle == true) { UE_scheduling_control->drx_longCycle_timer++; if (UE_scheduling_control->drx_longCycle_timer > UE_scheduling_control->drx_longCycle_timer_thres) { @@ -783,18 +783,18 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, } /* Check for error cases */ - if ((UE_scheduling_control->in_short_drx_cycle == TRUE) && (UE_scheduling_control->in_long_drx_cycle == TRUE)) { + if ((UE_scheduling_control->in_short_drx_cycle == true) && (UE_scheduling_control->in_long_drx_cycle == true)) { LOG_E(MAC, "Error in C-DRX: UE id %d is in both short and long DRX cycle. Should not happen. Back it to long cycle only\n", UE_id); - UE_scheduling_control->in_short_drx_cycle = FALSE; + UE_scheduling_control->in_short_drx_cycle = false; } /* Condition to start On Duration Timer */ - if (UE_scheduling_control->in_short_drx_cycle == TRUE && UE_scheduling_control->on_duration_timer == 0) { + if (UE_scheduling_control->in_short_drx_cycle == true && UE_scheduling_control->on_duration_timer == 0) { if (((frameP * 10) + subframeP) % (UE_scheduling_control->short_drx_cycle_duration) == (UE_scheduling_control->drx_start_offset) % (UE_scheduling_control->short_drx_cycle_duration)) { UE_scheduling_control->on_duration_timer = 1; } - } else if (UE_scheduling_control->in_long_drx_cycle == TRUE && UE_scheduling_control->on_duration_timer == 0) { + } else if (UE_scheduling_control->in_long_drx_cycle == true && UE_scheduling_control->on_duration_timer == 0) { if (((frameP * 10) + subframeP) % (UE_scheduling_control->drx_longCycle_timer_thres) == (UE_scheduling_control->drx_start_offset)) { UE_scheduling_control->on_duration_timer = 1; @@ -811,7 +811,7 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, /* (a)synchronous HARQ processes handling for Active Time */ for (int harq_process_id = 0; harq_process_id < 8; harq_process_id++) { if (UE_scheduling_control->drx_retransmission_timer[harq_process_id] > 0) { - harq_active_time_condition = TRUE; + harq_active_time_condition = true; active_time_condition = 2; // for tracing purpose break; } @@ -822,9 +822,9 @@ eNB_dlsch_ulsch_scheduler(module_id_t module_idP, UE_scheduling_control->drx_inactivity_timer > 1 || harq_active_time_condition || UE_template->ul_SR > 0) { - UE_scheduling_control->in_active_time = TRUE; + UE_scheduling_control->in_active_time = true; } else { - UE_scheduling_control->in_active_time = FALSE; + UE_scheduling_control->in_active_time = false; } /* BEGIN VCD */ diff --git a/openair2/LAYER2/MAC/eNB_scheduler_RA.c b/openair2/LAYER2/MAC/eNB_scheduler_RA.c index e5b95a7f47..c659df8d31 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_RA.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_RA.c @@ -1225,7 +1225,7 @@ check_Msg4_retransmission(module_id_t module_idP, int CC_idP, LOG_D(MAC,"[eNB %d][RAPROC] Frame %d, Subframe %d: state:IDLE\n", module_idP, frameP, subframeP); UE_id = find_UE_id(module_idP, ra->rnti); DevAssert(UE_id != -1); - mac->UE_info.UE_template[UE_PCCID(module_idP, UE_id)][UE_id].configured = TRUE; + mac->UE_info.UE_template[UE_PCCID(module_idP, UE_id)][UE_id].configured = true; mac->UE_info.UE_template[UE_PCCID(module_idP, UE_id)][UE_id].pusch_repetition_levels=ra->pusch_repetition_levels; cancel_ra_proc(module_idP, CC_idP, frameP, ra->rnti); } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 596d978a98..0898622115 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -2075,7 +2075,7 @@ schedule_PCH(module_id_t module_idP, for (uint16_t i = 0; i < MAX_MOBILES_PER_ENB; i++) { ue_pf_po = &UE_PF_PO[CC_id][i]; - if (ue_pf_po->enable_flag != TRUE) { + if (ue_pf_po->enable_flag != true) { continue; } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c b/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c index 6c9ffabd4f..9836b643d4 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c @@ -69,7 +69,7 @@ int last_ulsch_ue_id_volte[MAX_NUM_CCs] = {-1}; uint16_t pre_nb_rbs_required[2][MAX_NUM_CCs][NUMBER_OF_UE_MAX]; uint8_t dlsch_ue_select_tbl_in_use; uint8_t new_dlsch_ue_select_tbl_in_use; - boolean_t pre_scd_activeUE[NUMBER_OF_UE_MAX]; + bool pre_scd_activeUE[NUMBER_OF_UE_MAX]; eNB_UE_STATS pre_scd_eNB_UE_stats[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; #endif @@ -125,7 +125,7 @@ void pre_scd_nb_rbs_required( module_id_t module_idP, UE_info_t *UE_info = &RC.mac[module_idP]->UE_info; for (UE_id = 0; UE_id DL_req[CC_id].dl_config_request_body; for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { - if (UE_info->active[UE_id] == FALSE) { + if (UE_info->active[UE_id] == false) { continue; } @@ -331,7 +331,7 @@ void dlsch_scheduler_pre_ue_select_fairRR( break; } - if (UE_info->active[UE_id] == FALSE) { + if (UE_info->active[UE_id] == false) { continue; } @@ -459,7 +459,7 @@ void dlsch_scheduler_pre_ue_select_fairRR( break; } - if (UE_info->active[UE_id] == FALSE) { + if (UE_info->active[UE_id] == false) { continue; } @@ -607,7 +607,7 @@ static void dlsch_scheduler_pre_processor_reset_fairRR( if (rnti == NOT_A_RNTI) continue; - if (UE_info->active[UE_id] != TRUE) + if (UE_info->active[UE_id] != true) continue; LOG_D(MAC, "Running preprocessor for UE %d (%x)\n", UE_id, rnti); @@ -755,7 +755,7 @@ static void assign_rbs_required_fairRR( // clear rb allocations across all CC_id for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) { - if (UE_info->active[UE_id] != TRUE) + if (UE_info->active[UE_id] != true) continue; pCCid = UE_PCCID(Mod_id, UE_id); @@ -945,7 +945,7 @@ void dlsch_scheduler_pre_processor_fairRR (module_id_t Mod_id, min_rb_unit[CC_id] = get_min_rb_unit(Mod_id, CC_id); for (i = 0; i < NUMBER_OF_UE_MAX; i++) { - if (UE_info->active[i] != TRUE) + if (UE_info->active[i] != true) continue; UE_id = i; @@ -2241,7 +2241,7 @@ void ulsch_scheduler_pre_ue_select_fairRR( // UE round >0 for ( UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++ ) { - if (UE_info->active[UE_id] == FALSE) + if (UE_info->active[UE_id] == false) continue; rnti = UE_RNTI(module_idP,UE_id); @@ -2251,7 +2251,7 @@ void ulsch_scheduler_pre_ue_select_fairRR( CC_id = UE_PCCID(module_idP,UE_id); - if (UE_info->UE_template[CC_id][UE_id].configured == FALSE) + if (UE_info->UE_template[CC_id][UE_id].configured == false) continue; if (UE_info->UE_sched_ctrl[UE_id].ul_failure_timer > 0 @@ -2401,7 +2401,7 @@ void ulsch_scheduler_pre_ue_select_fairRR( } for ( UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++ ) { - if (UE_info->active[UE_id] == FALSE) + if (UE_info->active[UE_id] == false) continue; rnti = UE_RNTI(module_idP,UE_id); @@ -2414,7 +2414,7 @@ void ulsch_scheduler_pre_ue_select_fairRR( if (UE_id > last_ulsch_ue_id[CC_id]) continue; - if (UE_info->UE_template[CC_id][UE_id].configured == FALSE) + if (UE_info->UE_template[CC_id][UE_id].configured == false) continue; if (UE_info->UE_sched_ctrl[UE_id].ul_failure_timer > 0 diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index d53e0cadd3..4469d0a3f9 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -1989,7 +1989,7 @@ find_UE_id(module_id_t mod_idP, return -1; for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) { - if (UE_info->active[UE_id] == TRUE) { + if (UE_info->active[UE_id] == true) { int CC_id = UE_PCCID(mod_idP, UE_id); if (CC_id>=0 && CC_idUE_template[CC_id][UE_id].rnti == rntiP) { return UE_id; @@ -2063,7 +2063,7 @@ UE_RNTI(module_id_t mod_idP, } //------------------------------------------------------------------------------ -boolean_t +bool is_UE_active(module_id_t mod_idP, int ue_idP) //------------------------------------------------------------------------------ @@ -2187,20 +2187,20 @@ add_new_ue(module_id_t mod_idP, UE_info->num_UEs); for (i = 0; i < MAX_MOBILES_PER_ENB; i++) { - if (UE_info->active[i] == TRUE) + if (UE_info->active[i] == true) continue; UE_id = i; memset(&UE_info->UE_template[cc_idP][UE_id], 0, sizeof(UE_TEMPLATE)); UE_info->UE_template[cc_idP][UE_id].rnti = rntiP; - UE_info->UE_template[cc_idP][UE_id].configured = FALSE; + UE_info->UE_template[cc_idP][UE_id].configured = false; UE_info->numactiveCCs[UE_id] = 1; UE_info->numactiveULCCs[UE_id] = 1; UE_info->pCC_id[UE_id] = cc_idP; UE_info->ordered_CCids[0][UE_id] = cc_idP; UE_info->ordered_ULCCids[0][UE_id] = cc_idP; UE_info->num_UEs++; - UE_info->active[UE_id] = TRUE; + UE_info->active[UE_id] = true; add_ue_list(&UE_info->list, UE_id); dump_ue_list(&UE_info->list); pp_impl_param_t* dl = &RC.mac[mod_idP]->pre_processor_dl; @@ -2280,7 +2280,7 @@ rrc_mac_remove_ue(module_id_t mod_idP, UE_id, pCC_id, rntiP); - UE_info->active[UE_id] = FALSE; + UE_info->active[UE_id] = false; UE_info->num_UEs--; remove_ue_list(&UE_info->list, UE_id); @@ -3488,7 +3488,7 @@ has_ul_grant(module_id_t module_idP, } //------------------------------------------------------------------------------ -boolean_t +bool CCE_allocation_infeasible(int module_idP, int CC_idP, int format_flag, @@ -3501,7 +3501,7 @@ CCE_allocation_infeasible(int module_idP, nfapi_dl_config_request_pdu_t *dl_config_pdu = &DL_req->dl_config_pdu_list[DL_req->number_pdu]; nfapi_hi_dci0_request_body_t *HI_DCI0_req = &RC.mac[module_idP]->HI_DCI0_req[CC_idP][subframe].hi_dci0_request_body; nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &HI_DCI0_req->hi_dci0_pdu_list[HI_DCI0_req->number_of_dci + HI_DCI0_req->number_of_hi]; - boolean_t res = TRUE; + bool res = true; if (format_flag != 2) { // DL DCI if (DL_req->number_pdu == MAX_NUM_DL_PDU) { @@ -3517,7 +3517,7 @@ CCE_allocation_infeasible(int module_idP, subframe, format_flag, rnti, aggregation); if (allocate_CCEs(module_idP, CC_idP, 0, subframe, 0) != -1) - res = FALSE; + res = false; DL_req->number_pdu--; } @@ -3532,7 +3532,7 @@ CCE_allocation_infeasible(int module_idP, HI_DCI0_req->number_of_dci++; if (allocate_CCEs(module_idP, CC_idP, 0, subframe, 0) != -1) - res = FALSE; + res = false; HI_DCI0_req->number_of_dci--; } @@ -5029,7 +5029,7 @@ SR_indication(module_id_t mod_idP, if (UE_id != -1) { UE_scheduling_ctrl = &(UE_info->UE_sched_ctrl[UE_id]); - if ((UE_scheduling_ctrl->cdrx_configured == TRUE) && + if ((UE_scheduling_ctrl->cdrx_configured == true) && (UE_scheduling_ctrl->dci0_ongoing_timer > 0) && (UE_scheduling_ctrl->dci0_ongoing_timer < 8)) { LOG_D(MAC, "[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d on CC_id %d. \ @@ -5052,7 +5052,7 @@ SR_indication(module_id_t mod_idP, } UE_info->UE_template[cc_idP][UE_id].ul_SR = 1; - UE_info->UE_template[cc_idP][UE_id].ul_active = TRUE; + UE_info->UE_template[cc_idP][UE_id].ul_active = true; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION, 1); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION, 0); } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index d4f486f761..a31b8bdd03 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -242,7 +242,7 @@ rx_sdu(const module_id_t enb_mod_idP, } /* CDRX UL HARQ timers */ - if (UE_scheduling_control->cdrx_configured == TRUE) { + if (UE_scheduling_control->cdrx_configured == true) { /* Synchronous UL HARQ */ UE_scheduling_control->ul_synchronous_harq_timer[CC_idP][harq_pid] = 5; /* @@ -1003,7 +1003,7 @@ rx_sdu(const module_id_t enb_mod_idP, /* CDRX UL HARQ timers */ if (UE_id != -1) { - if (UE_scheduling_control->cdrx_configured == TRUE) { + if (UE_scheduling_control->cdrx_configured == true) { /* Synchronous UL HARQ */ UE_scheduling_control->ul_synchronous_harq_timer[CC_idP][harq_pid] = 5; /* @@ -1447,7 +1447,7 @@ schedule_ulsch_rnti(module_id_t module_idP, continue; // don't schedule if Msg5 is not received yet - if (UE_info->UE_template[CC_id][UE_id].configured == FALSE) { + if (UE_info->UE_template[CC_id][UE_id].configured == false) { LOG_D(MAC, "[eNB %d] frame %d, subframe %d, UE %d: not configured, skipping " "UE scheduling \n", @@ -2033,7 +2033,7 @@ void schedule_ulsch_rnti_emtc(module_id_t module_idP, } /* Don't schedule if Msg4 is not received yet */ - if (UE_template->configured == FALSE) { + if (UE_template->configured == false) { LOG_D(MAC,"[eNB %d] frame %d subframe %d, UE %d: not configured, skipping UE scheduling \n", module_idP, frameP, diff --git a/openair2/LAYER2/MAC/mac.h b/openair2/LAYER2/MAC/mac.h index 6637d05a8a..2392c8506b 100644 --- a/openair2/LAYER2/MAC/mac.h +++ b/openair2/LAYER2/MAC/mac.h @@ -811,9 +811,9 @@ typedef struct { /// TBS from last UL scheduling int TBS_UL[8]; /// Flag to indicate UL has been scheduled at least once - boolean_t ul_active; + bool ul_active; /// Flag to indicate UE has been configured (ACK from RRCConnectionSetup received) - boolean_t configured; + bool configured; /// MCS from last scheduling uint8_t mcs[8]; @@ -1026,16 +1026,16 @@ typedef struct { /* C-DRX related timers */ /* Note: only valid for FDD and LTE UE when this comment is written (11-01-19)*/ - /// is TRUE if the cqi mask feature is activated by RRC configuration - boolean_t cqi_mask_boolean; - /// is TRUE if the following drx parameters are configured for UE - boolean_t cdrx_configured; + /// is true if the cqi mask feature is activated by RRC configuration + bool cqi_mask_boolean; + /// is true if the following drx parameters are configured for UE + bool cdrx_configured; /* - * if TRUE, the eNB has configured the CDRX locally, but is waiting for the UE to acknowledge + * if true, the eNB has configured the CDRX locally, but is waiting for the UE to acknowledge * the activation. This is needed, during the RRC configuration process, when the context is * configured on the eNB side, but not yet on the UE side... */ - boolean_t cdrx_waiting_ack; + bool cdrx_waiting_ack; /* * Is set when a ULSCH scheduling is done and run until the first corresponding transmission is done (4 subframes). * When set, SR cannot be set for the UE. This allows OAI to avoid concidering a SR as uncompleted if the UE sends @@ -1043,16 +1043,16 @@ typedef struct { * create a lost in timers synchronization. */ uint8_t dci0_ongoing_timer; - /// is TRUE if the UE is in "Active Time", hence listening to PDCCH - boolean_t in_active_time; + /// is true if the UE is in "Active Time", hence listening to PDCCH + bool in_active_time; /// OnDurationTimer uint16_t on_duration_timer; uint16_t on_duration_timer_thres; /// drx-InactivityTimer uint16_t drx_inactivity_timer; uint16_t drx_inactivity_timer_thres; - /// is TRUE if UE is currently in short DRX cycle - boolean_t in_short_drx_cycle; + /// is true if UE is currently in short DRX cycle + bool in_short_drx_cycle; /// drxShortCycleTimer int (1..16) (number of short DRX cycles duration before long DRX cycles) uint8_t drx_shortCycle_timer_value; /// shortDRX-Cycle (duration of one short DRX cycle) @@ -1060,8 +1060,8 @@ typedef struct { /// DRX short cycle timer before switching to long DRX cycle = drx_shortCycle_timer_value * short_drx_cycle_duration uint16_t drx_shortCycle_timer; uint16_t drx_shortCycle_timer_thres; - /// is TRUE if UE is currently in long DRX cycle - boolean_t in_long_drx_cycle; + /// is true if UE is currently in long DRX cycle + bool in_long_drx_cycle; /// longDRX-CycleStartOffset (long DRX cycle timer) uint16_t drx_longCycle_timer; uint16_t drx_longCycle_timer_thres; @@ -1183,7 +1183,7 @@ typedef struct { UE_sched_ctrl_t UE_sched_ctrl[MAX_MOBILES_PER_ENB]; UE_list_t list; int num_UEs; - boolean_t active[MAX_MOBILES_PER_ENB]; + bool active[MAX_MOBILES_PER_ENB]; } UE_info_t; /*! \brief deleting control information*/ @@ -1191,9 +1191,9 @@ typedef struct { ///rnti of UE rnti_t rnti; ///remove UE context flag - boolean_t removeContextFlg; + bool removeContextFlg; ///remove RA flag - boolean_t raFlag; + bool raFlag; } UE_free_ctrl_t; /*! \brief REMOVE UE list used by eNB to order UEs/CC for deleting*/ typedef struct { diff --git a/openair2/LAYER2/MAC/mac_extern.h b/openair2/LAYER2/MAC/mac_extern.h index 522dc2721f..212422898b 100644 --- a/openair2/LAYER2/MAC/mac_extern.h +++ b/openair2/LAYER2/MAC/mac_extern.h @@ -71,7 +71,7 @@ extern rb_id_t mbms_rab_id; extern uint16_t pre_nb_rbs_required[2][MAX_NUM_CCs][NUMBER_OF_UE_MAX]; extern uint8_t dlsch_ue_select_tbl_in_use; extern uint8_t new_dlsch_ue_select_tbl_in_use; -extern boolean_t pre_scd_activeUE[NUMBER_OF_UE_MAX]; +extern bool pre_scd_activeUE[NUMBER_OF_UE_MAX]; extern eNB_UE_STATS pre_scd_eNB_UE_stats[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; #endif diff --git a/openair2/LAYER2/MAC/mac_proto.h b/openair2/LAYER2/MAC/mac_proto.h index b92ce85608..889c727fdd 100644 --- a/openair2/LAYER2/MAC/mac_proto.h +++ b/openair2/LAYER2/MAC/mac_proto.h @@ -400,7 +400,7 @@ int find_RA_id(module_id_t mod_idP, int CC_idP, rnti_t rntiP); rnti_t UE_RNTI(module_id_t module_idP, int UE_id); int UE_PCCID(module_id_t module_idP, int UE_id); uint8_t find_active_UEs(module_id_t module_idP); -boolean_t is_UE_active(module_id_t module_idP, int UE_id); +bool is_UE_active(module_id_t module_idP, int UE_id); uint8_t get_aggregation(uint8_t bw_index, uint8_t cqi, uint8_t dci_fmt); int8_t find_active_UEs_with_traffic(module_id_t module_idP); @@ -416,11 +416,11 @@ int get_nCCE_offset(int *CCE_table, int allocate_CCEs(int module_idP, int CC_idP, frame_t frameP, sub_frame_t subframeP, int test_only); -boolean_t CCE_allocation_infeasible(int module_idP, - int CC_idP, - int common_flag, - int subframe, - int aggregation, int rnti); +bool CCE_allocation_infeasible(int module_idP, + int CC_idP, + int common_flag, + int subframe, + int aggregation, int rnti); /* tries to allocate a CCE. If it succeeds, reserves NFAPI DCI and DLSCH config */ int CCE_try_allocate_dlsch(int module_id, int CC_id, @@ -741,13 +741,12 @@ BSR_SHORT *get_bsr_short(module_id_t module_idP, uint8_t bsr_len); */ BSR_LONG *get_bsr_long(module_id_t module_idP, uint8_t bsr_len); -/*! \fn boolean_t update_bsr(module_id_t module_idP, frame_t frameP,sub_frame_t subframeP) +/*! \fn bool update_bsr(module_id_t module_idP, frame_t frameP,sub_frame_t subframeP) \brief get the rlc stats and update the bsr level for each lcid \param[in] Mod_id instance of the UE \param[in] frame Frame index */ -boolean_t update_bsr(module_id_t module_idP, frame_t frameP, - sub_frame_t subframeP, eNB_index_t eNB_index); +bool update_bsr(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP, eNB_index_t eNB_index); /*! \fn locate_BsrIndexByBufferSize (int *table, int size, int value) \brief locate the BSR level in the table as defined in 36.321. This function requires that he values in table to be monotonic, either increasing or decreasing. The returned value is not less than 0, nor greater than n-1, where n is the size of table. diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index bb969668d6..db4d51a92f 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -638,7 +638,7 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id, LOG_E(MAC, "UE %d has RNTI NOT_A_RNTI!\n", UE_id); continue; } - if (UE_info->active[UE_id] != TRUE) { + if (UE_info->active[UE_id] != true) { LOG_E(MAC, "UE %d RNTI %x is NOT active!\n", UE_id, rnti); continue; } diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 926c44381c..d7796d1d40 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -2325,8 +2325,8 @@ ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP, uint8_t bsr_len = 0, bsr_ce_len = 0, bsr_header_len = 0; uint8_t phr_header_len = 0, phr_ce_len = 0, phr_len = 0; uint8_t lcid = 0, lcid_rlc_pdu_count = 0; - boolean_t is_lcid_processed = FALSE; - boolean_t is_all_lcid_processed = FALSE; + bool is_lcid_processed = false; + bool is_all_lcid_processed = false; uint16_t sdu_lengths[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; uint8_t sdu_lcids[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; uint8_t payload_offset = 0, num_sdus = 0; @@ -2444,11 +2444,11 @@ ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP, // Check for DCCH first // TO DO: Multiplex in the order defined by the logical channel prioritization for (lcid = DCCH; - (lcid < MAX_NUM_LCID) && (is_all_lcid_processed == FALSE); lcid++) { + (lcid < MAX_NUM_LCID) && (is_all_lcid_processed == false); lcid++) { if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) { lcid_rlc_pdu_count = 0; - is_lcid_processed = FALSE; + is_lcid_processed = false; lcid_buffer_occupancy_old = mac_rlc_get_buffer_occupancy_ind(module_idP, UE_mac_inst[module_idP]. @@ -2536,8 +2536,8 @@ ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP, //No more remaining TBS after this PDU //exit the function rlc_pdu_header_len_last = 1; - is_lcid_processed = TRUE; - is_all_lcid_processed = TRUE; + is_lcid_processed = true; + is_all_lcid_processed = true; } else { rlc_pdu_header_len_last = (sdu_lengths[num_sdus] > 128) ? 3 : 2; @@ -2547,8 +2547,8 @@ ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP, (bsr_len + phr_len + total_rlc_pdu_header_len + rlc_pdu_header_len_last + sdu_length_total)) { rlc_pdu_header_len_last = 1; - is_lcid_processed = TRUE; - is_all_lcid_processed = TRUE; + is_lcid_processed = true; + is_all_lcid_processed = true; } } @@ -2559,7 +2559,7 @@ ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP, lcid_rlc_pdu_count++; } else { /* avoid infinite loop ... */ - is_lcid_processed = TRUE; + is_lcid_processed = true; } /* Get updated BO after multiplexing this PDU */ @@ -3164,7 +3164,7 @@ ue_scheduler(const module_id_t module_idP, } //Check whether Regular BSR is triggered - if (update_bsr(module_idP, txFrameP, txSubframeP, eNB_indexP) == TRUE) { + if (update_bsr(module_idP, txFrameP, txSubframeP, eNB_indexP) == true) { // call SR procedure to generate pending SR and BSR for next PUCCH/PUSCH TxOp. This should implement the procedures // outlined in Sections 5.4.4 an 5.4.5 of 36.321 UE_mac_inst[module_idP].scheduling_info.SR_pending = 1; @@ -3251,11 +3251,11 @@ ue_scheduler(const module_id_t module_idP, // to be improved -boolean_t +bool update_bsr(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP, eNB_index_t eNB_index) { mac_rlc_status_resp_t rlc_status; - boolean_t bsr_regular_triggered = FALSE; + bool bsr_regular_triggered = false; uint8_t lcid; uint8_t lcgid; uint8_t num_lcid_with_data = 0; // for LCID with data only if LCGID is defined @@ -3352,7 +3352,7 @@ update_bsr(module_id_t module_idP, frame_t frameP, (lcgid_buffer_remain [UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] == 0)) { - bsr_regular_triggered = TRUE; + bsr_regular_triggered = true; LOG_D(MAC, "[UE %d] PDCCH Tick : MAC BSR Triggered LCID%d LCGID%d data become available at frame %d subframe %d\n", module_idP, lcid, @@ -3364,7 +3364,7 @@ update_bsr(module_id_t module_idP, frame_t frameP, // Trigger Regular BSR if ReTxBSR Timer has expired and UE has data for transmission if (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF == 0) { - bsr_regular_triggered = TRUE; + bsr_regular_triggered = true; if ((UE_mac_inst[module_idP].BSR_reporting_active & BSR_TRIGGER_REGULAR) == 0) { diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h index 4b37c19dff..7bbe8d68a7 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h @@ -74,7 +74,7 @@ extern uint8_t rb_table[34]; extern uint16_t pre_nb_rbs_required[2][MAX_NUM_CCs][NUMBER_OF_UE_MAX]; extern uint8_t dlsch_ue_select_tbl_in_use; extern uint8_t new_dlsch_ue_select_tbl_in_use; -extern boolean_t pre_scd_activeUE[NUMBER_OF_UE_MAX]; +extern bool pre_scd_activeUE[NUMBER_OF_UE_MAX]; extern eNB_UE_STATS pre_scd_eNB_UE_stats[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; #endif*/ diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 5ffccf28d3..072f0e58de 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -580,7 +580,7 @@ int nr_rrc_mac_config_req_ue_logicalChannelBearer( int cc_idP, uint8_t gNB_index, long logicalChannelIdentity, - boolean_t status){ + bool status){ NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); mac->logicalChannelBearer_exist[logicalChannelIdentity] = status; return 0; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 800e042464..05b6634655 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -415,7 +415,7 @@ typedef struct { uint8_t BSR_reporting_active; /// LogicalChannelConfig has bearer. - boolean_t logicalChannelBearer_exist[NR_MAX_NUM_LCID]; + bool logicalChannelBearer_exist[NR_MAX_NUM_LCID]; NR_UE_SCHEDULING_INFO scheduling_info; /// PHR @@ -546,7 +546,7 @@ typedef struct prach_association_pattern { // SSB details typedef struct ssb_info { - boolean_t transmitted; // True if the SSB index is transmitted according to the SSB positions map configuration + bool transmitted; // True if the SSB index is transmitted according to the SSB positions map configuration prach_occasion_info_t *mapped_ro[MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN]; // List of mapped RACH Occasions to this SSB index uint16_t nb_mapped_ro; // Total number of mapped ROs to this SSB index } ssb_info_t; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index caa4af4144..38f774be76 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -85,14 +85,12 @@ int8_t nr_ue_decode_BCCH_DL_SCH(module_id_t module_id, \param cc_id component carrier id \param gNB_index gNB index \param long logicalChannelIdentity - \param boolean_t status*/ -int nr_rrc_mac_config_req_ue_logicalChannelBearer( - module_id_t module_id, - int cc_idP, - uint8_t gNB_index, - long logicalChannelIdentity, - boolean_t status -); + \param bool status*/ +int nr_rrc_mac_config_req_ue_logicalChannelBearer(module_id_t module_id, + int cc_idP, + uint8_t gNB_index, + long logicalChannelIdentity, + bool status); /**\brief primitive from RRC layer to MAC layer for configuration L1/L2, now supported 4 rrc messages: MIB, cell_group_config for MAC/PHY, spcell_config(serving cell config) \param module_id module id @@ -154,14 +152,14 @@ void fill_scheduled_response(nr_scheduled_response_t *scheduled_response, */ int8_t nr_ue_get_SR(module_id_t module_idP, frame_t frameP, slot_t slotP); -/*! \fn boolean_t update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t gNB_index) +/*! \fn bool update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t gNB_index) \brief get the rlc stats and update the bsr level for each lcid \param[in] Mod_id instance of the UE \param[in] frameP Frame index \param[in] slot slotP number \param[in] uint8_t gNB_index */ -boolean_t nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t gNB_index); +bool nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t gNB_index); /*! \fn nr_locate_BsrIndexByBufferSize (int *table, int size, int value) \brief locate the BSR level in the table as defined in 38.321. This function requires that he values in table to be monotonic, either increasing or decreasing. The returned value is not less than 0, nor greater than n-1, where n is the size of table. diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index 735ff1bd54..507cdb2661 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -325,7 +325,7 @@ void ssb_rach_config(RA_config_t *ra, NR_PRACH_RESOURCES_t *prach_resources, NR_ // ======================================= NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR ssb_perRACH_config = nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present; - boolean_t multiple_ssb_per_ro; // true if more than one or exactly one SSB per RACH occasion, false if more than one RO per SSB + bool multiple_ssb_per_ro; // true if more than one or exactly one SSB per RACH occasion, false if more than one RO per SSB uint8_t ssb_rach_ratio; // Nb of SSBs per RACH or RACHs per SSB int total_preambles_per_ssb; uint8_t ssb_nb_in_ro; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 50ea7cdd34..6166fc7038 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2002,7 +2002,7 @@ int find_pucch_resource_set(NR_UE_MAC_INST_t *mac, int uci_size) { * processing slots of reception/transmission * gNB_id identifier * -* RETURN : TRUE a valid resource has been found +* RETURN : true a valid resource has been found * * DESCRIPTION : return tx harq process identifier for given transmission slot * TS 38.213 9.2.1 PUCCH Resource Sets @@ -2132,7 +2132,7 @@ uint8_t get_downlink_ack(NR_UE_MAC_INST_t *mac, int number_harq_feedback = 0; uint32_t dai_current = 0; uint32_t dai_max = 0; - bool two_transport_blocks = FALSE; + bool two_transport_blocks = false; int number_of_code_word = 1; int U_DAI_c = 0; int N_m_c_rx = 0; @@ -2154,7 +2154,7 @@ uint8_t get_downlink_ack(NR_UE_MAC_INST_t *mac, bwpd->pdsch_Config->choice.setup && bwpd->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI && bwpd->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI[0] == 2) { - two_transport_blocks = TRUE; + two_transport_blocks = true; number_of_code_word = 2; } @@ -2254,7 +2254,7 @@ uint8_t get_downlink_ack(NR_UE_MAC_INST_t *mac, * For a monitoring occasion of a PDCCH with DCI format 1_0 or DCI format 1_1 in at least one serving cell, * when a UE receives a PDSCH with one transport block and the value of higher layer parameter maxNrofCodeWordsScheduledByDCI is 2, * the HARQ-ACK response is associated with the first transport block and the UE generates a NACK for the second transport block - * if spatial bundling is not applied (HARQ-ACK-spatial-bundling-PUCCH = FALSE) and generates HARQ-ACK value of ACK for the second + * if spatial bundling is not applied (HARQ-ACK-spatial-bundling-PUCCH = false) and generates HARQ-ACK value of ACK for the second * transport block if spatial bundling is applied. */ @@ -2265,7 +2265,7 @@ uint8_t get_downlink_ack(NR_UE_MAC_INST_t *mac, ack_data[code_word][i] = 0; /* nack data transport block which has been missed */ number_harq_feedback++; } - if (two_transport_blocks == TRUE) { + if (two_transport_blocks == true) { dai_total[code_word][i] = dai[code_word][i]; /* for a single cell, dai_total is the same as dai of first cell */ } } @@ -2296,7 +2296,7 @@ uint8_t get_downlink_ack(NR_UE_MAC_INST_t *mac, o_ACK = o_ACK | (ack_data[1][m] << O_bit_number_cw1); } - if (two_transport_blocks == TRUE) { + if (two_transport_blocks == true) { O_bit_number_cw0 = (8 * j) + 2*(V_temp - 1); } else { @@ -2311,7 +2311,7 @@ uint8_t get_downlink_ack(NR_UE_MAC_INST_t *mac, j = j + 1; } - if (two_transport_blocks == TRUE) { + if (two_transport_blocks == true) { O_ACK = 2 * ( 4 * j + V_temp2); /* for two transport blocks */ } else { diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index ad6bf3cdc4..f6a42ccaab 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -1247,7 +1247,7 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in } //Check whether Regular BSR is triggered - if (nr_update_bsr(mod_id, txFrameP, txSlotP, gNB_indexP) == TRUE) { + if (nr_update_bsr(mod_id, txFrameP, txSlotP, gNB_indexP) == true) { // call SR procedure to generate pending SR and BSR for next PUCCH/PUSCH TxOp. This should implement the procedures // outlined in Sections 5.4.4 an 5.4.5 of 38.321 mac->scheduling_info.SR_pending = 1; @@ -1260,10 +1260,10 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in } -boolean_t +bool nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t gNB_index) { mac_rlc_status_resp_t rlc_status; - boolean_t bsr_regular_triggered = FALSE; + bool bsr_regular_triggered = false; uint8_t lcid; uint8_t lcgid; uint8_t num_lcid_with_data = 0; // for LCID with data only if LCGID is defined @@ -1356,7 +1356,7 @@ nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t gNB_ which belong to any LCG and for which data is already available for transmission */ { - bsr_regular_triggered = TRUE; + bsr_regular_triggered = true; LOG_D(NR_MAC, "[UE %d] PDCCH Tick : MAC BSR Triggered LCID%d LCGID%d data become available at frame %d slot %d\n", module_idP, lcid, mac->scheduling_info.LCGID[lcid], @@ -1367,7 +1367,7 @@ nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t gNB_ // Trigger Regular BSR if ReTxBSR Timer has expired and UE has data for transmission if (mac->scheduling_info.retxBSR_SF == 0) { - bsr_regular_triggered = TRUE; + bsr_regular_triggered = true; if ((mac->BSR_reporting_active & NR_BSR_TRIGGER_REGULAR) == 0) { LOG_I(NR_MAC, "[UE %d] PDCCH Tick : MAC BSR Triggered ReTxBSR Timer expiry at frame %d slot %d\n", @@ -1628,7 +1628,7 @@ static void build_ro_list(NR_UE_MAC_INST_t *mac) { int y2; // PRACH Configuration Index table additional variable used to compute the valid frame numbers uint8_t slot_shift_for_map; uint8_t map_shift; - boolean_t even_slot_invalid; + bool even_slot_invalid; int64_t s_map; uint8_t prach_conf_start_symbol; // Starting symbol of the PRACH occasions in the PRACH slot uint8_t N_t_slot; // Number of PRACH occasions in a 14-symbols PRACH slot @@ -1900,7 +1900,7 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac) { mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.rach_ConfigCommon->choice.setup; NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR ssb_perRACH_config = setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present; - boolean_t multiple_ssb_per_ro; // true if more than one or exactly one SSB per RACH occasion, false if more than one RO per SSB + bool multiple_ssb_per_ro; // true if more than one or exactly one SSB per RACH occasion, false if more than one RO per SSB uint8_t ssb_rach_ratio; // Nb of SSBs per RACH or RACHs per SSB uint16_t required_nb_of_prach_occasion; // Nb of RACH occasions required to map all the SSBs uint8_t required_nb_of_prach_conf_period; // Nb of PRACH configuration periods required to map all the SSBs diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 7658441aed..343b72d6a6 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -673,7 +673,6 @@ typedef struct { } NR_UE_sched_ctrl_t; typedef struct { - boolean_t fiveG_connected; uicc_t *uicc; } NRUEcontext_t; diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index 108a5dbe91..9adc6ecb5d 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -139,7 +139,7 @@ extern volatile int oai_exit; pthread_t pdcp_stats_thread_desc; // will be called when 4G F1 implementation will use GTP-U instead of protobuf -boolean_t cu_f1u_data_req( +bool cu_f1u_data_req( protocol_ctxt_t *ctxt_pP, const srb_flag_t srb_flagP, const rb_id_t rb_id, @@ -228,7 +228,7 @@ rlc_op_status_t cu_send_to_du(const protocol_ctxt_t *const ctxt, __func__, rb_id, size); extern instance_t CUuniqInstance; itti_send_msg_to_task(TASK_GTPV1_U, CUuniqInstance, message_p); - return TRUE; + return true; } //----------------------------------------------------------------------------- @@ -239,18 +239,16 @@ rlc_op_status_t cu_send_to_du(const protocol_ctxt_t *const ctxt, * this mem_block_t to be dissected for testing purposes. For further details see test * code at targets/TEST/PDCP/test_pdcp.c:test_pdcp_data_req() */ -boolean_t pdcp_data_req( - protocol_ctxt_t *ctxt_pP, - const srb_flag_t srb_flagP, - const rb_id_t rb_idP, - const mui_t muiP, - const confirm_t confirmP, - const sdu_size_t sdu_buffer_sizeP, - unsigned char *const sdu_buffer_pP, - const pdcp_transmission_mode_t modeP, - const uint32_t *const sourceL2Id, - const uint32_t *const destinationL2Id -) +bool pdcp_data_req(protocol_ctxt_t *ctxt_pP, + const srb_flag_t srb_flagP, + const rb_id_t rb_idP, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_buffer_sizeP, + unsigned char *const sdu_buffer_pP, + const pdcp_transmission_mode_t modeP, + const uint32_t *const sourceL2Id, + const uint32_t *const destinationL2Id) //----------------------------------------------------------------------------- { pdcp_t *pdcp_p = NULL; @@ -261,7 +259,7 @@ boolean_t pdcp_data_req( uint16_t current_sn = 0; mem_block_t *pdcp_pdu_p = NULL; rlc_op_status_t rlc_status; - boolean_t ret = TRUE; + bool ret = true; hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; uint8_t rb_offset= (srb_flagP == 0) ? DTCH -1 : 0; @@ -277,7 +275,7 @@ boolean_t pdcp_data_req( if (sdu_buffer_sizeP == 0) { LOG_W(PDCP, "Handed SDU is of size 0! Ignoring...\n"); - return FALSE; + return false; } /* @@ -287,12 +285,12 @@ boolean_t pdcp_data_req( sdu_buffer_sizeP, MAX_IP_PACKET_SIZE); if (modeP == PDCP_TRANSMISSION_MODE_TRANSPARENT) { - AssertError (rb_idP < NB_RB_MBMS_MAX, return FALSE, "RB id is too high (%ld/%d) %u %u!\n", rb_idP, NB_RB_MBMS_MAX, ctxt_pP->module_id, ctxt_pP->rnti); + AssertError (rb_idP < NB_RB_MBMS_MAX, return false, "RB id is too high (%ld/%d) %u %u!\n", rb_idP, NB_RB_MBMS_MAX, ctxt_pP->module_id, ctxt_pP->rnti); } else { if (srb_flagP) { - AssertError (rb_idP < 3, return FALSE, "RB id is too high (%ld/%d) %u %u!\n", rb_idP, 3, ctxt_pP->module_id, ctxt_pP->rnti); + AssertError (rb_idP < 3, return false, "RB id is too high (%ld/%d) %u %u!\n", rb_idP, 3, ctxt_pP->module_id, ctxt_pP->rnti); } else { - AssertError (rb_idP < LTE_maxDRB, return FALSE, "RB id is too high (%ld/%d) %u %u!\n", rb_idP, LTE_maxDRB, ctxt_pP->module_id, ctxt_pP->rnti); + AssertError (rb_idP < LTE_maxDRB, return false, "RB id is too high (%ld/%d) %u %u!\n", rb_idP, LTE_maxDRB, ctxt_pP->module_id, ctxt_pP->rnti); } } @@ -304,7 +302,7 @@ boolean_t pdcp_data_req( LOG_W(PDCP, PROTOCOL_CTXT_FMT" Instance is not configured for rb_id %ld Ignoring SDU...\n", PROTOCOL_CTXT_ARGS(ctxt_pP), rb_idP); - return FALSE; + return false; } } @@ -371,7 +369,7 @@ boolean_t pdcp_data_req( memset(&pdu_header.mac_i[0],0,PDCP_CONTROL_PLANE_DATA_PDU_MAC_I_SIZE); memset(&pdcp_pdu_p->data[sdu_buffer_sizeP + pdcp_header_len],0,PDCP_CONTROL_PLANE_DATA_PDU_MAC_I_SIZE); - if (pdcp_serialize_control_plane_data_pdu_with_SRB_sn_buffer((unsigned char *)pdcp_pdu_p->data, &pdu_header) == FALSE) { + if (pdcp_serialize_control_plane_data_pdu_with_SRB_sn_buffer((unsigned char *)pdcp_pdu_p->data, &pdu_header) == false) { LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" Cannot fill PDU buffer with relevant header fields!\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p)); @@ -382,7 +380,7 @@ boolean_t pdcp_data_req( } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); - return FALSE; + return false; } } else { pdcp_user_plane_data_pdu_header_with_long_sn pdu_header; @@ -390,7 +388,7 @@ boolean_t pdcp_data_req( pdu_header.sn = pdcp_get_next_tx_seq_number(pdcp_p); current_sn = pdu_header.sn ; - if (pdcp_serialize_user_plane_data_pdu_with_long_sn_buffer((unsigned char *)pdcp_pdu_p->data, &pdu_header) == FALSE) { + if (pdcp_serialize_user_plane_data_pdu_with_long_sn_buffer((unsigned char *)pdcp_pdu_p->data, &pdu_header) == false) { LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" Cannot fill PDU buffer with relevant header fields!\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p)); @@ -401,7 +399,7 @@ boolean_t pdcp_data_req( } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); - return FALSE; + return false; } } @@ -422,7 +420,7 @@ boolean_t pdcp_data_req( } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); - return FALSE; + return false; } LOG_D(PDCP, "Sequence number %d is assigned to current PDU\n", current_sn); @@ -481,7 +479,7 @@ boolean_t pdcp_data_req( ctxt_pP->module_id, rb_idP); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); - return FALSE; + return false; } /* @@ -497,16 +495,16 @@ boolean_t pdcp_data_req( if (ctxt_pP->enb_flag == ENB_FLAG_YES && NODE_IS_DU(RC.rrc[ctxt_pP->module_id]->node_type)) { LOG_E(PDCP, "Can't be DU, bad node type %d \n", RC.rrc[ctxt_pP->module_id]->node_type); - ret=FALSE; + ret = false; } else { rlc_status = pdcp_params.send_rlc_data_req_func(ctxt_pP, srb_flagP, MBMS_FLAG_NO, rb_idP, muiP, confirmP, pdcp_pdu_size, pdcp_pdu_p,sourceL2Id, destinationL2Id); - ret=FALSE; + ret = false; switch (rlc_status) { case RLC_OP_STATUS_OK: LOG_D(PDCP, "Data sending request over RLC succeeded!\n"); - ret=TRUE; + ret=true; break; case RLC_OP_STATUS_BAD_PARAMETER: @@ -544,7 +542,7 @@ boolean_t pdcp_data_req( itti_send_msg_to_task (TASK_CU_F1, ctxt_pP->module_id, message_p); //CU_send_DL_RRC_MESSAGE_TRANSFER(ctxt_pP->module_id, message_p); LOG_I(PDCP, "Send F1AP_DL_RRC_MESSAGE with ITTI\n"); - ret=TRUE; + ret=true; } else { rlc_status = rlc_data_req(ctxt_pP , srb_flagP @@ -561,27 +559,27 @@ boolean_t pdcp_data_req( switch (rlc_status) { case RLC_OP_STATUS_OK: LOG_D(PDCP, "Data sending request over RLC succeeded!\n"); - ret=TRUE; + ret=true; break; case RLC_OP_STATUS_BAD_PARAMETER: LOG_W(PDCP, "Data sending request over RLC failed with 'Bad Parameter' reason!\n"); - ret= FALSE; + ret= false; break; case RLC_OP_STATUS_INTERNAL_ERROR: LOG_W(PDCP, "Data sending request over RLC failed with 'Internal Error' reason!\n"); - ret= FALSE; + ret= false; break; case RLC_OP_STATUS_OUT_OF_RESSOURCES: LOG_W(PDCP, "Data sending request over RLC failed with 'Out of Resources' reason!\n"); - ret= FALSE; + ret= false; break; default: LOG_W(PDCP, "RLC returned an unknown status code after PDCP placed the order to send some data (Status Code:%d)\n", rlc_status); - ret= FALSE; + ret= false; break; } // switch case } @@ -596,7 +594,7 @@ boolean_t pdcp_data_req( /* * Control arrives here only if rlc_data_req() returns RLC_OP_STATUS_OK - * so we return TRUE afterwards + * so we return true afterwards */ for (pdcp_uid=0; pdcp_uid< MAX_MOBILES_PER_ENB; pdcp_uid++) { @@ -619,7 +617,7 @@ boolean_t pdcp_data_req( //----------------------------------------------------------------------------- -boolean_t +bool pdcp_data_ind( const protocol_ctxt_t *const ctxt_pP, const srb_flag_t srb_flagP, @@ -638,7 +636,7 @@ pdcp_data_ind( pdcp_sn_t sequence_number = 0; volatile sdu_size_t payload_offset = 0; rb_id_t rb_id = rb_idP; - boolean_t packet_forwarded = FALSE; + bool packet_forwarded = false; hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; uint8_t rb_offset= (srb_flagP == 0) ? DTCH -1 :0; @@ -654,7 +652,7 @@ pdcp_data_ind( "[MSG] PDCP UL %s PDU on rb_id %ld\n", (srb_flagP)? "CONTROL" : "DATA", rb_idP); if (MBMS_flagP) { - AssertError (rb_idP < NB_RB_MBMS_MAX, return FALSE, + AssertError (rb_idP < NB_RB_MBMS_MAX, return false, "RB id is too high (%ld/%d) %u rnti %x!\n", rb_idP, NB_RB_MBMS_MAX, @@ -680,12 +678,12 @@ pdcp_data_ind( } } else { rb_id = rb_idP % LTE_maxDRB; - AssertError (rb_id < LTE_maxDRB, return FALSE, "RB id is too high (%ld/%d) %u UE %x!\n", + AssertError (rb_id < LTE_maxDRB, return false, "RB id is too high (%ld/%d) %u UE %x!\n", rb_id, LTE_maxDRB, ctxt_pP->module_id, ctxt_pP->rnti); - AssertError (rb_id > 0, return FALSE, "RB id is too low (%ld/%d) %u UE %x!\n", + AssertError (rb_id > 0, return false, "RB id is too low (%ld/%d) %u UE %x!\n", rb_id, LTE_maxDRB, ctxt_pP->module_id, @@ -700,14 +698,14 @@ pdcp_data_ind( key); free_mem_block(sdu_buffer_pP, __func__); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); - return FALSE; + return false; } } if (sdu_buffer_sizeP == 0) { LOG_W(PDCP, "SDU buffer size is zero! Ignoring this chunk!\n"); - return FALSE; + return false; } if (ctxt_pP->enb_flag) { @@ -764,13 +762,13 @@ pdcp_data_ind( } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); - return FALSE; + return false; } #if 0 /* Removed by Cedric */ - if (pdcp_is_rx_seq_number_valid(sequence_number, pdcp_p, srb_flagP) == TRUE) { + if (pdcp_is_rx_seq_number_valid(sequence_number, pdcp_p, srb_flagP) == true) { LOG_T(PDCP, "Incoming PDU has a sequence number (%d) in accordance with RX window\n", sequence_number); /* if (dc == PDCP_DATA_PDU ) LOG_D(PDCP, "Passing piggybacked SDU to NAS driver...\n"); @@ -788,7 +786,7 @@ pdcp_data_ind( */ LOG_W(PDCP, "Ignoring PDU...\n"); free_mem_block(sdu_buffer_pP, __func__); - return FALSE; + return false; } #endif @@ -837,7 +835,7 @@ pdcp_data_ind( LOG_W(PDCP, "Ignoring PDU...\n"); free_mem_block(sdu_buffer_pP, __func__); /* TODO: indicate integrity verification failure to upper layer */ - return FALSE; + return false; } if (sequence_number < pdcp_p->next_pdcp_rx_sn) @@ -864,7 +862,7 @@ pdcp_data_ind( } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); - return TRUE; + return true; } /* if (srb_flagP) */ /* @@ -892,7 +890,7 @@ pdcp_data_ind( LOG_W(PDCP, "Ignoring PDU...\n"); free_mem_block(sdu_buffer_pP, __func__); /* TODO: indicate integrity verification failure to upper layer */ - return FALSE; + return false; } else if (pdcp_p->next_pdcp_rx_sn - sequence_number > reordering_window) { pdcp_p->rx_hfn++; rx_hfn_for_count = pdcp_p->rx_hfn; @@ -948,7 +946,7 @@ pdcp_data_ind( LOG_W(PDCP, "Ignoring PDU...\n"); free_mem_block(sdu_buffer_pP, __func__); /* TODO: indicate integrity verification failure to upper layer */ - return FALSE; + return false; } /* TODO: specs say we have to store this PDU in a list and then deliver @@ -1015,7 +1013,7 @@ pdcp_data_ind( LOG_W(PDCP, "Ignoring PDU...\n"); free_mem_block(sdu_buffer_pP, __func__); /* TODO: indicate integrity verification failure to upper layer */ - return FALSE; + return false; } break; @@ -1039,7 +1037,7 @@ pdcp_data_ind( } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); - return TRUE; + return true; } // XXX Decompression would be done at this point @@ -1051,7 +1049,7 @@ pdcp_data_ind( */ if (LINK_ENB_PDCP_TO_GTPV1U) { - if ((TRUE == ctxt_pP->enb_flag) && (FALSE == srb_flagP)) { + if ((true == ctxt_pP->enb_flag) && (false == srb_flagP)) { LOG_D(PDCP, "Sending packet to GTP, Calling GTPV1U_ENB_TUNNEL_DATA_REQ ue %x rab %ld len %u\n", ctxt_pP->rnti, rb_id + 4, @@ -1069,10 +1067,10 @@ pdcp_data_ind( GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).rnti = ctxt_pP->rnti; GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).rab_id = rb_id + 4; itti_send_msg_to_task(TASK_GTPV1_U, INSTANCE_DEFAULT, message_p); - packet_forwarded = TRUE; + packet_forwarded = true; } } else { - packet_forwarded = FALSE; + packet_forwarded = false; } #ifdef MBMS_MULTICAST_OUT @@ -1086,13 +1084,13 @@ pdcp_data_ind( // dest_addr.sin_addr.s_addr = ip_header->daddr; // sendto(mbms_socket, &sdu_buffer_pP->data[payload_offset], sdu_buffer_sizeP - payload_offset, MSG_DONTWAIT, (struct sockaddr*)&dest_addr, sizeof(dest_addr)); - // //packet_forwarded = TRUE; + // //packet_forwarded = true; } #endif - if (FALSE == packet_forwarded) { + if (false == packet_forwarded) { notifiedFIFO_elt_t * new_sdu_p = newNotifiedFIFO_elt(sdu_buffer_sizeP - payload_offset + sizeof (pdcp_data_ind_header_t), 0, NULL, NULL); if ((MBMS_flagP == 0) && (pdcp_p->rlc_mode == RLC_MODE_AM)) { @@ -1185,7 +1183,7 @@ pdcp_data_ind( } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); - return TRUE; + return true; } void pdcp_update_stats(const protocol_ctxt_t *const ctxt_pP) { @@ -1297,7 +1295,7 @@ pdcp_run ( NULL, NULL ); - if (result != TRUE) + if (result != true) LOG_E(PDCP, "PDCP data request failed!\n"); // Message buffer has been processed, free it now. @@ -1420,7 +1418,7 @@ pdcp_mbms_run ( // NULL, NULL // ); // -// if (result != TRUE) +// if (result != true) // LOG_E(PDCP, "PDCP data request failed!\n"); // // // Message buffer has been processed, free it now. @@ -1549,10 +1547,7 @@ void pdcp_add_UE(const protocol_ctxt_t *const ctxt_pP) { } //----------------------------------------------------------------------------- -boolean_t -pdcp_remove_UE( - const protocol_ctxt_t *const ctxt_pP -) +bool pdcp_remove_UE(const protocol_ctxt_t *const ctxt_pP) //----------------------------------------------------------------------------- { LTE_DRB_Identity_t srb_id = 0; @@ -1599,19 +1594,17 @@ pdcp_remove_UE( //----------------------------------------------------------------------------- -boolean_t -rrc_pdcp_config_asn1_req ( - const protocol_ctxt_t *const ctxt_pP, - LTE_SRB_ToAddModList_t *const srb2add_list_pP, - LTE_DRB_ToAddModList_t *const drb2add_list_pP, - LTE_DRB_ToReleaseList_t *const drb2release_list_pP, - const uint8_t security_modeP, - uint8_t *const kRRCenc_pP, - uint8_t *const kRRCint_pP, - uint8_t *const kUPenc_pP, - LTE_PMCH_InfoList_r9_t *const pmch_InfoList_r9_pP, - rb_id_t *const defaultDRB -) +bool +rrc_pdcp_config_asn1_req(const protocol_ctxt_t *const ctxt_pP, + LTE_SRB_ToAddModList_t *const srb2add_list_pP, + LTE_DRB_ToAddModList_t *const drb2add_list_pP, + LTE_DRB_ToReleaseList_t *const drb2release_list_pP, + const uint8_t security_modeP, + uint8_t *const kRRCenc_pP, + uint8_t *const kRRCint_pP, + uint8_t *const kUPenc_pP, + LTE_PMCH_InfoList_r9_t *const pmch_InfoList_r9_pP, + rb_id_t *const defaultDRB) //----------------------------------------------------------------------------- { long int lc_id = 0; @@ -1669,7 +1662,7 @@ rrc_pdcp_config_asn1_req ( PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), key); free(pdcp_p); - return TRUE; + return true; } else { LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD key 0x%"PRIx64"\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), @@ -1784,13 +1777,13 @@ rrc_pdcp_config_asn1_req ( PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), key_defaultDRB); free(pdcp_p); - return TRUE; + return true; } else if (h_rc != HASH_TABLE_OK) { LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD ADD key 0x%"PRIx64" FAILED\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), key); free(pdcp_p); - return TRUE; + return true; } else { LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD ADD key 0x%"PRIx64"\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), @@ -1944,7 +1937,7 @@ rrc_pdcp_config_asn1_req ( if (ctxt_pP->enb_flag) { drb_id = (mch_id * LTE_maxSessionPerPMCH ) + lc_id ;//+ (LTE_maxDRB + 3)*MAX_MOBILES_PER_ENB; // 1 - if (pdcp_mbms_array_eNB[ctxt_pP->module_id][mch_id][lc_id].instanciated_instance == TRUE) { + if (pdcp_mbms_array_eNB[ctxt_pP->module_id][mch_id][lc_id].instanciated_instance == true) { action = CONFIG_ACTION_MBMS_MODIFY; } else { action = CONFIG_ACTION_MBMS_ADD; @@ -1952,7 +1945,7 @@ rrc_pdcp_config_asn1_req ( } else { drb_id = (mch_id * LTE_maxSessionPerPMCH ) + lc_id; // + (LTE_maxDRB + 3); // 15 - if (pdcp_mbms_array_ue[ctxt_pP->module_id][mch_id][lc_id].instanciated_instance == TRUE) { + if (pdcp_mbms_array_ue[ctxt_pP->module_id][mch_id][lc_id].instanciated_instance == true) { action = CONFIG_ACTION_MBMS_MODIFY; } else { action = CONFIG_ACTION_MBMS_ADD; @@ -1990,23 +1983,22 @@ rrc_pdcp_config_asn1_req ( } //----------------------------------------------------------------------------- -boolean_t -pdcp_config_req_asn1 ( - const protocol_ctxt_t *const ctxt_pP, - pdcp_t *const pdcp_pP, - const srb_flag_t srb_flagP, - const rlc_mode_t rlc_modeP, - const config_action_t actionP, - const uint16_t lc_idP, - const uint16_t mch_idP, - const rb_id_t rb_idP, - const uint8_t rb_snP, - const uint8_t rb_reportP, - const uint16_t header_compression_profileP, - const uint8_t security_modeP, - uint8_t *const kRRCenc_pP, - uint8_t *const kRRCint_pP, - uint8_t *const kUPenc_pP) +bool +pdcp_config_req_asn1(const protocol_ctxt_t *const ctxt_pP, + pdcp_t *const pdcp_pP, + const srb_flag_t srb_flagP, + const rlc_mode_t rlc_modeP, + const config_action_t actionP, + const uint16_t lc_idP, + const uint16_t mch_idP, + const rb_id_t rb_idP, + const uint8_t rb_snP, + const uint8_t rb_reportP, + const uint16_t header_compression_profileP, + const uint8_t security_modeP, + uint8_t *const kRRCenc_pP, + uint8_t *const kRRCint_pP, + uint8_t *const kUPenc_pP) //----------------------------------------------------------------------------- { @@ -2015,7 +2007,7 @@ pdcp_config_req_asn1 ( DevAssert(pdcp_pP != NULL); if (ctxt_pP->enb_flag == ENB_FLAG_YES) { - pdcp_pP->is_ue = FALSE; + pdcp_pP->is_ue = false; pdcp_add_UE(ctxt_pP); //pdcp_eNB_UE_instance_to_rnti[ctxtP->module_id] = ctxt_pP->rnti; @@ -2035,11 +2027,11 @@ pdcp_config_req_asn1 ( //pdcp_eNB_UE_instance_to_rnti_index = (pdcp_eNB_UE_instance_to_rnti_index + 1) % MAX_MOBILES_PER_ENB; } else { - pdcp_pP->is_ue = TRUE; + pdcp_pP->is_ue = true; pdcp_UE_UE_module_id_to_rnti[ctxt_pP->module_id] = ctxt_pP->rnti; } - pdcp_pP->is_srb = (srb_flagP == SRB_FLAG_YES) ? TRUE : FALSE; + pdcp_pP->is_srb = srb_flagP == SRB_FLAG_YES; pdcp_pP->lcid = lc_idP; pdcp_pP->rb_id = rb_idP; pdcp_pP->header_compression_profile = header_compression_profileP; @@ -2162,10 +2154,10 @@ pdcp_config_req_asn1 ( rb_idP); if (ctxt_pP->enb_flag == ENB_FLAG_YES) { - pdcp_mbms_array_eNB[ctxt_pP->module_id][mch_idP][lc_idP].instanciated_instance = TRUE ; + pdcp_mbms_array_eNB[ctxt_pP->module_id][mch_idP][lc_idP].instanciated_instance = true ; pdcp_mbms_array_eNB[ctxt_pP->module_id][mch_idP][lc_idP].rb_id = rb_idP; } else { - pdcp_mbms_array_ue[ctxt_pP->module_id][mch_idP][lc_idP].instanciated_instance = TRUE ; + pdcp_mbms_array_ue[ctxt_pP->module_id][mch_idP][lc_idP].instanciated_instance = true ; pdcp_mbms_array_ue[ctxt_pP->module_id][mch_idP][lc_idP].rb_id = rb_idP; } @@ -2245,10 +2237,10 @@ void rrc_pdcp_config_req ( pdcp_p->rb_id = rb_idP; if (ctxt_pP->enb_flag == ENB_FLAG_NO) { - pdcp_p->is_ue = TRUE; + pdcp_p->is_ue = true; pdcp_UE_UE_module_id_to_rnti[ctxt_pP->module_id] = ctxt_pP->rnti; } else { - pdcp_p->is_ue = FALSE; + pdcp_p->is_ue = false; } pdcp_p->next_pdcp_tx_sn = 0; @@ -2321,10 +2313,10 @@ void rrc_pdcp_config_req ( pdcp_p->rb_id = rb_idP; if (ctxt_pP->enb_flag == ENB_FLAG_NO) { - pdcp_p->is_ue = TRUE; + pdcp_p->is_ue = true; pdcp_UE_UE_module_id_to_rnti[ctxt_pP->module_id] = ctxt_pP->rnti; } else { - pdcp_p->is_ue = FALSE; + pdcp_p->is_ue = false; } pdcp_p->next_pdcp_tx_sn = 0; diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h index 332ee382d7..8cbc49d756 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h @@ -51,7 +51,7 @@ typedef rlc_op_status_t (*send_rlc_data_req_func_t)(const protocol_ctxt_t *cons const rb_id_t, const mui_t, confirm_t, sdu_size_t, mem_block_t *,const uint32_t *const, const uint32_t *const); -typedef boolean_t (pdcp_data_ind_t)( const protocol_ctxt_t *, const srb_flag_t, +typedef bool (pdcp_data_ind_t)( const protocol_ctxt_t *, const srb_flag_t, const MBMS_flag_t, const rb_id_t, const sdu_size_t, mem_block_t *,const uint32_t *const, const uint32_t *const); typedef pdcp_data_ind_t* pdcp_data_ind_func_t; @@ -153,14 +153,13 @@ typedef struct pdcp_stats_s { typedef struct pdcp_s { - //boolean_t instanciated_instance; uint16_t header_compression_profile; /* SR: added this flag to distinguish UE/eNB instance as pdcp_run for virtual * mode can receive data on NETLINK for eNB while eNB_flag = 0 and for UE when eNB_flag = 1 */ - boolean_t is_ue; - boolean_t is_srb; + bool is_ue; + bool is_srb; /* Configured security algorithms */ uint8_t cipheringAlgorithm; @@ -217,7 +216,7 @@ typedef struct pdcp_s { } pdcp_t; typedef struct pdcp_mbms_s { - boolean_t instanciated_instance; + bool instanciated_instance; rb_id_t rb_id; } pdcp_mbms_t; @@ -230,7 +229,7 @@ typedef struct pdcp_mbms_s { * under targets/TEST/PDCP/ */ -/*! \fn boolean_t pdcp_data_req(const protocol_ctxt_t* const , srb_flag_t , rb_id_t , mui_t , confirm_t ,sdu_size_t , unsigned char* , pdcp_transmission_mode_t ) +/*! \fn bool pdcp_data_req(const protocol_ctxt_t* const , srb_flag_t , rb_id_t , mui_t , confirm_t ,sdu_size_t , unsigned char* , pdcp_transmission_mode_t ) * \brief This functions handles data transfer requests coming either from RRC or from IP * \param[in] ctxt_pP Running context. * \param[in] rab_id Radio Bearer ID @@ -239,38 +238,34 @@ typedef struct pdcp_mbms_s { * \param[in] sdu_buffer_size Size of incoming SDU in bytes * \param[in] sdu_buffer Buffer carrying SDU * \param[in] mode flag to indicate whether the userplane data belong to the control plane or data plane or transparent -* \return TRUE on success, FALSE otherwise +* \return true on success, false otherwise * \note None * @ingroup _pdcp */ -boolean_t pdcp_data_req( - protocol_ctxt_t *ctxt_pP, - const srb_flag_t srb_flagP, - const rb_id_t rb_id, - const mui_t muiP, - const confirm_t confirmP, - const sdu_size_t sdu_buffer_size, - unsigned char *const sdu_buffer, - const pdcp_transmission_mode_t mode, - const uint32_t * sourceL2Id, - const uint32_t * destinationL2Id -); +bool pdcp_data_req(protocol_ctxt_t *ctxt_pP, + const srb_flag_t srb_flagP, + const rb_id_t rb_id, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_buffer_size, + unsigned char *const sdu_buffer, + const pdcp_transmission_mode_t mode, + const uint32_t * sourceL2Id, + const uint32_t * destinationL2Id); -boolean_t cu_f1u_data_req( - protocol_ctxt_t *ctxt_pP, - const srb_flag_t srb_flagP, - const rb_id_t rb_id, - const mui_t muiP, - const confirm_t confirmP, - const sdu_size_t sdu_buffer_size, - unsigned char *const sdu_buffer, - const pdcp_transmission_mode_t mode, - const uint32_t *const sourceL2Id, - const uint32_t *const destinationL2Id - ); +bool cu_f1u_data_req(protocol_ctxt_t *ctxt_pP, + const srb_flag_t srb_flagP, + const rb_id_t rb_id, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_buffer_size, + unsigned char *const sdu_buffer, + const pdcp_transmission_mode_t mode, + const uint32_t *const sourceL2Id, + const uint32_t *const destinationL2Id); -/*! \fn boolean_t pdcp_data_ind(const protocol_ctxt_t* const, srb_flag_t, MBMS_flag_t, rb_id_t, sdu_size_t, mem_block_t*, boolean_t) +/*! \fn bool pdcp_data_ind(const protocol_ctxt_t* const, srb_flag_t, MBMS_flag_t, rb_id_t, sdu_size_t, mem_block_t*, bool) * \brief This functions handles data transfer indications coming from RLC * \param[in] ctxt_pP Running context. * \param[in] Shows if rb is SRB @@ -279,7 +274,7 @@ boolean_t cu_f1u_data_req( * \param[in] sdu_buffer_size Size of incoming SDU in bytes * \param[in] sdu_buffer Buffer carrying SDU * \param[in] is_data_plane flag to indicate whether the userplane data belong to the control plane or data plane -* \return TRUE on success, FALSE otherwise +* \return TRUE on success, false otherwise * \note None * @ingroup _pdcp */ @@ -316,20 +311,18 @@ void rrc_pdcp_config_req ( * \param[in] defaultDRB Default DRB ID * \return A status about the processing, OK or error code. */ -boolean_t rrc_pdcp_config_asn1_req ( - const protocol_ctxt_t *const ctxt_pP, - LTE_SRB_ToAddModList_t *const srb2add_list, - LTE_DRB_ToAddModList_t *const drb2add_list, - LTE_DRB_ToReleaseList_t *const drb2release_list, - const uint8_t security_modeP, - uint8_t *const kRRCenc, - uint8_t *const kRRCint, - uint8_t *const kUPenc, - LTE_PMCH_InfoList_r9_t *pmch_InfoList_r9, - rb_id_t *const defaultDRB -); +bool rrc_pdcp_config_asn1_req(const protocol_ctxt_t *const ctxt_pP, + LTE_SRB_ToAddModList_t *const srb2add_list, + LTE_DRB_ToAddModList_t *const drb2add_list, + LTE_DRB_ToReleaseList_t *const drb2release_list, + const uint8_t security_modeP, + uint8_t *const kRRCenc, + uint8_t *const kRRCint, + uint8_t *const kUPenc, + LTE_PMCH_InfoList_r9_t *pmch_InfoList_r9, + rb_id_t *const defaultDRB); -/*! \fn boolean_t pdcp_config_req_asn1 (const protocol_ctxt_t* const ctxt_pP, srb_flag_t srb_flagP, uint32_t action, rb_id_t rb_id, uint8_t rb_sn, uint8_t rb_report, uint16_t header_compression_profile, uint8_t security_mode) +/*! \fn bool pdcp_config_req_asn1 (const protocol_ctxt_t* const ctxt_pP, srb_flag_t srb_flagP, uint32_t action, rb_id_t rb_id, uint8_t rb_sn, uint8_t rb_report, uint16_t header_compression_profile, uint8_t security_mode) * \brief Function for RRC to configure a Radio Bearer. * \param[in] ctxt_pP Running context. * \param[in] pdcp_pP Pointer on PDCP structure. @@ -349,22 +342,21 @@ boolean_t rrc_pdcp_config_asn1_req ( * \param[in] kUPenc User-Plane encryption key * \return A status about the processing, OK or error code. */ -boolean_t pdcp_config_req_asn1 ( - const protocol_ctxt_t *const ctxt_pP, - pdcp_t *const pdcp_pP, - const srb_flag_t srb_flagP, - const rlc_mode_t rlc_mode, - const uint32_t action, - const uint16_t lc_id, - const uint16_t mch_id, - const rb_id_t rb_id, - const uint8_t rb_sn, - const uint8_t rb_report, - const uint16_t header_compression_profile, - const uint8_t security_mode, - uint8_t *const kRRCenc, - uint8_t *const kRRCint, - uint8_t *const kUPenc); +bool pdcp_config_req_asn1(const protocol_ctxt_t *const ctxt_pP, + pdcp_t *const pdcp_pP, + const srb_flag_t srb_flagP, + const rlc_mode_t rlc_mode, + const uint32_t action, + const uint16_t lc_id, + const uint16_t mch_id, + const rb_id_t rb_id, + const uint8_t rb_sn, + const uint8_t rb_report, + const uint16_t header_compression_profile, + const uint8_t security_mode, + uint8_t *const kRRCenc, + uint8_t *const kRRCint, + uint8_t *const kUPenc); /*! \fn void pdcp_add_UE(const protocol_ctxt_t* const ctxt_pP) * \brief Function (for RRC) to add a new UE in PDCP module @@ -373,13 +365,12 @@ boolean_t pdcp_config_req_asn1 ( */ void pdcp_add_UE(const protocol_ctxt_t *const ctxt_pP); -/*! \fn boolean_t pdcp_remove_UE(const protocol_ctxt_t* const ctxt_pP) +/*! \fn bool pdcp_remove_UE(const protocol_ctxt_t* const ctxt_pP) * \brief Function for RRC to remove UE from PDCP module hashtable * \param[in] ctxt_pP Running context. * \return A status about the processing, OK or error code. */ -boolean_t pdcp_remove_UE( - const protocol_ctxt_t *const ctxt_pP); +bool pdcp_remove_UE(const protocol_ctxt_t *const ctxt_pP); /*! \fn void rrc_pdcp_config_release( const protocol_ctxt_t* const, rb_id_t) * \brief This functions is unused diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.c index ef674132c4..77d3cf3857 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.c @@ -32,7 +32,7 @@ #include "pdcp.h" #include "pdcp_primitives.h" -extern boolean_t util_mark_nth_bit_of_octet(uint8_t* octet, uint8_t index); +extern bool util_mark_nth_bit_of_octet(uint8_t* octet, uint8_t index); /* * Parses data/control field out of buffer of User Plane PDCP Data PDU with @@ -123,13 +123,13 @@ uint8_t pdcp_get_sequence_number_of_pdu_with_SRB_sn(unsigned char* pdu_buffer) * Fills the incoming buffer with the fields of the header for srb sn * * @param pdu_buffer PDCP PDU buffer - * @return TRUE on success, FALSE otherwise + * @return true on success, false otherwise */ -boolean_t pdcp_serialize_control_plane_data_pdu_with_SRB_sn_buffer(unsigned char* pdu_buffer, \ - pdcp_control_plane_data_pdu_header* pdu) +bool pdcp_serialize_control_plane_data_pdu_with_SRB_sn_buffer(unsigned char* pdu_buffer, + pdcp_control_plane_data_pdu_header* pdu) { if (pdu_buffer == NULL || pdu == NULL) { - return FALSE; + return false; } /* @@ -138,20 +138,20 @@ boolean_t pdcp_serialize_control_plane_data_pdu_with_SRB_sn_buffer(unsigned char uint8_t sequence_number = pdu->sn; pdu_buffer[0] = sequence_number & 0x1F; // 5bit sn - return TRUE; + return true; } /* * Fills the incoming buffer with the fields of the header for long sn * * @param pdu_buffer PDCP PDU buffer - * @return TRUE on success, FALSE otherwise + * @return true on success, false otherwise */ -boolean_t pdcp_serialize_user_plane_data_pdu_with_long_sn_buffer(unsigned char* pdu_buffer, \ - pdcp_user_plane_data_pdu_header_with_long_sn* pdu) +bool pdcp_serialize_user_plane_data_pdu_with_long_sn_buffer(unsigned char* pdu_buffer, + pdcp_user_plane_data_pdu_header_with_long_sn* pdu) { if (pdu_buffer == NULL || pdu == NULL) { - return FALSE; + return false; } /* @@ -170,7 +170,7 @@ boolean_t pdcp_serialize_user_plane_data_pdu_with_long_sn_buffer(unsigned char* pdu_buffer[0] |= 0x80; // set the first bit as 1 } - return TRUE; + return true; } /* @@ -178,13 +178,14 @@ boolean_t pdcp_serialize_user_plane_data_pdu_with_long_sn_buffer(unsigned char* * * @param pdu_buffer The buffer that PDU will be serialized into * @param pdu A status report header - * @return TRUE on success, FALSE otherwise + * @return true on success, false otherwise */ -boolean_t pdcp_serialize_control_pdu_for_pdcp_status_report(unsigned char* pdu_buffer, \ - uint8_t bitmap[512], pdcp_control_pdu_for_pdcp_status_report* pdu) +bool pdcp_serialize_control_pdu_for_pdcp_status_report(unsigned char* pdu_buffer, + uint8_t bitmap[512], + pdcp_control_pdu_for_pdcp_status_report* pdu) { if (pdu_buffer == NULL || pdu == NULL) { - return FALSE; + return false; } /* @@ -205,6 +206,6 @@ boolean_t pdcp_serialize_control_pdu_for_pdcp_status_report(unsigned char* pdu_b */ memcpy(pdu_buffer + 2, bitmap, 512); - return TRUE; + return true; } diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.h index 8b5ebe7287..423f69afc9 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_primitives.h @@ -142,18 +142,18 @@ uint8_t pdcp_get_sequence_number_of_pdu_with_SRB_sn(unsigned char* pdu_buffer); * Fills the incoming buffer with the fields of the header for SRB1 * * @param pdu_buffer PDCP PDU buffer - * @return TRUE on success, FALSE otherwise + * @return true on success, false otherwise */ -boolean_t pdcp_serialize_control_plane_data_pdu_with_SRB_sn_buffer(unsigned char* pdu_buffer, \ - pdcp_control_plane_data_pdu_header* pdu); +bool pdcp_serialize_control_plane_data_pdu_with_SRB_sn_buffer(unsigned char* pdu_buffer, + pdcp_control_plane_data_pdu_header* pdu); /* * Fills the incoming buffer with the fields of the header for long SN (RLC UM and AM) * * @param pdu_buffer PDCP PDU buffer - * @return TRUE on success, FALSE otherwise + * @return true on success, false otherwise */ -boolean_t pdcp_serialize_user_plane_data_pdu_with_long_sn_buffer(unsigned char* pdu_buffer, \ - pdcp_user_plane_data_pdu_header_with_long_sn* pdu); +bool pdcp_serialize_user_plane_data_pdu_with_long_sn_buffer(unsigned char* pdu_buffer, + pdcp_user_plane_data_pdu_header_with_long_sn* pdu); /* * Fills the incoming status report header with given value of bitmap @@ -162,10 +162,11 @@ boolean_t pdcp_serialize_user_plane_data_pdu_with_long_sn_buffer(unsigned char* * @param FMS First Missing PDCP SN * @param bitmap Received/Missing sequence number bitmap * @param pdu A status report header - * @return TRUE on success, FALSE otherwise + * @return true on success, false otherwise */ -boolean_t pdcp_serialize_control_pdu_for_pdcp_status_report(unsigned char* pdu_buffer, \ - uint8_t bitmap[512], pdcp_control_pdu_for_pdcp_status_report* pdu); +bool pdcp_serialize_control_pdu_for_pdcp_status_report(unsigned char* pdu_buffer, + uint8_t bitmap[512], + pdcp_control_pdu_for_pdcp_status_report* pdu); int pdcp_netlink_dequeue_element(const protocol_ctxt_t* const ctxt_pP, struct pdcp_netlink_element_s **data_ppP); diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_sequence_manager.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_sequence_manager.c index cdc583ef21..31beb3a9e0 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_sequence_manager.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_sequence_manager.c @@ -33,12 +33,12 @@ /* * Initializes sequence numbering state * @param pdcp_entity The PDCP entity to be initialized - * @return boolean_t TRUE on success, FALSE otherwise + * @return bool true on success, false otherwise */ -boolean_t pdcp_init_seq_numbers(pdcp_t* pdcp_entity) +bool pdcp_init_seq_numbers(pdcp_t* pdcp_entity) { if (pdcp_entity == NULL) { - return FALSE; + return false; } /* Sequence number state variables */ @@ -55,34 +55,34 @@ boolean_t pdcp_init_seq_numbers(pdcp_t* pdcp_entity) // Shall UE and eNB behave differently on initialization? (see 7.1.e) pdcp_entity->last_submitted_pdcp_rx_sn = 4095; - return TRUE; + return true; } -boolean_t pdcp_is_seq_num_size_valid(pdcp_t* pdcp_entity) +bool pdcp_is_seq_num_size_valid(pdcp_t* pdcp_entity) { if (pdcp_entity == NULL) { - return FALSE; + return false; } // Check if the size of SN is valid (see 3GPP TS 36.323 v10.1.0 item 6.3.2) if (pdcp_entity->seq_num_size != 5 && pdcp_entity->seq_num_size != 7 && pdcp_entity->seq_num_size != 12) { LOG_W(PDCP, "Incoming SN size is invalid! (Expected: {5 | 7 | 12}, Received: %d\n", pdcp_entity->seq_num_size); - return FALSE; + return false; } - return TRUE; + return true; } /** * Check if SN number is in the range according to SN size */ -boolean_t pdcp_is_seq_num_valid(uint16_t seq_num, uint8_t seq_num_size) +bool pdcp_is_seq_num_valid(uint16_t seq_num, uint8_t seq_num_size) { if (seq_num >= 0 && seq_num <= pdcp_calculate_max_seq_num_for_given_size(seq_num_size)) { - return TRUE; + return true; } - return FALSE; + return false; } uint16_t pdcp_calculate_max_seq_num_for_given_size(uint8_t seq_num_size) @@ -96,7 +96,7 @@ uint16_t pdcp_calculate_max_seq_num_for_given_size(uint8_t seq_num_size) uint16_t pdcp_get_next_tx_seq_number(pdcp_t* pdcp_entity) { - if (pdcp_is_seq_num_size_valid(pdcp_entity) == FALSE) { + if (pdcp_is_seq_num_size_valid(pdcp_entity) == false) { return -1; } @@ -118,10 +118,10 @@ uint16_t pdcp_get_next_tx_seq_number(pdcp_t* pdcp_entity) return pdcp_seq_num; } -boolean_t pdcp_advance_rx_window(pdcp_t* pdcp_entity) +bool pdcp_advance_rx_window(pdcp_t* pdcp_entity) { - if (pdcp_is_seq_num_size_valid(pdcp_entity) == FALSE) { - return FALSE; + if (pdcp_is_seq_num_size_valid(pdcp_entity) == false) { + return false; } /* @@ -137,10 +137,10 @@ boolean_t pdcp_advance_rx_window(pdcp_t* pdcp_entity) pdcp_entity->next_pdcp_rx_sn++; } - return TRUE; + return true; } -boolean_t pdcp_mark_current_pdu_as_received(uint16_t seq_num, pdcp_t* pdcp_entity) +bool pdcp_mark_current_pdu_as_received(uint16_t seq_num, pdcp_t* pdcp_entity) { /* * Incoming sequence number and PDCP entity were already @@ -158,5 +158,5 @@ boolean_t pdcp_mark_current_pdu_as_received(uint16_t seq_num, pdcp_t* pdcp_entit LOG_D(PDCP, "Marking %d. bit of %d. octet of status bitmap\n", (seq_num % 8) + 1, octet_index); util_mark_nth_bit_of_octet(&pdcp_entity->missing_pdu_bitmap[octet_index], seq_num % 8); util_print_binary_representation((uint8_t*)"Current state of relevant octet: ", pdcp_entity->missing_pdu_bitmap[octet_index]); - return TRUE; + return true; } diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_sequence_manager.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp_sequence_manager.h index 172c9810e6..bff98d1b00 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_sequence_manager.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_sequence_manager.h @@ -35,17 +35,17 @@ * @param pdcp_entity The PDCP entity to be initialized * @return none */ -boolean_t pdcp_init_seq_numbers(pdcp_t* pdcp_entity); +bool pdcp_init_seq_numbers(pdcp_t* pdcp_entity); /** * Checks if incoming PDCP entitiy pointer and relevant sequence number size is valid - * @return TRUE (0x01) if it is valid, FALSE (0x00) otherwise + * @return true (0x01) if it is valid, false (0x00) otherwise */ -boolean_t pdcp_is_seq_num_size_valid(pdcp_t* pdcp_entity); +bool pdcp_is_seq_num_size_valid(pdcp_t* pdcp_entity); /** * Check if SN number is in the range according to SN size - * @return TRUE if it is valid, FALSE otherwise + * @return true if it is valid, false otherwise */ -boolean_t pdcp_is_seq_num_valid(uint16_t seq_num, uint8_t seq_num_size); +bool pdcp_is_seq_num_valid(uint16_t seq_num, uint8_t seq_num_size); /** * Returns the maximum allowed sequence number value for given size of SN field * @return Max sequence number value @@ -58,11 +58,11 @@ uint16_t pdcp_get_next_tx_seq_number(pdcp_t* pdcp_entity); /** * Advances the RX window state of given PDCP entity upon successfull receipt of a SDU */ -boolean_t pdcp_advance_rx_window(pdcp_t* pdcp_entity); +bool pdcp_advance_rx_window(pdcp_t* pdcp_entity); /** * Updates missing PDU bitmap with incoming sequence number -* @return TRUE if successful, FALSE otherwise +* @return true if successful, false otherwise */ -boolean_t pdcp_mark_current_pdu_as_received(uint16_t seq_num, pdcp_t* pdcp_entity); +bool pdcp_mark_current_pdu_as_received(uint16_t seq_num, pdcp_t* pdcp_entity); #endif diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.c index cf8218829f..79f6d68820 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.c @@ -130,9 +130,9 @@ void util_print_binary_representation(unsigned char* message, uint8_t octet) * * @param octet 8-bit data * @param index Index of bit to be set - * @return TRUE on success, FALSE otherwise + * @return true on success, false otherwise */ -boolean_t util_mark_nth_bit_of_octet(uint8_t* octet, uint8_t index) +bool util_mark_nth_bit_of_octet(uint8_t* octet, uint8_t index) { uint8_t mask = 0x80; @@ -148,6 +148,6 @@ boolean_t util_mark_nth_bit_of_octet(uint8_t* octet, uint8_t index) */ *octet |= mask; - return TRUE; + return true; } diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.h index 49846c7a9f..89b8ff672f 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_util.h @@ -66,8 +66,8 @@ void util_print_binary_representation(unsigned char* message, uint8_t octet); * * @param octet Octet * @param index Index - * @return TRUE on success, FALSE otherwise + * @return true on success, false otherwise */ -boolean_t util_mark_nth_bit_of_octet(uint8_t* octet, uint8_t index); +bool util_mark_nth_bit_of_octet(uint8_t* octet, uint8_t index); #endif // PDCP_UTIL_H diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c index 4eb0907046..ddc7bf85e8 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -52,7 +52,7 @@ rlc_am_get_status_pdu_buffer_occupancy( rlc_sn_t sn_cursor = rlc_pP->vr_r; rlc_sn_t sn_prev = rlc_pP->vr_r; rlc_sn_t sn_end = rlc_pP->vr_ms; - boolean_t segment_loop_end = false; + bool segment_loop_end = false; if (sn_prev != sn_end) { while ((RLC_AM_DIFF_SN(sn_prev,rlc_pP->vr_r) < RLC_AM_DIFF_SN(sn_end,rlc_pP->vr_r)) && (cursor_p != NULL)) { diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h index 1b6d837565..95c47943a4 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h @@ -54,7 +54,7 @@ typedef struct rlc_am_entity_s { rb_id_t rb_id; /*!< \brief Radio bearer identifier, for statistics and trace purpose. */ logical_chan_id_t channel_id; /*!< \brief Transport channel identifier. */ - boolean_t is_data_plane; /*!< \brief To know if the RLC belongs to a data radio bearer or a signalling radio bearer, for statistics and trace purpose. */ + bool is_data_plane; /*!< \brief To know if the RLC belongs to a data radio bearer or a signalling radio bearer, for statistics and trace purpose. */ rlc_buffer_occupancy_t sdu_buffer_occupancy; /*!< \brief Number of bytes of unsegmented SDUs. */ rlc_buffer_occupancy_t status_buffer_occupancy; /*!< \brief Number of bytes of control PDUs waiting for transmission. */ @@ -76,7 +76,7 @@ typedef struct rlc_am_entity_s { rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer; /*!< \brief Transmission PDU data buffer. Used also for retransmissions */ signed int retrans_num_pdus; /*!< \brief Number of PDUs in the retransmission buffer. */ signed int retrans_num_bytes_to_retransmit; /*!< \brief Number of bytes in the retransmission buffer to be retransmitted. Only payload is taken into account */ - boolean_t force_poll; /*!< \brief force poll due to t_poll_retransmit time-out. */ + bool force_poll; /*!< \brief force poll due to t_poll_retransmit time-out. */ //--------------------------------------------------------------------- // RX BUFFERS @@ -186,8 +186,8 @@ typedef struct rlc_am_entity_s { // note occupancy of other buffers is deducted from nb elements in lists rlc_buffer_occupancy_t buffer_occupancy_retransmission_buffer; /*!< \brief Number of PDUs. */ - boolean_t initialized; /*!< \brief Boolean for rlc_am_entity_t struct initialization. */ - boolean_t configured; /*!< \brief Boolean for rlc_am_entity_t struct configuration. */ + bool initialized; /*!< \brief Boolean for rlc_am_entity_t struct initialization. */ + bool configured; /*!< \brief Boolean for rlc_am_entity_t struct configuration. */ } rlc_am_entity_t; /** @} */ # endif diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c index cb09f24855..8ff29fa44b 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c @@ -32,7 +32,7 @@ rlc_am_init( const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlc_pP) { - if (rlc_pP->initialized == TRUE) { + if (rlc_pP->initialized == true) { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[AM INIT] INITIALIZATION ALREADY DONE, DOING NOTHING\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); } else { @@ -79,7 +79,7 @@ rlc_am_init( rlc_pP->last_absolute_subframe_status_indication = 0xFFFFFFFF; // any value > 1 - rlc_pP->initialized = TRUE; + rlc_pP->initialized = true; } } //----------------------------------------------------------------------------- @@ -134,7 +134,7 @@ rlc_am_reestablish( rlc_pP->last_absolute_subframe_status_indication = 0xFFFFFFFF; // any value > 1 - rlc_pP->initialized = TRUE; + rlc_pP->initialized = true; } @@ -197,7 +197,7 @@ rlc_am_configure( const uint32_t t_reorderingP, const uint32_t t_status_prohibitP) { - if (rlc_pP->configured == TRUE) { + if (rlc_pP->configured == true) { LOG_I(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RECONFIGURE] max_retx_threshold %d poll_pdu %d poll_byte %d t_poll_retransmit %d t_reordering %d t_status_prohibit %d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), max_retx_thresholdP, @@ -235,7 +235,7 @@ rlc_am_configure( rlc_am_init_timer_reordering (ctxt_pP, rlc_pP, t_reorderingP); rlc_am_init_timer_status_prohibit(ctxt_pP, rlc_pP, t_status_prohibitP); - rlc_pP->configured = TRUE; + rlc_pP->configured = true; } } diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c index 0957c20bdf..a5f0b4f9ef 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c @@ -183,12 +183,10 @@ rlc_am_send_sdu ( } } //----------------------------------------------------------------------------- -void -rlc_am_reassemble_pdu( - const protocol_ctxt_t *const ctxt_pP, - rlc_am_entity_t *const rlc_pP, - mem_block_t *const tb_pP, - boolean_t free_rlc_pdu) { +void rlc_am_reassemble_pdu(const protocol_ctxt_t *const ctxt_pP, + rlc_am_entity_t *const rlc_pP, + mem_block_t *const tb_pP, + bool free_rlc_pdu) { int i,j; rlc_am_pdu_info_t *pdu_info = &((rlc_am_rx_pdu_management_t *)(tb_pP->data))->pdu_info; LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[REASSEMBLY PDU] TRY REASSEMBLY PDU SN=%03d\n", diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h index bf9bd58fb5..839e7d9304 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h @@ -57,14 +57,14 @@ void rlc_am_reassembly (const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * */ void rlc_am_send_sdu (const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP); -/*! \fn void rlc_am_reassemble_pdu(const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP, const mem_block_t* const tb_pP,boolean_t free_rlc_pdu) +/*! \fn void rlc_am_reassemble_pdu(const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP, const mem_block_t* const tb_pP, bool free_rlc_pdu) * \brief Reassembly a RLC AM PDU, depending of the content of this PDU, data will be reassemblied to the current output SDU, the current will be sent to higher layers or not, after or before the reassembly, or no send of SDU will be triggered, depending on FI field in PDU header. * \param[in] ctxtP Running context. * \param[in] rlc_pP RLC AM protocol instance pointer. * \param[in] tb_pP RLC AM PDU embedded in a mem_block_t. * \param[in] free_rlc_pdu Flag for freeing RLC AM PDU after reassembly. */ -void rlc_am_reassemble_pdu(const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP, mem_block_t* const tb_pP,boolean_t free_rlc_pdu); +void rlc_am_reassemble_pdu(const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP, mem_block_t* const tb_pP, bool free_rlc_pdu); /** @} */ #endif diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c index 916d1513b0..a749aa035e 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c @@ -328,7 +328,7 @@ rlc_am_receive_process_data_pdu ( rlc_am_pdu_info_t* pdu_info_p = &((rlc_am_rx_pdu_management_t*)(tb_pP->data))->pdu_info; rlc_am_pdu_sn_10_t* rlc_am_pdu_sn_10_p = (rlc_am_pdu_sn_10_t*)first_byte_pP; rlc_am_rx_pdu_status_t pdu_status = RLC_AM_DATA_PDU_STATUS_OK; - boolean_t reassemble = false; + bool reassemble = false; if (rlc_am_get_data_pdu_infos(ctxt_pP,rlc_pP, rlc_am_pdu_sn_10_p, tb_size_in_bytesP, pdu_info_p) >= 0) { diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c index 56b37e1e39..7129307739 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c @@ -29,13 +29,12 @@ #include "LAYER2/MAC/mac_extern.h" #include "common/utils/LOG/log.h" //----------------------------------------------------------------------------- -boolean_t rlc_am_nack_pdu ( - const protocol_ctxt_t* const ctxt_pP, - rlc_am_entity_t *const rlc_pP, - const rlc_sn_t snP, - const rlc_sn_t prev_nack_snP, - sdu_size_t so_startP, - sdu_size_t so_endP) +bool rlc_am_nack_pdu(const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t *const rlc_pP, + const rlc_sn_t snP, + const rlc_sn_t prev_nack_snP, + sdu_size_t so_startP, + sdu_size_t so_endP) { // 5.2.1 Retransmission // ... @@ -54,8 +53,8 @@ boolean_t rlc_am_nack_pdu ( rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer_p = &rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE]; //int pdu_sdu_index; //int sdu_index; - boolean_t status = TRUE; - boolean_t retx_count_increment = FALSE; + bool status = true; + bool retx_count_increment = false; sdu_size_t pdu_data_to_retx = 0; if (mb_p != NULL) { @@ -63,7 +62,7 @@ boolean_t rlc_am_nack_pdu ( if(so_startP > so_endP) { LOG_E(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[NACK-PDU] ERROR NACK MISSING PDU, so_startP %d, so_endP %d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),so_startP, so_endP); - status = FALSE; + status = false; } // Handle full PDU NACK first else if ((so_startP == 0) && (so_endP == 0x7FFF)) { @@ -71,9 +70,7 @@ boolean_t rlc_am_nack_pdu ( pdu_data_to_retx = tx_data_pdu_buffer_p->payload_size; /* Increment VtReTxNext if this is the first NACK or if some segments have already been transmitted */ if ((tx_data_pdu_buffer_p->flags.retransmit == 0) || (tx_data_pdu_buffer_p->nack_so_start)) - { - retx_count_increment = TRUE; - } + retx_count_increment = true; tx_data_pdu_buffer_p->nack_so_start = 0; tx_data_pdu_buffer_p->num_holes = 0; @@ -89,11 +86,11 @@ boolean_t rlc_am_nack_pdu ( if(tx_data_pdu_buffer_p->nack_so_start >= tx_data_pdu_buffer_p->payload_size){ LOG_E(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[NACK-PDU] ERROR NACK MISSING PDU, nack_so_start %d, payload_size %d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),tx_data_pdu_buffer_p->nack_so_start, tx_data_pdu_buffer_p->payload_size); - status = FALSE; + status = false; } } else { - status = FALSE; + status = false; } } else if (tx_data_pdu_buffer_p->flags.max_retransmit == 0) { @@ -107,9 +104,8 @@ boolean_t rlc_am_nack_pdu ( if (prev_nack_snP != snP) { /* New NACK_SN with SO */ /* check whether a new segment is to be placed in Retransmission Buffer, then increment vrReTx */ - if ((tx_data_pdu_buffer_p->flags.retransmit == 0) || (so_startP < tx_data_pdu_buffer_p->nack_so_start)) { - retx_count_increment = TRUE; - } + if ((tx_data_pdu_buffer_p->flags.retransmit == 0) || (so_startP < tx_data_pdu_buffer_p->nack_so_start)) + retx_count_increment = true; tx_data_pdu_buffer_p->num_holes = 1; tx_data_pdu_buffer_p->retx_hole_index = 0; @@ -129,21 +125,18 @@ boolean_t rlc_am_nack_pdu ( tx_data_pdu_buffer_p->nack_so_stop = so_endP; tx_data_pdu_buffer_p->num_holes ++; pdu_data_to_retx = so_endP - so_startP + 1; + } else { + status = false; } - else { - status = FALSE; - } - } - else { - status = FALSE; + } else { + status = false; } } else { - status = FALSE; + status = false; } - } - else { - status = FALSE; + } else { + status = false; } if (status) { @@ -175,17 +168,16 @@ boolean_t rlc_am_nack_pdu ( LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[NACK-PDU] ERROR NACK MISSING PDU SN %05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP); - status = FALSE; + status = false; } return status; } //----------------------------------------------------------------------------- -void rlc_am_ack_pdu ( - const protocol_ctxt_t* const ctxt_pP, - rlc_am_entity_t *const rlc_pP, - const rlc_sn_t snP, - boolean_t free_pdu) +void rlc_am_ack_pdu(const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t *const rlc_pP, + const rlc_sn_t snP, + bool free_pdu) { mem_block_t* mb_p = rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE].mem_block; rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer = &rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE]; @@ -283,7 +275,7 @@ mem_block_t* rlc_am_retransmit_get_am_segment( sdu_size_t retx_so_start,retx_so_stop; //starting and ending SO for retransmission in this PDU rlc_sn_t sn = pdu_mngt->sn; uint16_t header_so_part; - boolean_t fi_start, fi_end; + bool fi_start, fi_end; uint8_t sdu_index = 0; uint8_t sdu_segment_index = 0; uint8_t num_LIs_pdu_segment = pdu_mngt->nb_sdus - 1; @@ -377,11 +369,11 @@ mem_block_t* rlc_am_retransmit_get_am_segment( /* Set FI part to false if SO Start and SO End are different from PDU boundaries */ if (retx_so_start) { - fi_start = FALSE; + fi_start = false; } if (retx_so_stop < pdu_mngt->payload_size - 1) { - fi_end = FALSE; + fi_end = false; } /* Header content is filled at the end */ @@ -423,7 +415,7 @@ mem_block_t* rlc_am_retransmit_get_am_segment( else { /* if retx_so_start is still not included then set data_size with full original PDU data size */ - /* Set fi_start to FALSE in this case */ + /* Set fi_start to false in this case */ data_size = pdu_mngt->payload_size; } sdu_index ++; @@ -432,7 +424,7 @@ mem_block_t* rlc_am_retransmit_get_am_segment( if (retx_so_start == data_size) { /* Set FI Start if retx_so_start = cumulated data size */ - fi_start = TRUE; + fi_start = true; /* there must be at least one SDU more */ //Assertion(eNB)_PRAN_DesignDocument_annex No.778 if(sdu_index >= pdu_mngt->nb_sdus) @@ -464,8 +456,8 @@ mem_block_t* rlc_am_retransmit_get_am_segment( } else if (retx_so_start != 0) { - /* in all other cases set fi_start to FALSE if it SO Start is not 0 */ - fi_start = FALSE; + /* in all other cases set fi_start to false if it SO Start is not 0 */ + fi_start = false; } /* Set first SDU portion of the segment */ @@ -582,10 +574,10 @@ mem_block_t* rlc_am_retransmit_get_am_segment( "RLC AM Tx PDU Segment Data Error: retx_so_stop=%d OriginalPDUDataLength=%d SOStart=%d SegmentLength=%d numLISegment=%d numLIPDU=%d sn=%d LcId=%d !\n", retx_so_stop,pdu_mngt->payload_size,retx_so_start,*payload_sizeP,num_LIs_pdu_segment,pdu_mngt->nb_sdus - 1,sn,rlc_pP->channel_id); */ - /* init FI End to FALSE if retx_so_stop is not end of PDU */ + /* init FI End to false if retx_so_stop is not end of PDU */ if (retx_so_stop != pdu_mngt->payload_size - 1) { - fi_end = FALSE; + fi_end = false; } /* Check consistency between sdus_segment_size and payload_sizeP */ @@ -596,7 +588,7 @@ mem_block_t* rlc_am_retransmit_get_am_segment( data_size += sdus_segment_size[i]; if ((retx_so_stop == data_size - 1) && (i < num_LIs_pdu_segment)) { - fi_end = TRUE; + fi_end = true; } } //Assertion(eNB)_PRAN_DesignDocument_annex No.782 @@ -665,7 +657,7 @@ mem_block_t* rlc_am_retransmit_get_am_segment( pdu_mngt->nack_so_start = pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index]; } - /* Content is supposed to be init with 0 so with FIStart=FIEnd=TRUE */ + /* Content is supposed to be init with 0 so with FIStart=FIEnd=true */ RLC_AM_PDU_SET_D_C(*pdu_segment_header_p); RLC_AM_PDU_SET_RF(*pdu_segment_header_p); /* Change FI */ diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h index fc52689314..c34d06337d 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h @@ -35,7 +35,7 @@ # ifndef __RLC_AM_RETRANSMIT_H__ # define __RLC_AM_RETRANSMIT_H__ //----------------------------------------------------------------------------- -/*! \fn boolean_t rlc_am_nack_pdu (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *rlcP, int16_t snP, int16_t prev_nack_snP,sdu_size_t so_startP, sdu_size_t so_endP) +/*! \fn bool rlc_am_nack_pdu (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *rlcP, int16_t snP, int16_t prev_nack_snP,sdu_size_t so_startP, sdu_size_t so_endP) * \brief The RLC AM PDU which have the sequence number snP is marked NACKed with segment offset fields. * \param[in] ctxtP Running context. * \param[in] rlcP RLC AM protocol instance pointer. @@ -46,13 +46,12 @@ * \return OK/KO * \note It may appear a new hole in the retransmission buffer depending on the segment offset informations. Depending on the state of the retransmission buffer, negative confirmation can be sent to higher layers about the drop by the RLC AM instance of a particular SDU. */ -boolean_t rlc_am_nack_pdu ( - const protocol_ctxt_t* const ctxt_pP, - rlc_am_entity_t *const rlcP, - const rlc_sn_t snP, - const rlc_sn_t prev_nack_snP, - sdu_size_t so_startP, - sdu_size_t so_endP); +bool rlc_am_nack_pdu(const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t *const rlcP, + const rlc_sn_t snP, + const rlc_sn_t prev_nack_snP, + sdu_size_t so_startP, + sdu_size_t so_endP); /*! \fn void rlc_am_ack_pdu (const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t *rlcP, rlc_sn_t snP) * \brief The RLC AM PDU which have the sequence number snP is marked ACKed. @@ -62,11 +61,10 @@ boolean_t rlc_am_nack_pdu ( * \param[in] free_pdu Boolean indicating that the PDU can be freed because smaller than new vtA. * \note Depending on the state of the retransmission buffer, positive confirmation can be sent to higher layers about the receiving by the peer RLC AM instance of a particular SDU. */ -void rlc_am_ack_pdu ( - const protocol_ctxt_t* const ctxt_pP, - rlc_am_entity_t *const rlcP, - const rlc_sn_t snP, - boolean_t free_pdu); +void rlc_am_ack_pdu(const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t *const rlcP, + const rlc_sn_t snP, + bool free_pdu); /*! \fn mem_block_t* rlc_am_retransmit_get_copy (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *rlcP, rlc_sn_t snP) * \brief The RLC AM PDU which have the sequence number snP is marked ACKed. diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c index 4a06553901..bd578abab2 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c @@ -31,14 +31,13 @@ #include "common/utils/LOG/log.h" -boolean_t rlc_am_rx_check_vr_reassemble( - const protocol_ctxt_t* const ctxt_pP, - const rlc_am_entity_t* const rlc_pP) +bool rlc_am_rx_check_vr_reassemble(const protocol_ctxt_t* const ctxt_pP, + const rlc_am_entity_t* const rlc_pP) { mem_block_t* cursor_p = rlc_pP->receiver_buffer.head; rlc_am_rx_pdu_management_t * pdu_cursor_mgnt_p = NULL; sdu_size_t next_waited_so = 0; - boolean_t reassemble = FALSE; + bool reassemble = false; if (cursor_p != NULL) { @@ -48,7 +47,7 @@ boolean_t rlc_am_rx_check_vr_reassemble( if (sn_ref != rlc_pP->vr_r) { /* Case vrR has advanced from head : most likely case */ - reassemble = TRUE; + reassemble = true; /* Handle first SN if it is made of PDU segments : set them all to be reassembled */ if (pdu_info_p->rf) { pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data); @@ -58,7 +57,7 @@ boolean_t rlc_am_rx_check_vr_reassemble( { LOG_E(RLC, "AM Rx Check Reassembly head SN=%d with PDU segments != vrR=%d should be fully received LCID=%d\n", sn_ref,rlc_pP->vr_r,rlc_pP->channel_id); - return FALSE; + return false; } /* AssertFatal(pdu_cursor_mgnt_p->all_segments_received > 0,"AM Rx Check Reassembly head SN=%d with PDU segments != vrR=%d should be fully received LCID=%d\n", @@ -94,7 +93,7 @@ boolean_t rlc_am_rx_check_vr_reassemble( { LOG_E(RLC, "AM Rx Check Reassembly vr=%d should be partly received SNHead=%d LCID=%d\n", rlc_pP->vr_r,sn_ref,rlc_pP->channel_id); - return FALSE; + return false; } /* AssertFatal(pdu_cursor_mgnt_p->all_segments_received == 0,"AM Rx Check Reassembly vr=%d should be partly received SNHead=%d LCID=%d\n", @@ -123,7 +122,7 @@ boolean_t rlc_am_rx_check_vr_reassemble( { LOG_E(RLC, "AM Rx Check Reassembly SNHead=vr=%d should be partly received LCID=%d\n", rlc_pP->vr_r,rlc_pP->channel_id); - return FALSE; + return false; } /* AssertFatal(pdu_cursor_mgnt_p->all_segments_received == 0,"AM Rx Check Reassembly SNHead=vr=%d should be partly received LCID=%d\n", @@ -132,7 +131,7 @@ boolean_t rlc_am_rx_check_vr_reassemble( while ((cursor_p != NULL) && (pdu_info_p->sn == rlc_pP->vr_r) && (pdu_info_p->so == next_waited_so)) { if (pdu_cursor_mgnt_p->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO) { pdu_cursor_mgnt_p->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_PENDING; - reassemble = TRUE; + reassemble = true; } next_waited_so += pdu_info_p->payload_size; cursor_p = cursor_p->next; @@ -157,7 +156,7 @@ mem_block_t * create_new_segment_from_pdu( int16_t new_li_list[RLC_AM_MAX_SDU_IN_PDU]; int16_t header_size = 0; uint8_t num_li = 0; - boolean_t fi_start, fi_end, lsf; + bool fi_start, fi_end, lsf; /* Init some PDU Segment header fixed parameters */ fi_start = !((pdu_rx_info_p->fi & 0x2) >> 1); @@ -170,11 +169,11 @@ mem_block_t * create_new_segment_from_pdu( header_size = RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE; if (so_offset) { - fi_start = FALSE; + fi_start = false; } if (so_offset + data_length_to_copy != pdu_rx_info_p->payload_size) { - fi_end = FALSE; - lsf = FALSE; + fi_end = false; + lsf = false; } } // end no LI in original segment else { @@ -185,7 +184,7 @@ mem_block_t * create_new_segment_from_pdu( /* set LSF to false if we know that end of the original segment will not be copied */ if (so_offset + data_length_to_copy != pdu_rx_info_p->payload_size) { - lsf = FALSE; + lsf = false; } /* catch the first LI containing so_offset */ @@ -223,7 +222,7 @@ mem_block_t * create_new_segment_from_pdu( num_li = j; /* set FI End if remaining size = 0 */ if (remaining_size == 0) { - fi_end = TRUE; + fi_end = true; } } } @@ -263,7 +262,7 @@ mem_block_t * create_new_segment_from_pdu( } /* Fill Header part in the buffer */ - /* Content is supposed to be init with 0 so with FIStart=FIEnd=TRUE */ + /* Content is supposed to be init with 0 so with FIStart=FIEnd=true */ /* copy first two bytes from original: D/C + RF + FI + E+ SN*/ memset(pdu_segment_header_p, 0, header_size); RLC_AM_PDU_SET_D_C(*pdu_segment_header_p); @@ -1106,7 +1105,7 @@ rlc_am_rx_list_reassemble_rlc_sdus( do { if (rlc_am_rx_pdu_management_p->all_segments_received > 0) { cursor_p = list2_remove_head(&rlc_pP->receiver_buffer); - rlc_am_reassemble_pdu(ctxt_pP, rlc_pP, cursor_p,TRUE); + rlc_am_reassemble_pdu(ctxt_pP, rlc_pP, cursor_p, true); rlc_am_rx_old_pdu_management = rlc_am_rx_pdu_management_p; cursor_p = list2_get_head(&rlc_pP->receiver_buffer); @@ -1123,7 +1122,7 @@ rlc_am_rx_list_reassemble_rlc_sdus( else if (rlc_am_rx_pdu_management_p->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_PENDING) { rlc_am_rx_pdu_management_p->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLED; - rlc_am_reassemble_pdu(ctxt_pP, rlc_pP, cursor_p,FALSE); + rlc_am_reassemble_pdu(ctxt_pP, rlc_pP, cursor_p, false); rlc_am_rx_old_pdu_management = rlc_am_rx_pdu_management_p; cursor_p = cursor_p->next; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h index fd8704964d..18e423312c 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h @@ -61,13 +61,13 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_check_duplicate_insert_pdu(const protocol_ */ signed int rlc_am_rx_list_insert_pdu(const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t* const rlcP, mem_block_t* const tbP); -/*! \fn boolean_t rlc_am_rx_check_vr_reassemble(const protocol_ctxt_t* const ctxt_pP,const rlc_am_entity_t* const rlc_pP) +/*! \fn bool rlc_am_rx_check_vr_reassemble(const protocol_ctxt_t* const ctxt_pP,const rlc_am_entity_t* const rlc_pP) * \brief Check if reassembly taking into account potential new vrR value * \param[in] ctxt_pP Running context. * \param[in] rlcP RLC AM protocol instance pointer. -* \return TRUE if reassembly must be done, FALSE else +* \return true if reassembly must be done, false else */ -boolean_t rlc_am_rx_check_vr_reassemble(const protocol_ctxt_t* const ctxt_pP,const rlc_am_entity_t* const rlc_pP); +bool rlc_am_rx_check_vr_reassemble(const protocol_ctxt_t* const ctxt_pP,const rlc_am_entity_t* const rlc_pP); /*! \fn void rlc_am_rx_check_all_byte_segments(const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t* const rlcP, mem_block_t* const tbP) * \brief Check if all sub-segments of a PDU are received, if yes then call rlc_am_rx_mark_all_segments_received() procedure. diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c index ed81e119ac..9e7c3338f8 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c @@ -32,12 +32,11 @@ #include "common/utils/LOG/log.h" //----------------------------------------------------------------------------- -void rlc_am_pdu_polling ( - const protocol_ctxt_t* const ctxt_pP, - rlc_am_entity_t *const rlc_pP, - rlc_am_pdu_sn_10_t *const pdu_pP, - const int16_t payload_sizeP, - boolean_t is_new_pdu) +void rlc_am_pdu_polling(const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t *const rlc_pP, + rlc_am_pdu_sn_10_t *const pdu_pP, + const int16_t payload_sizeP, + bool is_new_pdu) { // 5.2.2 Polling // An AM RLC entity can poll its peer AM RLC entity in order to trigger STATUS reporting at the peer AM RLC entity. diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h index dc754d08e4..1e472302c8 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h @@ -36,14 +36,14 @@ # define __RLC_AM_SEGMENT_H__ //----------------------------------------------------------------------------- -/*! \fn void rlc_am_pdu_polling (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP,boolean_t is_new_pdu) +/*! \fn void rlc_am_pdu_polling (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP, bool is_new_pdu) * \brief Set or not the poll bit in the PDU header depending on RLC AM protocol variables. * \param[in] ctxt_pP Running context. * \param[in] rlcP RLC AM protocol instance pointer. * \param[in] pduP Pointer on the header of the PDU in order to be able to set the poll bit if necessary. * \param[in] payload_sizeP Size of the payload of the PDU. */ -void rlc_am_pdu_polling (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP,boolean_t is_new_pdu); +void rlc_am_pdu_polling (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP, bool is_new_pdu); /*! \fn void rlc_am_segment_10 (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t * const rlcP) * \brief Segment a PDU with 10 bits sequence number, based on segmentation information given by MAC (size to transmit). diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c index 02a0247a03..f1e6c961e7 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c @@ -237,7 +237,7 @@ rlc_am_receive_process_control_pdu( rlc_sn_t nack_sn,prev_nack_sn; sdu_size_t data_cnf_so_stop = 0x7FFF; unsigned int nack_index; - boolean_t status = TRUE; + bool status = true; if (rlc_am_get_control_pdu_infos(rlc_am_pdu_sn_10_p, tb_size_in_bytes_pP, &rlc_pP->control_pdu_info) >= 0) { rlc_am_tx_buffer_display(ctxt_pP, rlc_pP, " TX BUFFER BEFORE PROCESS OF STATUS PDU"); @@ -282,7 +282,7 @@ rlc_am_receive_process_control_pdu( if (RLC_AM_DIFF_SN(rlc_pP->vt_s,rlc_pP->vt_a) >= RLC_AM_DIFF_SN(ack_sn,rlc_pP->vt_a)) { if (rlc_pP->control_pdu_info.num_nack == 0) { while (sn_cursor != ack_sn) { - rlc_am_ack_pdu(ctxt_pP, rlc_pP, sn_cursor,TRUE); + rlc_am_ack_pdu(ctxt_pP, rlc_pP, sn_cursor, true); sn_cursor = RLC_AM_NEXT_SN(sn_cursor); } @@ -294,7 +294,7 @@ rlc_am_receive_process_control_pdu( prev_nack_sn = 0x3FFF; while (sn_cursor != nack_sn) { - rlc_am_ack_pdu(ctxt_pP, rlc_pP, sn_cursor,TRUE); + rlc_am_ack_pdu(ctxt_pP, rlc_pP, sn_cursor, true); sn_cursor = RLC_AM_NEXT_SN(sn_cursor); } @@ -316,7 +316,7 @@ rlc_am_receive_process_control_pdu( rlc_am_ack_pdu(ctxt_pP, rlc_pP, sn_cursor, - FALSE); + false); } else { status = rlc_am_nack_pdu (ctxt_pP, rlc_pP, @@ -348,13 +348,13 @@ rlc_am_receive_process_control_pdu( LOG_E(RLC, PROTOCOL_RLC_AM_CTXT_FMT" WARNING CONTROL PDU ACK SN %d OUT OF WINDOW vtA=%d vtS=%d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),ack_sn,rlc_pP->vt_a,rlc_pP->vt_s); *tb_size_in_bytes_pP = 0; - status = FALSE; + status = false; } } else { LOG_E(RLC, PROTOCOL_RLC_AM_CTXT_FMT" ERROR IN DECODING CONTROL PDU\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); *tb_size_in_bytes_pP = 0; - status = FALSE; + status = false; } if (status) { @@ -480,8 +480,8 @@ rlc_am_send_status_pdu( int waited_so = 0; mem_block_t *tb_p = NULL; sdu_size_t pdu_size = 0; - boolean_t status_report_completed = false; - boolean_t segment_loop_end = false; + bool status_report_completed = false; + bool segment_loop_end = false; memset(&control_pdu_info, 0, sizeof(rlc_am_control_pdu_info_t)); LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] nb_bits_to_transmit %d (15 already allocated for header)\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.c index 7a95a62787..e898a601c2 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.c @@ -1170,7 +1170,7 @@ void rlc_am_v9_3_0_test(void) { // initscr(); // cbreak(); - // keypad(stdscr, TRUE); + // keypad(stdscr, true); // under test pool_buffer_init(); set_comp_log(RLC, LOG_ERR, LOG_MED, 1); diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c index 969ed2d7a5..7aead2f30a 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c @@ -111,7 +111,7 @@ rlc_am_check_timer_poll_retransmit( } - rlc_pP->force_poll= TRUE; + rlc_pP->force_poll = true; //BugFix : new ms_time_out is computed when next poll is transmitter } } diff --git a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.c b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.c index 4e3fffe176..f079696aa9 100644 --- a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.c +++ b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.c @@ -31,13 +31,11 @@ #include "list.h" #include "LAYER2/MAC/mac_extern.h" //----------------------------------------------------------------------------- -void -rlc_tm_send_sdu ( - const protocol_ctxt_t* const ctxt_pP, - rlc_tm_entity_t * const rlc_pP, - const boolean_t error_indicationP, - uint8_t * const srcP, - const sdu_size_t length_in_bitsP) +void rlc_tm_send_sdu(const protocol_ctxt_t* const ctxt_pP, + rlc_tm_entity_t * const rlc_pP, + const bool error_indicationP, + uint8_t * const srcP, + const sdu_size_t length_in_bitsP) { int length_in_bytes; #if DEBUG_RLC_TM_DISPLAY_ASCII_DATA diff --git a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.h b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.h index d2bab33b1a..de7b9b8170 100644 --- a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.h +++ b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm.h @@ -51,7 +51,7 @@ /*! \fn void rlc_tm_send_sdu ( * const protocol_ctxt_t* const ctxt_pP, * rlc_tm_entity_t * const rlc_pP, -* const boolean_t error_indicationP, +* const bool error_indicationP, * uint8_t * const srcP, * const sdu_size_t length_in_bitsP) * \brief Send SDU if any reassemblied to upper layer. @@ -60,12 +60,11 @@ * \param[in] srcP SDU data pointer. * \param[in] length_in_bitsP Length of SDU in bits. */ -void rlc_tm_send_sdu ( - const protocol_ctxt_t* const ctxt_pP, - rlc_tm_entity_t * const rlc_pP, - const boolean_t error_indicationP, - uint8_t * const srcP, - const sdu_size_t length_in_bitsP); +void rlc_tm_send_sdu(const protocol_ctxt_t* const ctxt_pP, + rlc_tm_entity_t * const rlc_pP, + const bool error_indicationP, + uint8_t * const srcP, + const sdu_size_t length_in_bitsP); /*! \fn void rlc_tm_no_segment (const protocol_ctxt_t* const ctxt_pP, rlc_tm_entity_t * const rlcP) * \brief Schedule a SDU to be transmited by lower layers. diff --git a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_entity.h b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_entity.h index 1a13982df6..3c2f1804be 100644 --- a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_entity.h +++ b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_entity.h @@ -40,14 +40,13 @@ * \brief Structure containing a RLC TM instance protocol variables, allocation variables, buffers and other miscellaneous variables. */ typedef struct rlc_tm_entity { - boolean_t allocation; /*!< \brief Boolean for rlc_tm_entity_t struct allocation. */ + bool allocation; /*!< \brief Boolean for rlc_tm_entity_t struct allocation. */ rlc_protocol_state_t protocol_state; /*!< \brief Protocol state, can be RLC_NULL_STATE, RLC_DATA_TRANSFER_READY_STATE, RLC_LOCAL_SUSPEND_STATE. */ - boolean_t is_uplink_downlink; /*!< \brief Is this instance is a transmitter, a receiver or both? */ - boolean_t is_data_plane; /*!< \brief To know if the RLC belongs to a data radio bearer or a signalling radio bearer, for statistics and trace purpose. */ + bool is_uplink_downlink; /*!< \brief Is this instance is a transmitter, a receiver or both? */ + bool is_data_plane; /*!< \brief To know if the RLC belongs to a data radio bearer or a signalling radio bearer, for statistics and trace purpose. */ // for stats and trace purpose : logical_chan_id_t channel_id; /*!< \brief Transport channel identifier. */ rb_id_t rb_id; /*!< \brief Radio bearer identifier, for statistics and trace purpose. */ - //boolean_t is_enb; /*!< \brief To know if the RLC belongs to a eNB or UE. */ //----------------------------- // tranmission //----------------------------- diff --git a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c index 22e6f4d78d..a838b2a006 100644 --- a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c +++ b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c @@ -133,10 +133,9 @@ rlc_tm_cleanup ( } //----------------------------------------------------------------------------- -void rlc_tm_configure( - const protocol_ctxt_t* const ctxt_pP, - rlc_tm_entity_t * const rlcP, - const boolean_t is_uplink_downlinkP) +void rlc_tm_configure(const protocol_ctxt_t* const ctxt_pP, + rlc_tm_entity_t * const rlcP, + const bool is_uplink_downlinkP) { rlcP->is_uplink_downlink = is_uplink_downlinkP; rlc_tm_reset_state_variables (ctxt_pP, rlcP); diff --git a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h index 57e2116a72..f315a0311a 100644 --- a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h +++ b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h @@ -78,27 +78,24 @@ void rlc_tm_init ( * \brief Reset protocol variables and state variables to initial values. * \param[in] rlcP RLC TM protocol instance pointer. */ -void rlc_tm_reset_state_variables ( - const protocol_ctxt_t* const ctxt_pP, - rlc_tm_entity_t * const rlcP); +void rlc_tm_reset_state_variables(const protocol_ctxt_t* const ctxt_pP, + rlc_tm_entity_t * const rlcP); /*! \fn void rlc_tm_cleanup(rlc_tm_entity_t * const rlcP) * \brief Free all allocated memory (lists and buffers) previously allocated by this RLC TM instance. * \param[in] rlcP RLC TM protocol instance pointer. */ -void rlc_tm_cleanup( - rlc_tm_entity_t * const rlcP); +void rlc_tm_cleanup(rlc_tm_entity_t * const rlcP); -/*! \fn void rlc_tm_configure(const protocol_ctxt_t* const ctxt_pP,rlc_tm_entity_t * const rlcP, const boolean_t is_uplink_downlinkP) +/*! \fn void rlc_tm_configure(const protocol_ctxt_t* const ctxt_pP,rlc_tm_entity_t * const rlcP, const bool is_uplink_downlinkP) * \brief Configure RLC TM protocol parameters. * \param[in] rlcP RLC TM protocol instance pointer. * \param[in] is_uplink_downlinkP Is this instance is TRANSMITTER_ONLY, RECEIVER_ONLY, or TRANSMITTER_AND_RECEIVER. */ -void rlc_tm_configure( - const protocol_ctxt_t* const ctxt_pP, - rlc_tm_entity_t * const rlcP, - const boolean_t is_uplink_downlinkP); +void rlc_tm_configure(const protocol_ctxt_t* const ctxt_pP, + rlc_tm_entity_t * const rlcP, + const bool is_uplink_downlinkP); /*! \fn void rlc_tm_set_debug_infos(const protocol_ctxt_t* const ctxt_pP, rlc_tm_entity_t * const rlcP, const rb_id_t rb_idP, const srb_flag_t srb_flagP) * \brief Set debug informations for a RLC TM protocol instance, these informations are only for trace purpose. diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c index bec815ac5d..f2cb4f09b1 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c @@ -263,7 +263,7 @@ rlc_um_init ( } rlc_pP->first_pdu = 1; - rlc_pP->initialized = TRUE; + rlc_pP->initialized = true; } } //----------------------------------------------------------------------------- diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_entity.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_entity.h index 3250ac85b8..7bfa3d60ff 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_entity.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_entity.h @@ -53,12 +53,11 @@ typedef struct rlc_um_timer_s { */ typedef struct rlc_um_entity_s { - boolean_t initialized; /*!< \brief Boolean for rlc_am_entity_t struct initialization. */ - boolean_t is_uplink_downlink; /*!< \brief Is this instance is a transmitter, a receiver or both? */ + bool initialized; /*!< \brief Boolean for rlc_am_entity_t struct initialization. */ + bool is_uplink_downlink; /*!< \brief Is this instance is a transmitter, a receiver or both? */ rlc_protocol_state_t protocol_state; /*!< \brief Protocol state, can be RLC_NULL_STATE, RLC_DATA_TRANSFER_READY_STATE, RLC_LOCAL_SUSPEND_STATE. */ - boolean_t is_data_plane; /*!< \brief To know if the RLC belongs to a data radio bearer or a signalling radio bearer, for statistics and trace purpose. */ - //boolean_t is_enb; /*!< \brief To know if the RLC belongs to a eNB or UE. */ - boolean_t is_mxch; /*!< \brief To know if the RLC belongs to a MBMS bearer. */ + bool is_data_plane; /*!< \brief To know if the RLC belongs to a data radio bearer or a signalling radio bearer, for statistics and trace purpose. */ + bool is_mxch; /*!< \brief To know if the RLC belongs to a MBMS bearer. */ //----------------------------- // PROTOCOL VARIABLES //----------------------------- @@ -114,7 +113,7 @@ typedef struct rlc_um_entity_s { //----------------------------- // STATISTICS //----------------------------- - boolean_t first_pdu; /*!< \brief Act as a boolean, tells if the next PDU is the first PDU to be received. */ + bool first_pdu; /*!< \brief Act as a boolean, tells if the next PDU is the first PDU to be received. */ unsigned int stat_tx_pdcp_sdu; /*!< \brief Number of SDUs received from upper layers. */ unsigned int stat_tx_pdcp_bytes; /*!< \brief Number of SDU bytes received from upper layers. */ diff --git a/openair2/LAYER2/RLC/rlc.c b/openair2/LAYER2/RLC/rlc.c index b9dcf0414b..ec90817500 100644 --- a/openair2/LAYER2/RLC/rlc.c +++ b/openair2/LAYER2/RLC/rlc.c @@ -41,13 +41,12 @@ #include "common/ran_context.h" extern RAN_CONTEXT_t RC; -extern boolean_t pdcp_data_ind( - const protocol_ctxt_t *const ctxt_pP, - const srb_flag_t srb_flagP, - const MBMS_flag_t MBMS_flagP, - const rb_id_t rb_idP, - const sdu_size_t sdu_buffer_sizeP, - mem_block_t *const sdu_buffer_pP); +extern bool pdcp_data_ind(const protocol_ctxt_t *const ctxt_pP, + const srb_flag_t srb_flagP, + const MBMS_flag_t MBMS_flagP, + const rb_id_t rb_idP, + const sdu_size_t sdu_buffer_sizeP, + mem_block_t *const sdu_buffer_pP); #define DEBUG_RLC_PDCP_INTERFACE 1 //#define TRACE_RLC_PAYLOAD 1 @@ -397,7 +396,7 @@ rlc_op_status_t rlc_data_req (const protocol_ctxt_t *const ctxt_pP, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_IN); - if (MBMS_flagP == TRUE) { + if (MBMS_flagP == true) { if (ctxt_pP->enb_flag) { log_ch_id = rlc_mbms_enb_get_lcid_by_rb_id(ctxt_pP->module_id,rb_idP); mbms_id_p = &rlc_mbms_lcid2service_session_id_eNB[ctxt_pP->module_id][log_ch_id]; diff --git a/openair2/LAYER2/RLC/rlc.h b/openair2/LAYER2/RLC/rlc.h index 1e5b7947d7..1e17ff96bf 100644 --- a/openair2/LAYER2/RLC/rlc.h +++ b/openair2/LAYER2/RLC/rlc.h @@ -107,7 +107,7 @@ typedef struct { rlc_buffer_occupancy_t pdus_in_buffer; /*!< \brief Number of PDUs buffered in RLC protocol instance (OBSOLETE). */ frame_t head_sdu_creation_time; /*!< \brief Head SDU creation time. */ sdu_size_t head_sdu_remaining_size_to_send; /*!< \brief remaining size of sdu: could be the total size or the remaining size of already segmented sdu */ - boolean_t head_sdu_is_segmented; /*!< \brief 0 if head SDU has not been segmented, 1 if already segmented */ + bool head_sdu_is_segmented; /*!< \brief 0 if head SDU has not been segmented, 1 if already segmented */ } mac_rlc_status_resp_t; diff --git a/openair2/LAYER2/RLC/rlc_mac.c b/openair2/LAYER2/RLC/rlc_mac.c index 89cbe4c406..0e1cb89fd7 100644 --- a/openair2/LAYER2/RLC/rlc_mac.c +++ b/openair2/LAYER2/RLC/rlc_mac.c @@ -425,8 +425,8 @@ rlc_buffer_occupancy_t mac_rlc_get_buffer_occupancy_ind( /* Assumptions : for UE only */ /* At each TTI, Buffer Occupancy is first computed in mac_rlc_status_ind called by MAC ue_scheduler() function */ /* Then this function is called during MAC multiplexing ue_get_sdu(), and it may be call several times for the same bearer if it is in AM mode and there are several PDU types to transmit */ - //AssertFatal(enb_flagP == FALSE,"RLC Tx mac_rlc_get_buffer_occupancy_ind function is not implemented for eNB LcId=%d\n", channel_idP); - if(enb_flagP != FALSE) { + //AssertFatal(enb_flagP == false,"RLC Tx mac_rlc_get_buffer_occupancy_ind function is not implemented for eNB LcId=%d\n", channel_idP); + if(enb_flagP != false) { LOG_E(RLC, "Tx mac_rlc_get_buffer_occupancy_ind function is not implemented for eNB LcId=%u\n", channel_idP); return 0; } diff --git a/openair2/LAYER2/RLC/rlc_rrc.c b/openair2/LAYER2/RLC/rlc_rrc.c index 4313f379fe..ed9af5efb2 100644 --- a/openair2/LAYER2/RLC/rlc_rrc.c +++ b/openair2/LAYER2/RLC/rlc_rrc.c @@ -480,7 +480,7 @@ rlc_op_status_t rrc_rlc_remove_rlc ( /* for no gcc warnings */ (void)lcid; - if (MBMS_flagP == TRUE) { + if (MBMS_flagP == true) { if (ctxt_pP->enb_flag) { lcid = rlc_mbms_enb_get_lcid_by_rb_id(ctxt_pP->module_id,rb_idP); mbms_id_p = &rlc_mbms_lcid2service_session_id_eNB[ctxt_pP->module_id][lcid]; @@ -581,7 +581,7 @@ rlc_union_t *rrc_rlc_add_rlc ( rlc_mbms_id_t *mbms_id_p = NULL; logical_chan_id_t lcid = 0; - if (MBMS_flagP == FALSE) { + if (MBMS_flagP == false) { //AssertFatal (rb_idP < NB_RB_MAX, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX); //AssertFatal (chan_idP < RLC_MAX_LC, "LC id is too high (%u/%d)!\n", chan_idP, RLC_MAX_LC); if(rb_idP >= NB_RB_MAX) { @@ -595,7 +595,7 @@ rlc_union_t *rrc_rlc_add_rlc ( } } - if (MBMS_flagP == TRUE) { + if (MBMS_flagP == true) { if (ctxt_pP->enb_flag) { lcid = rlc_mbms_enb_get_lcid_by_rb_id(ctxt_pP->module_id,rb_idP); mbms_id_p = &rlc_mbms_lcid2service_session_id_eNB[ctxt_pP->module_id][lcid]; @@ -640,11 +640,11 @@ rlc_union_t *rrc_rlc_add_rlc ( } else if (h_rc == HASH_TABLE_KEY_NOT_EXISTS) { rlc_union_p = calloc(1, sizeof(rlc_union_t)); h_rc = hashtable_insert(rlc_coll_p, key, rlc_union_p); - if(MBMS_flagP != TRUE) + if(MBMS_flagP != true) h_lcid_rc = hashtable_insert(rlc_coll_p, key_lcid, rlc_union_p); if ((h_rc == HASH_TABLE_OK) && (h_lcid_rc == HASH_TABLE_OK)) { - if (MBMS_flagP == TRUE) { + if (MBMS_flagP == true) { LOG_I(RLC, PROTOCOL_CTXT_FMT" RLC service id %u session id %u rrc_rlc_add_rlc\n", PROTOCOL_CTXT_ARGS(ctxt_pP), mbms_id_p->service_id, diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index fc794ad169..9598bf1ad6 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -359,15 +359,14 @@ static void enqueue_pdcp_data_ind( if (pthread_mutex_unlock(&pq.m) != 0) abort(); } -boolean_t pdcp_data_ind( - const protocol_ctxt_t *const ctxt_pP, - const srb_flag_t srb_flagP, - const MBMS_flag_t MBMS_flagP, - const rb_id_t rb_id, - const sdu_size_t sdu_buffer_size, - mem_block_t *const sdu_buffer, - const uint32_t *const srcID, - const uint32_t *const dstID) +bool pdcp_data_ind(const protocol_ctxt_t *const ctxt_pP, + const srb_flag_t srb_flagP, + const MBMS_flag_t MBMS_flagP, + const rb_id_t rb_id, + const sdu_size_t sdu_buffer_size, + mem_block_t *const sdu_buffer, + const uint32_t *const srcID, + const uint32_t *const dstID) { enqueue_pdcp_data_ind(ctxt_pP, srb_flagP, @@ -438,7 +437,7 @@ static void *enb_tun_read_thread(void *_) ctxt.rnti = rnti; uint8_t qfi = 7; - boolean_t rqi = 0; + bool rqi = 0; int pdusession_id = 10; sdap_data_req(&ctxt, SRB_FLAG_NO, rb_id, RLC_MUI_UNDEFINED, @@ -484,7 +483,7 @@ static void *ue_tun_read_thread(void *_) ctxt.rnti = rnti; - boolean_t dc = SDAP_HDR_UL_DATA_PDU; + bool dc = SDAP_HDR_UL_DATA_PDU; uint8_t qfi = 7; int pdusession_id = 10; @@ -858,7 +857,7 @@ void pdcp_run(const protocol_ctxt_t *const ctxt_pP) RRC_DCCH_DATA_REQ(msg_p).mode, NULL, NULL); - if (result != TRUE) + if (result != true) LOG_E(PDCP, "PDCP data request failed!\n"); result = itti_free(ITTI_MSG_ORIGIN_ID(msg_p), RRC_DCCH_DATA_REQ(msg_p).sdu_p); AssertFatal(result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); @@ -950,7 +949,7 @@ static void add_drb_am(int is_gnb, int rnti, struct NR_DRB_ToAddMod *s, int has_sdap = 0; int has_sdapULheader=0; int has_sdapDLheader=0; - boolean_t is_sdap_DefaultDRB = false; + bool is_sdap_DefaultDRB = false; NR_QFI_t *mappedQFIs2Add = NULL; uint8_t mappedQFIs2AddCount=0; if (s->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity) @@ -1033,20 +1032,18 @@ static void add_drb(int is_gnb, int rnti, struct NR_DRB_ToAddMod *s, LOG_I(PDCP, "%s:%s:%d: added DRB for UE RNTI %x\n", __FILE__, __FUNCTION__, __LINE__, rnti); } -boolean_t nr_rrc_pdcp_config_asn1_req( - const protocol_ctxt_t *const ctxt_pP, - NR_SRB_ToAddModList_t *const srb2add_list, - NR_DRB_ToAddModList_t *const drb2add_list, - NR_DRB_ToReleaseList_t *const drb2release_list, - const uint8_t security_modeP, - uint8_t *const kRRCenc, - uint8_t *const kRRCint, - uint8_t *const kUPenc, - uint8_t *const kUPint - ,LTE_PMCH_InfoList_r9_t *pmch_InfoList_r9 - ,rb_id_t *const defaultDRB, - struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_bearer2add_list) - //struct NR_RLC_Config *rlc_Config) +bool nr_rrc_pdcp_config_asn1_req(const protocol_ctxt_t *const ctxt_pP, + NR_SRB_ToAddModList_t *const srb2add_list, + NR_DRB_ToAddModList_t *const drb2add_list, + NR_DRB_ToReleaseList_t *const drb2release_list, + const uint8_t security_modeP, + uint8_t *const kRRCenc, + uint8_t *const kRRCint, + uint8_t *const kUPenc, + uint8_t *const kUPint, + LTE_PMCH_InfoList_r9_t *pmch_InfoList_r9, + rb_id_t *const defaultDRB, + struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_bearer2add_list) { int rnti = ctxt_pP->rnti; int i; @@ -1104,17 +1101,16 @@ boolean_t nr_rrc_pdcp_config_asn1_req( } /* Dummy function due to dependency from LTE libraries */ -boolean_t rrc_pdcp_config_asn1_req( - const protocol_ctxt_t *const ctxt_pP, - LTE_SRB_ToAddModList_t *const srb2add_list, - LTE_DRB_ToAddModList_t *const drb2add_list, - LTE_DRB_ToReleaseList_t *const drb2release_list, - const uint8_t security_modeP, - uint8_t *const kRRCenc, - uint8_t *const kRRCint, - uint8_t *const kUPenc - ,LTE_PMCH_InfoList_r9_t *pmch_InfoList_r9 - ,rb_id_t *const defaultDRB) +bool rrc_pdcp_config_asn1_req(const protocol_ctxt_t *const ctxt_pP, + LTE_SRB_ToAddModList_t *const srb2add_list, + LTE_DRB_ToAddModList_t *const drb2add_list, + LTE_DRB_ToReleaseList_t *const drb2release_list, + const uint8_t security_modeP, + uint8_t *const kRRCenc, + uint8_t *const kRRCint, + uint8_t *const kUPenc, + LTE_PMCH_InfoList_r9_t *pmch_InfoList_r9, + rb_id_t *const defaultDRB) { return 0; } @@ -1219,8 +1215,7 @@ uint64_t get_pdcp_optmask(void) return pdcp_optmask; } -boolean_t pdcp_remove_UE( - const protocol_ctxt_t *const ctxt_pP) +bool pdcp_remove_UE(const protocol_ctxt_t *const ctxt_pP) { int rnti = ctxt_pP->rnti; @@ -1275,13 +1270,12 @@ void pdcp_config_set_security( nr_pdcp_manager_unlock(nr_pdcp_ue_manager); } -static boolean_t pdcp_data_req_srb( - protocol_ctxt_t *ctxt_pP, - const rb_id_t rb_id, - const mui_t muiP, - const confirm_t confirmP, - const sdu_size_t sdu_buffer_size, - unsigned char *const sdu_buffer) +static bool pdcp_data_req_srb(protocol_ctxt_t *ctxt_pP, + const rb_id_t rb_id, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_buffer_size, + unsigned char *const sdu_buffer) { LOG_D(PDCP, "%s() called, size %d\n", __func__, sdu_buffer_size); nr_pdcp_ue_t *ue; @@ -1322,13 +1316,12 @@ static boolean_t pdcp_data_req_srb( } -static boolean_t pdcp_data_req_drb( - protocol_ctxt_t *ctxt_pP, - const rb_id_t rb_id, - const mui_t muiP, - const confirm_t confirmP, - const sdu_size_t sdu_buffer_size, - unsigned char *const sdu_buffer) +static bool pdcp_data_req_drb(protocol_ctxt_t *ctxt_pP, + const rb_id_t rb_id, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_buffer_size, + unsigned char *const sdu_buffer) { LOG_D(PDCP, "%s() called, size %d\n", __func__, sdu_buffer_size); nr_pdcp_ue_t *ue; @@ -1368,19 +1361,16 @@ static boolean_t pdcp_data_req_drb( return 1; } -boolean_t cu_f1u_data_req( - protocol_ctxt_t *ctxt_pP, - const srb_flag_t srb_flagP, - const rb_id_t rb_id, - const mui_t muiP, - const confirm_t confirmP, - const sdu_size_t sdu_buffer_size, - unsigned char *const sdu_buffer, - const pdcp_transmission_mode_t mode - ,const uint32_t *const sourceL2Id - ,const uint32_t *const destinationL2Id - ) { - +bool cu_f1u_data_req(protocol_ctxt_t *ctxt_pP, + const srb_flag_t srb_flagP, + const rb_id_t rb_id, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_buffer_size, + unsigned char *const sdu_buffer, + const pdcp_transmission_mode_t mode, + const uint32_t *const sourceL2Id, + const uint32_t *const destinationL2Id) { //Force instance id to 0, OAI incoherent instance management ctxt_pP->instance=0; mem_block_t *memblock = get_free_mem_block(sdu_buffer_size, __func__); @@ -1397,18 +1387,16 @@ boolean_t cu_f1u_data_req( return ret; } -boolean_t pdcp_data_req( - protocol_ctxt_t *ctxt_pP, - const srb_flag_t srb_flagP, - const rb_id_t rb_id, - const mui_t muiP, - const confirm_t confirmP, - const sdu_size_t sdu_buffer_size, - unsigned char *const sdu_buffer, - const pdcp_transmission_mode_t mode - ,const uint32_t *const sourceL2Id - ,const uint32_t *const destinationL2Id - ) +bool pdcp_data_req(protocol_ctxt_t *ctxt_pP, + const srb_flag_t srb_flagP, + const rb_id_t rb_id, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_buffer_size, + unsigned char *const sdu_buffer, + const pdcp_transmission_mode_t mode, + const uint32_t *const sourceL2Id, + const uint32_t *const destinationL2Id) { if (srb_flagP) { return pdcp_data_req_srb(ctxt_pP, rb_id, muiP, confirmP, sdu_buffer_size, sdu_buffer); diff --git a/openair2/M2AP/m2ap_common.h b/openair2/M2AP/m2ap_common.h index 95da064b4a..0a6895fcb7 100644 --- a/openair2/M2AP/m2ap_common.h +++ b/openair2/M2AP/m2ap_common.h @@ -55,11 +55,6 @@ # define M2AP_PORT 36423 #endif -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - extern int asn1_xer_print; #if defined(ENB_MODE) diff --git a/openair2/RRC/LITE/rrc_common.c b/openair2/RRC/LITE/rrc_common.c index a4239e857d..f0c4e94c99 100644 --- a/openair2/RRC/LITE/rrc_common.c +++ b/openair2/RRC/LITE/rrc_common.c @@ -306,7 +306,7 @@ rrc_rx_tx( LOG_D(RRC,"SFN.SN %d.%d => release timer %d/%d\n",ctxt_pP->frame,ctxt_pP->subframe, ue_context_p->ue_context.ue_release_timer,ue_context_p->ue_context.ue_release_timer_thres); if ((ctxt_pP->frame == 0) && (ctxt_pP->subframe==0)) { - if (ue_context_p->ue_context.Initialue_identity_s_TMSI.presence == TRUE) { + if (ue_context_p->ue_context.Initialue_identity_s_TMSI.presence == true) { LOG_I(RRC,"UE rnti %x:S-TMSI %x failure timer %d/20000\n", ue_context_p->ue_context.rnti, ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi, diff --git a/openair2/RRC/LTE/L2_interface.c b/openair2/RRC/LTE/L2_interface.c index 0a63acc8fb..c12d2aa873 100644 --- a/openair2/RRC/LTE/L2_interface.c +++ b/openair2/RRC/LTE/L2_interface.c @@ -299,7 +299,7 @@ mac_rrc_data_ind( const uint8_t *sduP, const sdu_size_t sdu_lenP, const uint8_t mbsfn_sync_areaP, - const boolean_t brOption + const bool brOption ) //-------------------------------------------------------------------------- { diff --git a/openair2/RRC/LTE/L2_interface_common.c b/openair2/RRC/LTE/L2_interface_common.c index 1993fe7de0..660bd91dda 100644 --- a/openair2/RRC/LTE/L2_interface_common.c +++ b/openair2/RRC/LTE/L2_interface_common.c @@ -58,7 +58,7 @@ rrc_data_req( { if(sdu_sizeP == 255) { LOG_I(RRC,"sdu_sizeP == 255"); - return FALSE; + return false; } MessageDef *message_p; @@ -94,7 +94,7 @@ rrc_data_req( if (ctxt_pP->enb_flag && NODE_IS_CU(RC.rrc[ctxt_pP->module_id]->node_type)) pdcp_run(ctxt_pP); - return TRUE; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway. + return true; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway. } //------------------------------------------------------------------------------ diff --git a/openair2/RRC/LTE/L2_interface_ue.c b/openair2/RRC/LTE/L2_interface_ue.c index 534030864a..850ecf1b58 100644 --- a/openair2/RRC/LTE/L2_interface_ue.c +++ b/openair2/RRC/LTE/L2_interface_ue.c @@ -298,7 +298,7 @@ rrc_data_req_ue( TASK_PDCP_UE, ctxt_pP->instance, message_p); - return TRUE; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway. + return true; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway. } } diff --git a/openair2/RRC/LTE/MESSAGES/asn1_msg.c b/openair2/RRC/LTE/MESSAGES/asn1_msg.c index c34c65b195..e5024e3505 100644 --- a/openair2/RRC/LTE/MESSAGES/asn1_msg.c +++ b/openair2/RRC/LTE/MESSAGES/asn1_msg.c @@ -343,7 +343,7 @@ uint8_t do_MIB_SL(const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index, if (in_coverage > 0 ) { //in coverage - mib_sl->inCoverage_r12 = TRUE; + mib_sl->inCoverage_r12 = true; mib_sl->sl_Bandwidth_r12 = *UE_rrc_inst[ctxt_pP->module_id].sib2[eNB_index]->freqInfo.ul_Bandwidth; if (UE_rrc_inst[ctxt_pP->module_id].sib1[eNB_index]->tdd_Config) { @@ -366,7 +366,7 @@ uint8_t do_MIB_SL(const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index, } else { //Todo - out of coverage for V2X // Todo - UE has a selected SyncRef UE - mib_sl->inCoverage_r12 = FALSE; + mib_sl->inCoverage_r12 = false; //set sl-Bandwidth, subframeAssignmentSL and reserved from the pre-configured parameters } @@ -989,7 +989,7 @@ uint8_t do_SIB1(rrc_eNB_carrier_data_t *carrier, sib1_1250->nonCriticalExtension = NULL; ////Rel1310 if ((configuration->schedulingInfoSIB1_BR_r13[CC_id] != 0) && - (brOption==TRUE)) { + (brOption==true)) { sib1_1250->nonCriticalExtension = calloc(1, sizeof(LTE_SystemInformationBlockType1_v1310_IEs_t)); memset(sib1_1250->nonCriticalExtension, 0, sizeof(LTE_SystemInformationBlockType1_v1310_IEs_t)); LTE_SystemInformationBlockType1_v1310_IEs_t *sib1_1310 = sib1_1250->nonCriticalExtension; @@ -1279,7 +1279,7 @@ uint8_t do_SIB23(uint8_t Mod_id, *sib2 = &sib2_part->choice.sib2; *sib3 = &sib3_part->choice.sib3; - if ((configuration->eMBMS_configured > 0) && (brOption==FALSE)) { + if ((configuration->eMBMS_configured > 0) && (brOption==false)) { sib13_part = CALLOC(1,sizeof(struct LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member)); memset(sib13_part,0,sizeof(struct LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member)); sib13_part->present = LTE_SystemInformation_r8_IEs__sib_TypeAndInfo__Member_PR_sib13_v920; @@ -2781,7 +2781,7 @@ do_RRCConnectionSetup( mac_MainConfig->ul_SCH_Config->maxHARQ_Tx = maxHARQ_Tx; // max number of UL HARQ transmission mac_MainConfig->ul_SCH_Config->periodicBSR_Timer = periodicBSR_Timer; mac_MainConfig->ul_SCH_Config->retxBSR_Timer = LTE_RetxBSR_Timer_r12_sf320; // LTE_RetxBSR_Timer_r12_sf5120 // regular BSR timer - mac_MainConfig->ul_SCH_Config->ttiBundling = 0; // FALSE + mac_MainConfig->ul_SCH_Config->ttiBundling = 0; // false //* timeAlignmentTimerDedicated *// mac_MainConfig->timeAlignmentTimerDedicated = LTE_TimeAlignmentTimer_infinity; //* DRX Config *// @@ -3135,7 +3135,7 @@ uint8_t do_RRCConnectionSetup_BR( //mac_MainConfig->ul_SCH_Config->maxHARQ_Tx = maxHARQ_Tx; mac_MainConfig->ul_SCH_Config->periodicBSR_Timer = periodicBSR_Timer; mac_MainConfig->ul_SCH_Config->retxBSR_Timer = LTE_RetxBSR_Timer_r12_sf320; - mac_MainConfig->ul_SCH_Config->ttiBundling = 0; // FALSE + mac_MainConfig->ul_SCH_Config->ttiBundling = 0; // false mac_MainConfig->timeAlignmentTimerDedicated = LTE_TimeAlignmentTimer_infinity; mac_MainConfig->drx_Config = NULL; mac_MainConfig->phr_Config = CALLOC(1, sizeof(*mac_MainConfig->phr_Config)); diff --git a/openair2/RRC/LTE/defs_NB_IoT.h b/openair2/RRC/LTE/defs_NB_IoT.h index c76bdea53f..b98dbe22cc 100644 --- a/openair2/RRC/LTE/defs_NB_IoT.h +++ b/openair2/RRC/LTE/defs_NB_IoT.h @@ -156,7 +156,7 @@ typedef struct UE_RRC_INFO_NB_IoT_s { #define RRC_TRANSACTION_IDENTIFIER_NUMBER 3 typedef struct UE_S_TMSI_NB_IoT_s { - boolean_t presence; + bool presence; mme_code_t mme_code; m_tmsi_t m_tmsi; } __attribute__ ((__packed__)) UE_S_TMSI_NB_IoT; diff --git a/openair2/RRC/LTE/rrc_UE.c b/openair2/RRC/LTE/rrc_UE.c index 9b37853ed2..577ee3effd 100644 --- a/openair2/RRC/LTE/rrc_UE.c +++ b/openair2/RRC/LTE/rrc_UE.c @@ -4351,8 +4351,8 @@ void rrc_ue_generate_nrMeasurementReport(protocol_ctxt_t *const ctxt_pP, uint8_t AssertFatal(size >= 0, "do_nrMeasurementReport failed \n"); LOG_I(RRC, "[UE %d] Frame %d : Generating Measurement Report for eNB %d\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index); - int result = pdcp_data_req(ctxt_pP, SRB_FLAG_YES, DCCH, rrc_mui++, 0, size, buffer, PDCP_TRANSMISSION_MODE_DATA,NULL, NULL); - AssertFatal (result == TRUE, "PDCP data request failed!\n"); + const bool result = pdcp_data_req(ctxt_pP, SRB_FLAG_YES, DCCH, rrc_mui++, 0, size, buffer, PDCP_TRANSMISSION_MODE_DATA,NULL, NULL); + AssertFatal (result == true, "PDCP data request failed!\n"); } } } @@ -4370,7 +4370,6 @@ void rrc_ue_generate_MeasurementReport(protocol_ctxt_t *const ctxt_pP, uint8_t e long nElem, nElem1; float rsrp_filtered, rsrq_filtered; static frame_t pframe=0; - int result; nElem = 98; nElem1 = 35; target_eNB_offset = UE_rrc_inst[ctxt_pP->module_id].Info[0].handoverTarget; // eNB_offset of target eNB: used to obtain the mod_id of target eNB @@ -4420,8 +4419,8 @@ void rrc_ue_generate_MeasurementReport(protocol_ctxt_t *const ctxt_pP, uint8_t e AssertFatal(size >= 0, "do_MeasurementReport failed \n"); LOG_I(RRC, "[UE %d] Frame %d : Generating Measurement Report for eNB %d. Size is %zu\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index, size); - result = pdcp_data_req(ctxt_pP, SRB_FLAG_YES, DCCH, rrc_mui++, 0, size, buffer, PDCP_TRANSMISSION_MODE_DATA,NULL, NULL); - AssertFatal (result == TRUE, "PDCP data request failed!\n"); + const bool result = pdcp_data_req(ctxt_pP, SRB_FLAG_YES, DCCH, rrc_mui++, 0, size, buffer, PDCP_TRANSMISSION_MODE_DATA,NULL, NULL); + AssertFatal (result == true, "PDCP data request failed!\n"); //LOG_D(RRC, "[UE %d] Frame %d Sending MeasReport (%d bytes) through DCCH%d to PDCP \n",ue_mod_idP,frameP, size, DCCH); } diff --git a/openair2/RRC/LTE/rrc_defs.h b/openair2/RRC/LTE/rrc_defs.h index 64baf5e2ac..22c8a14863 100644 --- a/openair2/RRC/LTE/rrc_defs.h +++ b/openair2/RRC/LTE/rrc_defs.h @@ -367,7 +367,7 @@ typedef struct UE_RRC_INFO_s { } __attribute__ ((__packed__)) UE_RRC_INFO; typedef struct UE_S_TMSI_s { - boolean_t presence; + bool presence; mme_code_t mme_code; m_tmsi_t m_tmsi; } __attribute__ ((__packed__)) UE_S_TMSI; @@ -931,7 +931,7 @@ typedef struct UE_RRC_INST_s { } UE_RRC_INST; typedef struct UE_PF_PO_s { - boolean_t enable_flag; /* flag indicate whether current object is used */ + bool enable_flag; /* flag indicate whether current object is used */ uint16_t ue_index_value; /* UE index value */ uint8_t PF_min; /* minimal value of Paging Frame (PF) */ uint8_t PO; /* Paging Occasion (PO) */ diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c index ea98d3169d..a5d938cdf6 100644 --- a/openair2/RRC/LTE/rrc_eNB.c +++ b/openair2/RRC/LTE/rrc_eNB.c @@ -150,7 +150,7 @@ init_SI( LTE_SystemInformationBlockType1_v1310_IEs_t *sib1_v13ext=(LTE_SystemInformationBlockType1_v1310_IEs_t *)NULL; LOG_D(RRC,"%s()\n\n\n\n",__FUNCTION__); - if(configuration->radioresourceconfig[CC_id].mbms_dedicated_serving_cell == TRUE) { + if(configuration->radioresourceconfig[CC_id].mbms_dedicated_serving_cell == true) { LOG_A(RRC, "Configuring MIB FeMBMS (N_RB_DL %d)\n", (int)configuration->N_RB_DL[CC_id]); RC.rrc[ctxt_pP->module_id]->carrier[CC_id].MIB_FeMBMS = (uint8_t *) malloc16(4); @@ -266,7 +266,7 @@ init_SI( carrier->sizeof_SIB1 = do_SIB1(&rrc->carrier[CC_id], ctxt_pP->module_id, CC_id, - FALSE, + false, configuration ); AssertFatal(carrier->sizeof_SIB1 != 255,"FATAL, RC.rrc[enb_mod_idP].carrier[CC_id].sizeof_SIB1 == 255"); @@ -276,7 +276,7 @@ init_SI( RC.rrc[ctxt_pP->module_id]->carrier[CC_id].SIB1_BR = (uint8_t *) malloc16(32); RC.rrc[ctxt_pP->module_id]->carrier[CC_id].sizeof_SIB1_BR = do_SIB1(&RC.rrc[ctxt_pP->module_id]->carrier[CC_id], ctxt_pP->module_id, - CC_id, TRUE, configuration); + CC_id, true, configuration); } } @@ -285,7 +285,7 @@ init_SI( AssertFatal(carrier->SIB23!=NULL,"cannot allocate memory for SIB"); carrier->sizeof_SIB23 = do_SIB23(ctxt_pP->module_id, CC_id, - FALSE, + false, configuration ); LOG_I(RRC,"do_SIB23, size %d \n ", carrier->sizeof_SIB23); @@ -295,7 +295,7 @@ init_SI( if (configuration->schedulingInfoSIB1_BR_r13[CC_id]>0) { carrier->SIB23_BR = (uint8_t *) malloc16(64); AssertFatal(carrier->SIB23_BR!=NULL,"cannot allocate memory for SIB"); - carrier->sizeof_SIB23_BR = do_SIB23(ctxt_pP->module_id, CC_id, TRUE, configuration); + carrier->sizeof_SIB23_BR = do_SIB23(ctxt_pP->module_id, CC_id, true, configuration); } LOG_T(RRC, PROTOCOL_RRC_CTXT_FMT" SIB2/3 Contents (partial)\n", @@ -661,7 +661,7 @@ rrc_eNB_get_next_transaction_identifier( ////----------------------------------------------------------------------------- //{ // -// boolean_t reg = FALSE; +// bool reg = false; // module_id_t i; // // AssertFatal(enb_mod_idP < NB_eNB_INST, "eNB index invalid (%d/%d)!", enb_mod_idP, NB_eNB_INST); @@ -669,12 +669,12 @@ rrc_eNB_get_next_transaction_identifier( // for (i = 0; i < MAX_MOBILES_PER_ENB; i++) { // if (RC.rrc[enb_mod_idP]->Info.UE_info[i] == UE_identity) { // // UE_identity already registered -// reg = TRUE; +// reg = true; // break; // } // } // -// if (reg == FALSE) { +// if (reg == false) { // return (UE_MODULE_INVALID); // } else // return (i); @@ -713,7 +713,7 @@ rrc_eNB_ue_context_stmsi_exist( m_tmsiP, mme_codeP, ue_context_p, ue_context_p->ue_context.rnti); - if (ue_context_p->ue_context.Initialue_identity_s_TMSI.presence == TRUE) { + if (ue_context_p->ue_context.Initialue_identity_s_TMSI.presence == true) { printf("=> S-TMSI %x, MME %x\n", ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi, ue_context_p->ue_context.Initialue_identity_s_TMSI.mme_code); @@ -986,7 +986,7 @@ void remove_UE_from_freelist(module_id_t mod_id, rnti_t rnti) { pthread_mutex_unlock(&lock_ue_freelist); } -void put_UE_in_freelist(module_id_t mod_id, rnti_t rnti, boolean_t removeFlag) { +void put_UE_in_freelist(module_id_t mod_id, rnti_t rnti, bool removeFlag) { UE_free_list_t *free_list = NULL; eNB_MAC_INST *eNB_MAC = RC.mac[mod_id]; pthread_mutex_lock(&lock_ue_freelist); @@ -1013,7 +1013,7 @@ void release_UE_in_freeList(module_id_t mod_id) { PHY_VARS_eNB *eNB_PHY = NULL; struct rrc_eNB_ue_context_s *ue_context_pP = NULL; eNB_MAC_INST *eNB_MAC = RC.mac[mod_id]; - boolean_t remove_UEContext; + bool remove_UEContext; rnti_t rnti; int head, tail, ue_num; pthread_mutex_lock(&lock_ue_freelist); @@ -1678,7 +1678,7 @@ rrc_eNB_process_RRCConnectionReestablishmentComplete( ue_context_pP->ue_context.rnti = ctxt_pP->rnti; if (EPC_MODE_ENABLED) { - uint8_t send_security_mode_command = FALSE; + uint8_t send_security_mode_command = false; rrc_pdcp_config_security( ctxt_pP, ue_context_pP, @@ -2332,7 +2332,7 @@ rrc_eNB_generate_dedicatedRRCConnectionReconfiguration(const protocol_ctxt_t *co // PDCP PDCP_rlc_AM = CALLOC(1, sizeof(*PDCP_rlc_AM)); DRB_pdcp_config->rlc_AM = PDCP_rlc_AM; - PDCP_rlc_AM->statusReportRequired = FALSE; + PDCP_rlc_AM->statusReportRequired = false; break; default : @@ -2590,7 +2590,7 @@ rrc_eNB_modify_dedicatedRRCConnectionReconfiguration(const protocol_ctxt_t *cons PDCP_rlc_AM = CALLOC(1, sizeof(*PDCP_rlc_AM)); DRB_pdcp_config->rlc_AM = PDCP_rlc_AM; - PDCP_rlc_AM->statusReportRequired = FALSE; + PDCP_rlc_AM->statusReportRequired = false; break; default : @@ -2951,7 +2951,7 @@ void rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t #ifdef RRC_DEFAULT_RAB_IS_AM // EXMIMO_IOT PDCP_rlc_AM = CALLOC(1, sizeof(*PDCP_rlc_AM)); DRB_pdcp_config->rlc_AM = PDCP_rlc_AM; - PDCP_rlc_AM->statusReportRequired = FALSE; + PDCP_rlc_AM->statusReportRequired = false; #else PDCP_rlc_UM = CALLOC(1, sizeof(*PDCP_rlc_UM)); DRB_pdcp_config->rlc_UM = PDCP_rlc_UM; @@ -3347,7 +3347,7 @@ void rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.triggerType.choice.event.eventId.present = LTE_ReportConfigInterRAT__triggerType__event__eventId_PR_eventB1_NR_r15; ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.triggerType.choice.event.eventId.choice.eventB1_NR_r15.b1_ThresholdNR_r15.present = LTE_ThresholdNR_r15_PR_nr_RSRP_r15; ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.triggerType.choice.event.eventId.choice.eventB1_NR_r15.b1_ThresholdNR_r15.choice.nr_RSRP_r15 = 0; - ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.triggerType.choice.event.eventId.choice.eventB1_NR_r15.reportOnLeave_r15 = FALSE; + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.triggerType.choice.event.eventId.choice.eventB1_NR_r15.reportOnLeave_r15 = false; ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.triggerType.choice.event.hysteresis = 2; ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.triggerType.choice.event.timeToTrigger = LTE_TimeToTrigger_ms80; ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.maxReportCells = 4; @@ -3361,9 +3361,9 @@ void rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t if (ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.ext7->reportQuantityCellNR_r15 == NULL) exit(1); - ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.ext7->reportQuantityCellNR_r15->ss_rsrp = TRUE; - ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.ext7->reportQuantityCellNR_r15->ss_rsrq = TRUE; - ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.ext7->reportQuantityCellNR_r15->ss_sinr = TRUE; + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.ext7->reportQuantityCellNR_r15->ss_rsrp = true; + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.ext7->reportQuantityCellNR_r15->ss_rsrq = true; + ReportConfig_NR->reportConfig.choice.reportConfigInterRAT.ext7->reportQuantityCellNR_r15->ss_sinr = true; ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_NR); LOG_A(RRC, "Generating RRCCConnectionReconfigurationRequest (NRUE Measurement Report Request).\n"); } @@ -3714,7 +3714,7 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt #ifdef RRC_DEFAULT_RAB_IS_AM // EXMIMO_IOT PDCP_rlc_AM = CALLOC(1, sizeof(*PDCP_rlc_AM)); DRB_pdcp_config->rlc_AM = PDCP_rlc_AM; - PDCP_rlc_AM->statusReportRequired = FALSE; + PDCP_rlc_AM->statusReportRequired = 0; // FALSE #else PDCP_rlc_UM = CALLOC(1, sizeof(*PDCP_rlc_UM)); DRB_pdcp_config->rlc_UM = PDCP_rlc_UM; @@ -5052,7 +5052,7 @@ check_handovers( && ue_context_p->ue_context.handover_info != NULL && ue_context_p->ue_context.handover_info->forwarding_state == FORWARDING_NO_EMPTY ) { MessageDef *msg_p; - int result; + bool result; protocol_ctxt_t ctxt; do { @@ -5090,7 +5090,7 @@ check_handovers( GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).mode, NULL, NULL ); - if (result != TRUE) { + if (result != true) { LOG_E(RRC, "target enb send data forwarding buffer to PDCP request failed!\n"); } else { LOG_D(RRC, "target enb send data forwarding buffer to PDCP!\n"); @@ -5158,7 +5158,7 @@ check_handovers( GTPV1U_ENB_END_MARKER_IND (msg_p).mode, NULL, NULL ); - if (result != TRUE) { + if (result != true) { LOG_E(RRC, "target enb send spgw buffer to PDCP request failed!\n"); } else { LOG_D(RRC, "target enb send spgw buffer to PDCP!\n"); @@ -5390,7 +5390,7 @@ rrc_eNB_generate_HO_RRCConnectionReconfiguration(const protocol_ctxt_t *const ct #ifdef RRC_DEFAULT_RAB_IS_AM // EXMIMO_IOT PDCP_rlc_AM = CALLOC(1, sizeof(*PDCP_rlc_AM)); DRB_pdcp_config->rlc_AM = PDCP_rlc_AM; - PDCP_rlc_AM->statusReportRequired = FALSE; + PDCP_rlc_AM->statusReportRequired = 0; // FALSE #else PDCP_rlc_UM = CALLOC(1, sizeof(*PDCP_rlc_UM)); DRB_pdcp_config->rlc_UM = PDCP_rlc_UM; @@ -6280,10 +6280,7 @@ rrc_eNB_configure_rbs_handover(struct rrc_eNB_ue_context_s *ue_context_p, protoc ctxt_pP, ue_context_p, ue_context_p->ue_context.kenb); - rrc_pdcp_config_security( - ctxt_pP, - ue_context_p, - FALSE); + rrc_pdcp_config_security(ctxt_pP, ue_context_p, false); } // Add a new user (called during the HO procedure) @@ -6361,9 +6358,9 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete( UE_sched_ctrl_t *UE_scheduling_control = &(RC.mac[module_id]->UE_info.UE_sched_ctrl[UE_id_mac]); - if (UE_scheduling_control->cdrx_waiting_ack == TRUE) { - UE_scheduling_control->cdrx_waiting_ack = FALSE; - UE_scheduling_control->cdrx_configured = TRUE; // Set to TRUE when RRC Connection Reconfiguration is received + if (UE_scheduling_control->cdrx_waiting_ack == true) { + UE_scheduling_control->cdrx_waiting_ack = false; + UE_scheduling_control->cdrx_configured = true; // Set to TRUE when RRC Connection Reconfiguration is received LOG_I(RRC, "CDRX configuration activated after RRC Connection Reconfiguration Complete reception\n"); } } @@ -6627,7 +6624,7 @@ rrc_eNB_generate_RRCConnectionSetup( ) //----------------------------------------------------------------------------- { - boolean_t is_mtc = ctxt_pP->brOption; + bool is_mtc = ctxt_pP->brOption; LTE_LogicalChannelConfig_t *SRB1_logicalChannelConfig; //,*SRB2_logicalChannelConfig; LTE_SRB_ToAddModList_t **SRB_configList; LTE_SRB_ToAddMod_t *SRB1_config; @@ -7284,7 +7281,7 @@ rrc_eNB_decode_ccch( LOG_E(RRC, "%s:%d:%s: rrc_eNB_get_next_free_ue_context returned NULL\n", __FILE__, __LINE__, __FUNCTION__); if (ue_context_p != NULL) { - ue_context_p->ue_context.Initialue_identity_s_TMSI.presence = TRUE; + ue_context_p->ue_context.Initialue_identity_s_TMSI.presence = true; ue_context_p->ue_context.Initialue_identity_s_TMSI.mme_code = mme_code; ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi = m_tmsi; } else { @@ -8766,7 +8763,7 @@ void rrc_subframe_process(protocol_ctxt_t *const ctxt_pP, const int CC_id) { if ((ctxt_pP->frame&127) == 0 && ctxt_pP->subframe ==0) { if (fd) { - if (ue_context_p->ue_context.Initialue_identity_s_TMSI.presence == TRUE) { + if (ue_context_p->ue_context.Initialue_identity_s_TMSI.presence == true) { fprintf(fd,"RRC UE rnti %x: S-TMSI %x failure timer %d/8\n", ue_context_p->ue_context.rnti, ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi, diff --git a/openair2/RRC/LTE/rrc_eNB_GTPV1U.c b/openair2/RRC/LTE/rrc_eNB_GTPV1U.c index 575a38ee3d..64b5594dd9 100644 --- a/openair2/RRC/LTE/rrc_eNB_GTPV1U.c +++ b/openair2/RRC/LTE/rrc_eNB_GTPV1U.c @@ -84,23 +84,20 @@ rrc_eNB_process_GTPV1U_CREATE_TUNNEL_RESP( } //------------------------------------------------------------------------------ -boolean_t -gtpv_data_req( - const protocol_ctxt_t* const ctxt_pP, - const rb_id_t rb_idP, - const mui_t muiP, - const confirm_t confirmP, - const sdu_size_t sdu_sizeP, - uint8_t* const buffer_pP, - const pdcp_transmission_mode_t modeP, - uint32_t task_id -) +bool gtpv_data_req(const protocol_ctxt_t* const ctxt_pP, + const rb_id_t rb_idP, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_sizeP, + uint8_t* const buffer_pP, + const pdcp_transmission_mode_t modeP, + uint32_t task_id) //------------------------------------------------------------------------------ { if(sdu_sizeP == 0) { LOG_I(GTPU,"gtpv_data_req sdu_sizeP == 0"); - return FALSE; + return false; } LOG_D(GTPU,"gtpv_data_req ue rnti %x sdu_sizeP %d rb id %ld", ctxt_pP->rnti, sdu_sizeP, rb_idP); MessageDef *message_p; @@ -129,7 +126,7 @@ gtpv_data_req( GTPV1U_ENB_DATA_FORWARDING_IND (message_p).eNB_index = ctxt_pP->eNB_index; itti_send_msg_to_task (TASK_DATA_FORWARDING, ctxt_pP->instance, message_p); - return TRUE; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway. + return true; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway. } else if (task_id == TASK_END_MARKER){ LOG_I(GTPU,"gtpv_data_req task_id = TASK_END_MARKER\n"); @@ -152,23 +149,22 @@ gtpv_data_req( GTPV1U_ENB_END_MARKER_IND (message_p).eNB_index = ctxt_pP->eNB_index; itti_send_msg_to_task (TASK_END_MARKER, ctxt_pP->instance, message_p); - return TRUE; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway. + return true; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway. } LOG_E(RRC, "Impossible state\n"); - return FALSE; + return false; } -boolean_t gtpv_data_req_new ( - protocol_ctxt_t *ctxt, - const srb_flag_t srb_flagP, - const rb_id_t rb_idP, - const mui_t muiP, - const confirm_t confirmP, - const sdu_size_t sdu_buffer_sizeP, - unsigned char *const sdu_buffer_pP, - const pdcp_transmission_mode_t modeP, - const uint32_t *sourceL2Id, - const uint32_t *destinationL2Id) { +bool gtpv_data_req_new(protocol_ctxt_t *ctxt, + const srb_flag_t srb_flagP, + const rb_id_t rb_idP, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_buffer_sizeP, + unsigned char *const sdu_buffer_pP, + const pdcp_transmission_mode_t modeP, + const uint32_t *sourceL2Id, + const uint32_t *destinationL2Id) { int task; if (sdu_buffer_sizeP==0) diff --git a/openair2/RRC/LTE/rrc_eNB_GTPV1U.h b/openair2/RRC/LTE/rrc_eNB_GTPV1U.h index ab789099ca..f991cbd5f6 100644 --- a/openair2/RRC/LTE/rrc_eNB_GTPV1U.h +++ b/openair2/RRC/LTE/rrc_eNB_GTPV1U.h @@ -60,16 +60,13 @@ void rrc_eNB_send_GTPV1U_ENB_DELETE_TUNNEL_REQ( rrc_eNB_ue_context_t* ue_context_pP ); -boolean_t -gtpv_data_req( - const protocol_ctxt_t* const ctxt_pP, - const rb_id_t rb_idP, - const mui_t muiP, - const confirm_t confirmP, - const sdu_size_t sdu_sizeP, - uint8_t* const buffer_pP, - const pdcp_transmission_mode_t modeP, - uint32_t task_id -); +bool gtpv_data_req(const protocol_ctxt_t* const ctxt_pP, + const rb_id_t rb_idP, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_sizeP, + uint8_t* const buffer_pP, + const pdcp_transmission_mode_t modeP, + uint32_t task_id); #endif /* RRC_ENB_GTPV1U_H_ */ diff --git a/openair2/RRC/LTE/rrc_eNB_S1AP.c b/openair2/RRC/LTE/rrc_eNB_S1AP.c index f24c9ab1b6..aefbc01831 100644 --- a/openair2/RRC/LTE/rrc_eNB_S1AP.c +++ b/openair2/RRC/LTE/rrc_eNB_S1AP.c @@ -402,15 +402,13 @@ static e_LTE_SecurityAlgorithmConfig__integrityProtAlgorithm rrc_eNB_select_inte *\param mod_id Instance ID of eNB. *\param ue_index Instance ID of UE in the eNB. *\param security_capabilities The security capabilities received from S1AP. - *\return TRUE if at least one algorithm has been changed else FALSE. + *\return true if at least one algorithm has been changed else false. */ int -rrc_eNB_process_security( - const protocol_ctxt_t *const ctxt_pP, - rrc_eNB_ue_context_t *const ue_context_pP, - security_capabilities_t *security_capabilities_pP -) { - boolean_t changed = FALSE; +rrc_eNB_process_security(const protocol_ctxt_t *const ctxt_pP, + rrc_eNB_ue_context_t *const ue_context_pP, + security_capabilities_t *security_capabilities_pP) { + bool changed = false; LTE_CipheringAlgorithm_r12_t cipheringAlgorithm; e_LTE_SecurityAlgorithmConfig__integrityProtAlgorithm integrityProtAlgorithm; /* Save security parameters */ @@ -428,14 +426,14 @@ rrc_eNB_process_security( if (ue_context_pP->ue_context.ciphering_algorithm != cipheringAlgorithm) { ue_context_pP->ue_context.ciphering_algorithm = cipheringAlgorithm; - changed = TRUE; + changed = true; } integrityProtAlgorithm = rrc_eNB_select_integrity (ue_context_pP->ue_context.security_capabilities.integrity_algorithms); if (ue_context_pP->ue_context.integrity_algorithm != integrityProtAlgorithm) { ue_context_pP->ue_context.integrity_algorithm = integrityProtAlgorithm; - changed = TRUE; + changed = true; } LOG_I (RRC, "[eNB %d][UE %x] Selected security algorithms (%p): %lx, %x, %s\n", @@ -532,7 +530,7 @@ rrc_pdcp_config_security( pdcp_p, DCCH, DCCH+2, - (send_security_mode_command == TRUE) ? + (send_security_mode_command == true) ? 0 | (ue_context_pP->ue_context.integrity_algorithm << 4) : (ue_context_pP->ue_context.ciphering_algorithm ) | (ue_context_pP->ue_context.integrity_algorithm << 4), @@ -960,12 +958,12 @@ int rrc_eNB_process_S1AP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, const char ue_context_p, S1AP_INITIAL_CONTEXT_SETUP_REQ(msg_p).security_key); { - uint8_t send_security_mode_command = TRUE; + uint8_t send_security_mode_command = true; #ifndef EXMIMO_IOT if ((ue_context_p->ue_context.ciphering_algorithm == SecurityAlgorithmConfig__cipheringAlgorithm_eea0) && (ue_context_p->ue_context.integrity_algorithm == INTEGRITY_ALGORITHM_NONE)) { - send_security_mode_command = FALSE; + send_security_mode_command = false; } #endif @@ -978,7 +976,7 @@ int rrc_eNB_process_S1AP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, const char rrc_eNB_generate_SecurityModeCommand ( &ctxt, ue_context_p); - send_security_mode_command = FALSE; + send_security_mode_command = false; // apply ciphering after RRC security command mode rrc_pdcp_config_security( &ctxt, @@ -1414,19 +1412,19 @@ int rrc_eNB_process_S1AP_E_RAB_MODIFY_REQ(MessageDef *msg_p, const char *msg_nam /* Save e RAB information for later */ { int j; - boolean_t is_treated[S1AP_MAX_E_RAB] = {FALSE}; + bool is_treated[S1AP_MAX_E_RAB] = {false}; uint8_t nb_of_failed_e_rabs = 0; // keep the previous bearer // the index for the rec for (i = 0; i < S1AP_E_RAB_MODIFY_REQ (msg_p).nb_e_rabs_tomodify; i++) { - if (is_treated[i] == TRUE) { + if (is_treated[i] == true) { // already treated continue; } for (j = i+1; j < S1AP_E_RAB_MODIFY_REQ (msg_p).nb_e_rabs_tomodify; j++) { - if (is_treated[j] == FALSE && + if (is_treated[j] == false && S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[j].e_rab_id == S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].e_rab_id) { // handle multiple E-RAB ID ue_context_p->ue_context.modify_e_rab[j].status = E_RAB_STATUS_NEW; @@ -1434,12 +1432,12 @@ int rrc_eNB_process_S1AP_E_RAB_MODIFY_REQ(MessageDef *msg_p, const char *msg_nam ue_context_p->ue_context.modify_e_rab[j].cause = S1AP_CAUSE_RADIO_NETWORK; ue_context_p->ue_context.modify_e_rab[j].cause_value = 31;//S1ap_CauseRadioNetwork_multiple_E_RAB_ID_instances; nb_of_failed_e_rabs++; - is_treated[i] = TRUE; - is_treated[j] = TRUE; + is_treated[i] = true; + is_treated[j] = true; } } - if (is_treated[i] == TRUE) { + if (is_treated[i] == true) { // handle multiple E-RAB ID ue_context_p->ue_context.modify_e_rab[i].status = E_RAB_STATUS_NEW; ue_context_p->ue_context.modify_e_rab[i].param.e_rab_id = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].e_rab_id; @@ -1456,7 +1454,7 @@ int rrc_eNB_process_S1AP_E_RAB_MODIFY_REQ(MessageDef *msg_p, const char *msg_nam ue_context_p->ue_context.modify_e_rab[i].cause = S1AP_CAUSE_NAS; ue_context_p->ue_context.modify_e_rab[i].cause_value = 3;//S1ap_CauseNas_unspecified; nb_of_failed_e_rabs++; - is_treated[i] = TRUE; + is_treated[i] = true; continue; } @@ -1474,19 +1472,19 @@ int rrc_eNB_process_S1AP_E_RAB_MODIFY_REQ(MessageDef *msg_p, const char *msg_nam ue_context_p->ue_context.modify_e_rab[i].param.nas_pdu.buffer = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].nas_pdu.buffer; ue_context_p->ue_context.modify_e_rab[i].param.sgw_addr = ue_context_p->ue_context.e_rab[j].param.sgw_addr; ue_context_p->ue_context.modify_e_rab[i].param.gtp_teid = ue_context_p->ue_context.e_rab[j].param.gtp_teid; - is_treated[i] = TRUE; + is_treated[i] = true; break; } } - if (is_treated[i] == FALSE) { + if (is_treated[i] == false) { // handle Unknown E-RAB ID ue_context_p->ue_context.modify_e_rab[i].status = E_RAB_STATUS_NEW; ue_context_p->ue_context.modify_e_rab[i].param.e_rab_id = S1AP_E_RAB_MODIFY_REQ(msg_p).e_rab_modify_params[i].e_rab_id; ue_context_p->ue_context.modify_e_rab[i].cause = S1AP_CAUSE_RADIO_NETWORK; ue_context_p->ue_context.modify_e_rab[i].cause_value = 30;//S1ap_CauseRadioNetwork_unknown_E_RAB_ID; nb_of_failed_e_rabs++; - is_treated[i] = TRUE; + is_treated[i] = true; } } @@ -1824,8 +1822,8 @@ int rrc_eNB_process_PAGING_IND(MessageDef *msg_p, const char *msg_name, instance uint8_t i = 0; for (i = 0; i < MAX_MOBILES_PER_ENB; i++) { - if ((UE_PF_PO[CC_id][i].enable_flag == TRUE && UE_PF_PO[CC_id][i].ue_index_value == (uint16_t)(S1AP_PAGING_IND(msg_p).ue_index_value)) - || (UE_PF_PO[CC_id][i].enable_flag != TRUE)) { + if ((UE_PF_PO[CC_id][i].enable_flag == true && UE_PF_PO[CC_id][i].ue_index_value == (uint16_t)(S1AP_PAGING_IND(msg_p).ue_index_value)) + || (UE_PF_PO[CC_id][i].enable_flag != true)) { /* set T = min(Tc,Tue) */ UE_PF_PO[CC_id][i].T = T; /* set UE_ID */ @@ -1845,12 +1843,12 @@ int rrc_eNB_process_PAGING_IND(MessageDef *msg_p, const char *msg_name, instance UE_PF_PO[CC_id][i].PO = (frame_type==FDD) ? (4*(i_s&1)+(5*(i_s>>1))) : ((i_s&1)+(5*(i_s>>1))); } - if (UE_PF_PO[CC_id][i].enable_flag == TRUE) { + if (UE_PF_PO[CC_id][i].enable_flag == true) { //paging exist UE log LOG_D(RRC,"[eNB %ld] CC_id %d In S1AP_PAGING_IND: Update exist UE %d, T %d, PF %d, PO %d\n", instance, CC_id, UE_PF_PO[CC_id][i].ue_index_value, T, UE_PF_PO[CC_id][i].PF_min, UE_PF_PO[CC_id][i].PO); } else { /* set enable_flag */ - UE_PF_PO[CC_id][i].enable_flag = TRUE; + UE_PF_PO[CC_id][i].enable_flag = true; //paging new UE log LOG_D(RRC,"[eNB %ld] CC_id %d In S1AP_PAGING_IND: Insert a new UE %d, T %d, PF %d, PO %d\n", instance, CC_id, UE_PF_PO[CC_id][i].ue_index_value, T, UE_PF_PO[CC_id][i].PF_min, UE_PF_PO[CC_id][i].PO); } diff --git a/openair2/RRC/LTE/rrc_proto.h b/openair2/RRC/LTE/rrc_proto.h index f0456005f5..7bd3fbf758 100644 --- a/openair2/RRC/LTE/rrc_proto.h +++ b/openair2/RRC/LTE/rrc_proto.h @@ -457,7 +457,7 @@ mac_rrc_data_ind( const uint8_t *sduP, const sdu_size_t sdu_lenP, const uint8_t mbsfn_sync_areaP, - const boolean_t brOption + const bool brOption ); int8_t @@ -685,7 +685,7 @@ extern RRC_release_list_t rrc_release_info; extern pthread_mutex_t lock_ue_freelist; void remove_UE_from_freelist(module_id_t mod_id, rnti_t rnti); -void put_UE_in_freelist(module_id_t mod_id, rnti_t rnti, boolean_t removeFlag); +void put_UE_in_freelist(module_id_t mod_id, rnti_t rnti, bool removeFlag); void release_UE_in_freeList(module_id_t mod_id); /** @}*/ diff --git a/openair2/RRC/NR/L2_nr_interface.c b/openair2/RRC/NR/L2_nr_interface.c index 161d1cd847..6fc0566cbd 100644 --- a/openair2/RRC/NR/L2_nr_interface.c +++ b/openair2/RRC/NR/L2_nr_interface.c @@ -168,7 +168,7 @@ nr_rrc_data_req( { if(sdu_sizeP == 255) { LOG_D(RRC,"sdu_sizeP == 255"); - return FALSE; + return false; } MessageDef *message_p; @@ -204,7 +204,7 @@ nr_rrc_data_req( if (ctxt_pP->enb_flag && NODE_IS_CU(RC.nrrrc[ctxt_pP->module_id]->node_type)) pdcp_run(ctxt_pP); - return TRUE; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway. + return true; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway. } uint16_t mac_rrc_nr_data_req(const module_id_t Mod_idP, @@ -315,7 +315,7 @@ int8_t nr_mac_rrc_data_ind(const module_id_t module_idP, const rb_id_t srb_idP, const uint8_t *sduP, const sdu_size_t sdu_lenP, - const boolean_t brOption) { + const bool brOption) { if (NODE_IS_DU(RC.nrrrc[module_idP]->node_type)) { LOG_W(RRC,"[DU %d][RAPROC] Received SDU for CCCH on SRB %ld length %d for UE id %d RNTI %x \n", diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 3488080f27..1b322ed925 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -173,7 +173,7 @@ typedef struct UE_RRC_INFO_NR_s { } __attribute__ ((__packed__)) NR_UE_RRC_INFO; typedef struct UE_S_TMSI_NR_s { - boolean_t presence; + bool presence; uint16_t amf_set_id; uint8_t amf_pointer; uint32_t fiveg_tmsi; diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index d569b91aa8..dc6e14215f 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -174,18 +174,16 @@ int8_t nr_mac_rrc_bwp_switch_req(const module_id_t module_idP, const int dl_bwp_id, const int ul_bwp_id); -int8_t nr_mac_rrc_data_ind( - const module_id_t module_idP, - const int CC_id, - const frame_t frameP, - const sub_frame_t sub_frameP, - const int UE_id, - const rnti_t rntiP, - const rb_id_t srb_idP, - const uint8_t *sduP, - const sdu_size_t sdu_lenP, - const boolean_t brOption -); +int8_t nr_mac_rrc_data_ind(const module_id_t module_idP, + const int CC_id, + const frame_t frameP, + const sub_frame_t sub_frameP, + const int UE_id, + const rnti_t rntiP, + const rb_id_t srb_idP, + const uint8_t *sduP, + const sdu_size_t sdu_lenP, + const bool brOption); int nr_rrc_reconfiguration_req(rrc_gNB_ue_context_t *const ue_context_pP, protocol_ctxt_t *const ctxt_pP, @@ -219,16 +217,15 @@ rlc_op_status_t nr_rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt const LTE_PMCH_InfoList_r9_t * const pmch_InfoList_r9_pP, struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_bearer2add_list); -boolean_t nr_rrc_pdcp_config_asn1_req( - const protocol_ctxt_t *const ctxt_pP, - NR_SRB_ToAddModList_t *const srb2add_list, - NR_DRB_ToAddModList_t *const drb2add_list, - NR_DRB_ToReleaseList_t *const drb2release_list, - const uint8_t security_modeP, - uint8_t *const kRRCenc, - uint8_t *const kRRCint, - uint8_t *const kUPenc, - uint8_t *const kUPint - ,LTE_PMCH_InfoList_r9_t *pmch_InfoList_r9 - ,rb_id_t *const defaultDRB, - struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_bearer2add_list); +bool nr_rrc_pdcp_config_asn1_req(const protocol_ctxt_t *const ctxt_pP, + NR_SRB_ToAddModList_t *const srb2add_list, + NR_DRB_ToAddModList_t *const drb2add_list, + NR_DRB_ToReleaseList_t *const drb2release_list, + const uint8_t security_modeP, + uint8_t *const kRRCenc, + uint8_t *const kRRCint, + uint8_t *const kUPenc, + uint8_t *const kUPint, + LTE_PMCH_InfoList_r9_t *pmch_InfoList_r9, + rb_id_t *const defaultDRB, + struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_bearer2add_list); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 3d95081336..43082003df 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -116,16 +116,16 @@ uint8_t first_rrcreconfiguration = 0; ///---------------------------------------------------------------------------------------------------------------/// ///---------------------------------------------------------------------------------------------------------------/// -boolean_t DURecvCb( protocol_ctxt_t *ctxt_pP, - const srb_flag_t srb_flagP, - const rb_id_t rb_idP, - const mui_t muiP, - const confirm_t confirmP, - const sdu_size_t sdu_buffer_sizeP, - unsigned char *const sdu_buffer_pP, - const pdcp_transmission_mode_t modeP, - const uint32_t *sourceL2Id, - const uint32_t *destinationL2Id) { +bool DURecvCb(protocol_ctxt_t *ctxt_pP, + const srb_flag_t srb_flagP, + const rb_id_t rb_idP, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_buffer_sizeP, + unsigned char *const sdu_buffer_pP, + const pdcp_transmission_mode_t modeP, + const uint32_t *sourceL2Id, + const uint32_t *destinationL2Id) { // The buffer comes from the stack in gtp-u thread, we have a make a separate buffer to enqueue in a inter-thread message queue mem_block_t *sdu=get_free_mem_block(sdu_buffer_sizeP, __func__); memcpy(sdu->data, sdu_buffer_pP, sdu_buffer_sizeP); @@ -917,7 +917,7 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( sdap_config->sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_absent; sdap_config->sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_absent; } - sdap_config->defaultDRB = TRUE; + sdap_config->defaultDRB = true; sdap_config->mappedQoS_FlowsToAdd = calloc(1, sizeof(struct NR_SDAP_Config__mappedQoS_FlowsToAdd)); memset(sdap_config->mappedQoS_FlowsToAdd, 0, sizeof(struct NR_SDAP_Config__mappedQoS_FlowsToAdd)); @@ -1826,7 +1826,7 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete( ue_context_pP->ue_context.rnti = ctxt_pP->rnti; if (AMF_MODE_ENABLED) { - uint8_t send_security_mode_command = FALSE; + uint8_t send_security_mode_command = false; nr_rrc_pdcp_config_security( ctxt_pP, ue_context_pP, @@ -2113,7 +2113,7 @@ int nr_rrc_gNB_decode_ccch(protocol_ctxt_t *const ctxt_pP, } if (ue_context_p != NULL) { - ue_context_p->ue_context.Initialue_identity_5g_s_TMSI.presence = TRUE; + ue_context_p->ue_context.Initialue_identity_5g_s_TMSI.presence = true; ue_context_p->ue_context.ng_5G_S_TMSI_Part1 = s_tmsi_part1; } } @@ -2590,7 +2590,7 @@ rrc_gNB_decode_dcch( fiveg_s_TMSI, fiveg_s_TMSI >> 38, fiveg_s_TMSI >> 38, (fiveg_s_TMSI >> 32) & 0x3F, (fiveg_s_TMSI >> 32) & 0x3F, (uint32_t)fiveg_s_TMSI); - if (ue_context_p->ue_context.Initialue_identity_5g_s_TMSI.presence == TRUE) { + if (ue_context_p->ue_context.Initialue_identity_5g_s_TMSI.presence == true) { ue_context_p->ue_context.Initialue_identity_5g_s_TMSI.amf_set_id = fiveg_s_TMSI >> 38; ue_context_p->ue_context.Initialue_identity_5g_s_TMSI.amf_pointer = (fiveg_s_TMSI >> 32) & 0x3F; ue_context_p->ue_context.Initialue_identity_5g_s_TMSI.fiveg_tmsi = (uint32_t)fiveg_s_TMSI; @@ -3235,7 +3235,6 @@ static int rrc_process_DU_DL(MessageDef *msg_p, const char *msg_name, instance_ LOG_I(F1AP, "Received DL RRC Transfer on srb_id %ld\n", req->srb_id); // rlc_op_status_t rlc_status; - // boolean_t ret = TRUE; //LOG_I(F1AP, "PRRCContainer size %lu:", ie->value.choice.RRCContainer.size); //for (int i = 0; i < ie->value.choice.RRCContainer.size; i++) @@ -3260,23 +3259,23 @@ static int rrc_process_DU_DL(MessageDef *msg_p, const char *msg_name, instance_ // switch (rlc_status) { // case RLC_OP_STATUS_OK: // //LOG_I(F1AP, "Data sending request over RLC succeeded!\n"); - // ret=TRUE; + // ret=true; // break; // case RLC_OP_STATUS_BAD_PARAMETER: // LOG_W(F1AP, "Data sending request over RLC failed with 'Bad Parameter' reason!\n"); - // ret= FALSE; + // ret= false; // break; // case RLC_OP_STATUS_INTERNAL_ERROR: // LOG_W(F1AP, "Data sending request over RLC failed with 'Internal Error' reason!\n"); - // ret= FALSE; + // ret= false; // break; // case RLC_OP_STATUS_OUT_OF_RESSOURCES: // LOG_W(F1AP, "Data sending request over RLC failed with 'Out of Resources' reason!\n"); - // ret= FALSE; + // ret= false; // break; // default: // LOG_W(F1AP, "RLC returned an unknown status code after PDCP placed the order to send some data (Status Code:%d)\n", rlc_status); - // ret= FALSE; + // ret= false; // break; // } // switch case // return ret; @@ -3940,7 +3939,7 @@ void nr_rrc_subframe_process(protocol_ctxt_t *const ctxt_pP, const int CC_id) { gNB_MAC_INST *nrmac=RC.nrmac[ctxt_pP->module_id]; //WHAT A BEAUTIFULL RACE CONDITION !!! if (fd) { - if (ue_context_p->ue_context.Initialue_identity_5g_s_TMSI.presence == TRUE) { + if (ue_context_p->ue_context.Initialue_identity_5g_s_TMSI.presence == true) { fprintf(fd,"NR RRC UE rnti %x: S-TMSI %x failure timer %d/8\n", ue_context_p->ue_id_rnti, ue_context_p->ue_context.Initialue_identity_5g_s_TMSI.fiveg_tmsi, diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 0dcd064663..6663ddea85 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -708,7 +708,7 @@ rrc_gNB_process_security( rrc_gNB_ue_context_t *const ue_context_pP, ngap_security_capabilities_t *security_capabilities_pP ) { - boolean_t changed = FALSE; + bool changed = false; NR_CipheringAlgorithm_t cipheringAlgorithm; e_NR_IntegrityProtAlgorithm integrityProtAlgorithm; /* Save security parameters */ @@ -726,14 +726,14 @@ rrc_gNB_process_security( if (ue_context_pP->ue_context.ciphering_algorithm != cipheringAlgorithm) { ue_context_pP->ue_context.ciphering_algorithm = cipheringAlgorithm; - changed = TRUE; + changed = true; } integrityProtAlgorithm = rrc_gNB_select_integrity(ctxt_pP, ue_context_pP->ue_context.security_capabilities.nRintegrity_algorithms); if (ue_context_pP->ue_context.integrity_algorithm != integrityProtAlgorithm) { ue_context_pP->ue_context.integrity_algorithm = integrityProtAlgorithm; - changed = TRUE; + changed = true; } LOG_I (NR_RRC, "[gNB %d][UE %x] Selected security algorithms (%p): %lx, %x, %s\n", @@ -1126,17 +1126,17 @@ rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ( ue_context_p->ue_context.gNB_ue_ngap_id = gNB_ue_ngap_id; { int j; - boolean_t is_treated[NGAP_MAX_PDUSESSION] = {FALSE}; + bool is_treated[NGAP_MAX_PDUSESSION] = {false}; uint8_t nb_of_failed_pdusessions = 0; for (i = 0; i < nb_pdusessions_tomodify; i++) { - if (is_treated[i] == TRUE) { + if (is_treated[i] == true) { continue; } //Check if same PDU session ID to handle multiple pdu sessions for (j = i+1; j < nb_pdusessions_tomodify; j++) { - if (is_treated[j] == FALSE && + if (is_treated[j] == false && NGAP_PDUSESSION_MODIFY_REQ(msg_p).pdusession_modify_params[j].pdusession_id == NGAP_PDUSESSION_MODIFY_REQ(msg_p).pdusession_modify_params[i].pdusession_id) { // handle multiple pdu session id @@ -1147,12 +1147,12 @@ rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ( ue_context_p->ue_context.modify_pdusession[j].cause = NGAP_CAUSE_RADIO_NETWORK; ue_context_p->ue_context.modify_pdusession[j].cause_value = NGAP_CauseRadioNetwork_multiple_PDU_session_ID_instances; nb_of_failed_pdusessions++; - is_treated[i] = TRUE; - is_treated[j] = TRUE; + is_treated[i] = true; + is_treated[j] = true; } } // handle multiple pdu session id case - if (is_treated[i] == TRUE) { + if (is_treated[i] == true) { LOG_D(NR_RRC, "handle multiple pdu session id \n"); ue_context_p->ue_context.modify_pdusession[i].status = PDU_SESSION_STATUS_NEW; ue_context_p->ue_context.modify_pdusession[i].param.pdusession_id = @@ -1195,13 +1195,13 @@ rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ( ue_context_p->ue_context.modify_pdusession[i].param.gtp_teid = ue_context_p->ue_context.pduSession[j].param.gtp_teid; - is_treated[i] = TRUE; + is_treated[i] = true; break; } } // handle Unknown pdu session ID - if (is_treated[i] == FALSE) { + if (is_treated[i] == false) { LOG_D(NR_RRC, "handle Unknown pdu session ID \n"); ue_context_p->ue_context.modify_pdusession[i].status = PDU_SESSION_STATUS_NEW; ue_context_p->ue_context.modify_pdusession[i].param.pdusession_id = @@ -1209,7 +1209,7 @@ rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ( ue_context_p->ue_context.modify_pdusession[i].cause = NGAP_CAUSE_RADIO_NETWORK; ue_context_p->ue_context.modify_pdusession[i].cause_value = NGAP_CauseRadioNetwork_unknown_PDU_session_ID; nb_of_failed_pdusessions++; - is_treated[i] = TRUE; + is_treated[i] = true; } } diff --git a/openair2/RRC/NR_UE/L2_interface_ue.c b/openair2/RRC/NR_UE/L2_interface_ue.c index 6f0c7fc27f..b4508e2627 100644 --- a/openair2/RRC/NR_UE/L2_interface_ue.c +++ b/openair2/RRC/NR_UE/L2_interface_ue.c @@ -181,6 +181,6 @@ rrc_data_req_nr_ue( TASK_PDCP_UE, ctxt_pP->instance, message_p); - return TRUE; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway. + return true; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway. } diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 50ec32772d..078f7f51a1 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -2014,7 +2014,7 @@ nr_rrc_ue_establish_srb2( int i, cnt; if( radioBearerConfig->srb3_ToRelease != NULL){ - if( *radioBearerConfig->srb3_ToRelease == TRUE){ + if( *radioBearerConfig->srb3_ToRelease == true){ //TODO (release the PDCP entity and the srb-Identity of the SRB3.) } } diff --git a/openair2/SDAP/nr_sdap/nr_sdap.c b/openair2/SDAP/nr_sdap/nr_sdap.c index 74ef93aff7..dd7a76920d 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.c +++ b/openair2/SDAP/nr_sdap/nr_sdap.c @@ -21,19 +21,19 @@ #include "nr_sdap.h" -boolean_t sdap_data_req(protocol_ctxt_t *ctxt_p, - const srb_flag_t srb_flag, - const rb_id_t rb_id, - const mui_t mui, - const confirm_t confirm, - const sdu_size_t sdu_buffer_size, - unsigned char *const sdu_buffer, - const pdcp_transmission_mode_t pt_mode, - const uint32_t *sourceL2Id, - const uint32_t *destinationL2Id, - const uint8_t qfi, - const boolean_t rqi, - const int pdusession_id) { +bool sdap_data_req(protocol_ctxt_t *ctxt_p, + const srb_flag_t srb_flag, + const rb_id_t rb_id, + const mui_t mui, + const confirm_t confirm, + const sdu_size_t sdu_buffer_size, + unsigned char *const sdu_buffer, + const pdcp_transmission_mode_t pt_mode, + const uint32_t *sourceL2Id, + const uint32_t *destinationL2Id, + const uint8_t qfi, + const bool rqi, + const int pdusession_id) { nr_sdap_entity_t *sdap_entity; sdap_entity = nr_sdap_get_entity(ctxt_p->rnti, pdusession_id); @@ -42,19 +42,19 @@ boolean_t sdap_data_req(protocol_ctxt_t *ctxt_p, return 0; } - boolean_t ret = sdap_entity->tx_entity(sdap_entity, - ctxt_p, - srb_flag, - rb_id, - mui, - confirm, - sdu_buffer_size, - sdu_buffer, - pt_mode, - sourceL2Id, - destinationL2Id, - qfi, - rqi); + bool ret = sdap_entity->tx_entity(sdap_entity, + ctxt_p, + srb_flag, + rb_id, + mui, + confirm, + sdu_buffer_size, + sdu_buffer, + pt_mode, + sourceL2Id, + destinationL2Id, + qfi, + rqi); return ret; } diff --git a/openair2/SDAP/nr_sdap/nr_sdap.h b/openair2/SDAP/nr_sdap/nr_sdap.h index cd702cfd7f..5959ca1558 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.h +++ b/openair2/SDAP/nr_sdap/nr_sdap.h @@ -32,20 +32,19 @@ * Downlink - gNB * Uplink - nrUE */ -boolean_t sdap_data_req(protocol_ctxt_t *ctxt_p, - const srb_flag_t srb_flag, - const rb_id_t rb_id, - const mui_t mui, - const confirm_t confirm, - const sdu_size_t sdu_buffer_size, - unsigned char *const sdu_buffer, - const pdcp_transmission_mode_t pt_mode, - const uint32_t *sourceL2Id, - const uint32_t *destinationL2Id, - const uint8_t qfi, - const boolean_t rqi, - const int pdusession_id - ); +bool sdap_data_req(protocol_ctxt_t *ctxt_p, + const srb_flag_t srb_flag, + const rb_id_t rb_id, + const mui_t mui, + const confirm_t confirm, + const sdu_size_t sdu_buffer_size, + unsigned char *const sdu_buffer, + const pdcp_transmission_mode_t pt_mode, + const uint32_t *sourceL2Id, + const uint32_t *destinationL2Id, + const uint8_t qfi, + const bool rqi, + const int pdusession_id); /* * TS 37.324 4.4 Functions diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 79532748d2..5e3627296c 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -46,23 +46,22 @@ void nr_pdcp_submit_sdap_ctrl_pdu(int rnti, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_u return; } -static boolean_t nr_sdap_tx_entity(nr_sdap_entity_t *entity, - protocol_ctxt_t *ctxt_p, - const srb_flag_t srb_flag, - const rb_id_t rb_id, - const mui_t mui, - const confirm_t confirm, - const sdu_size_t sdu_buffer_size, - unsigned char *const sdu_buffer, - const pdcp_transmission_mode_t pt_mode, - const uint32_t *sourceL2Id, - const uint32_t *destinationL2Id, - const uint8_t qfi, - const boolean_t rqi - ) { +static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, + protocol_ctxt_t *ctxt_p, + const srb_flag_t srb_flag, + const rb_id_t rb_id, + const mui_t mui, + const confirm_t confirm, + const sdu_size_t sdu_buffer_size, + unsigned char *const sdu_buffer, + const pdcp_transmission_mode_t pt_mode, + const uint32_t *sourceL2Id, + const uint32_t *destinationL2Id, + const uint8_t qfi, + const bool rqi) { /* The offset of the SDAP header, it might be 0 if the has_sdap is not true in the pdcp entity. */ int offset=0; - boolean_t ret=false; + bool ret = false; /*Hardcode DRB ID given from upper layer (ue/enb_tun_read_thread rb_id), it will change if we have SDAP*/ rb_id_t sdap_drb_id = rb_id; int pdcp_ent_has_sdap = 0; @@ -297,7 +296,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity, } } -void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, uint8_t qfi, rb_id_t drb, boolean_t hasSdap){ +void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, uint8_t qfi, rb_id_t drb, bool hasSdap) { if(qfi < SDAP_MAX_QFI && qfi > SDAP_MAP_RULE_EMPTY && drb > 0 && @@ -390,7 +389,7 @@ void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *existing_sdap_entity, nr_sdap_entity_t *new_nr_sdap_entity(int has_sdap, uint16_t rnti, int pdusession_id, - boolean_t is_defaultDRB, + bool is_defaultDRB, uint8_t drb_identity, NR_QFI_t *mapped_qfi_2_add, uint8_t mappedQFIs2AddCount) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index b46e5bf4e3..635289d4d4 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -64,7 +64,7 @@ typedef struct nr_sdap_ul_hdr_s { typedef struct qfi2drb_s { rb_id_t drb_id; - boolean_t hasSdap; + bool hasSdap; } qfi2drb_t; void nr_pdcp_submit_sdap_ctrl_pdu(int rnti, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu); @@ -75,7 +75,7 @@ typedef struct nr_sdap_entity_s { int pdusession_id; qfi2drb_t qfi2drb_table[SDAP_MAX_QFI]; - void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, uint8_t qfi, rb_id_t drb, boolean_t hasSdap); + void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, uint8_t qfi, rb_id_t drb, bool hasSdap); void (*qfi2drb_map_delete)(struct nr_sdap_entity_s *entity, uint8_t qfi); rb_id_t (*qfi2drb_map)(struct nr_sdap_entity_s *entity, uint8_t qfi, rb_id_t upper_layer_rb_id); @@ -84,20 +84,19 @@ typedef struct nr_sdap_entity_s { void (*sdap_submit_ctrl_pdu)(int rnti, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu); - boolean_t (*tx_entity)(struct nr_sdap_entity_s *entity, - protocol_ctxt_t *ctxt_p, - const srb_flag_t srb_flag, - const rb_id_t rb_id, - const mui_t mui, - const confirm_t confirm, - const sdu_size_t sdu_buffer_size, - unsigned char *const sdu_buffer, - const pdcp_transmission_mode_t pt_mode, - const uint32_t *sourceL2Id, - const uint32_t *destinationL2Id, - const uint8_t qfi, - const boolean_t rqi - ); + bool (*tx_entity)(struct nr_sdap_entity_s *entity, + protocol_ctxt_t *ctxt_p, + const srb_flag_t srb_flag, + const rb_id_t rb_id, + const mui_t mui, + const confirm_t confirm, + const sdu_size_t sdu_buffer_size, + unsigned char *const sdu_buffer, + const pdcp_transmission_mode_t pt_mode, + const uint32_t *sourceL2Id, + const uint32_t *destinationL2Id, + const uint8_t qfi, + const bool rqi); void (*rx_entity)(struct nr_sdap_entity_s *entity, rb_id_t pdcp_entity, @@ -114,7 +113,7 @@ typedef struct nr_sdap_entity_s { } nr_sdap_entity_t; /* QFI to DRB Mapping Related Function */ -void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, uint8_t qfi, rb_id_t drb, boolean_t hasSdap); +void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, uint8_t qfi, rb_id_t drb, bool hasSdap); /* QFI to DRB Mapping Related Function */ void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, uint8_t qfi); @@ -168,7 +167,7 @@ void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *existing_sdap_entity, nr_sdap_entity_t *new_nr_sdap_entity(int has_sdap, uint16_t rnti, int pdusession_id, - boolean_t is_defaultDRB, + bool is_defaultDRB, uint8_t default_DRB, NR_QFI_t *mapped_qfi_2_add, uint8_t mappedQFIs2AddCount); diff --git a/openair2/X2AP/x2ap_common.h b/openair2/X2AP/x2ap_common.h index a2f903a737..7dd88ffa21 100644 --- a/openair2/X2AP/x2ap_common.h +++ b/openair2/X2AP/x2ap_common.h @@ -52,11 +52,6 @@ # define X2AP_PORT 36422 #endif -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - extern int asn1_xer_print; #if defined(ENB_MODE) diff --git a/openair3/M3AP/m3ap_common.h b/openair3/M3AP/m3ap_common.h index 7f68510314..c5f55bc70a 100644 --- a/openair3/M3AP/m3ap_common.h +++ b/openair3/M3AP/m3ap_common.h @@ -52,11 +52,6 @@ # define M3AP_PORT 36444 #endif -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - extern int asn1_xer_print; #if defined(ENB_MODE) diff --git a/openair3/NAS/COMMON/UTIL/nas_timer.c b/openair3/NAS/COMMON/UTIL/nas_timer.c index 8448d9a78c..b67a3bc232 100644 --- a/openair3/NAS/COMMON/UTIL/nas_timer.c +++ b/openair3/NAS/COMMON/UTIL/nas_timer.c @@ -121,7 +121,7 @@ static nas_timer_database_t _nas_timer_db = { static void _nas_timer_db_init(void); static int _nas_timer_db_get_id(void); -static int _nas_timer_db_is_active(int id); +static bool _nas_timer_db_is_active(int id); static nas_timer_entry_t *_nas_timer_db_create_entry(long sec, nas_timer_callback_t cb, void *args); static void _nas_timer_db_delete_entry(int id); @@ -130,7 +130,7 @@ static void _nas_timer_db_insert_entry(int id, nas_timer_entry_t *te); static int _nas_timer_db_insert(timer_queue_t *entry); static nas_timer_entry_t *_nas_timer_db_remove_entry(int id); -static int _nas_timer_db_remove(timer_queue_t *entry); +static bool _nas_timer_db_remove(timer_queue_t *entry); /* * ----------------------------------------------------------------------------- @@ -408,12 +408,12 @@ static int _nas_timer_db_get_id(void) ** Others: _nas_timer_db ** ** ** ** Outputs: None ** - ** Return: TRUE if the timer entry is active; FALSE ** + ** Return: true if the timer entry is active; false ** ** if it is not an active timer entry. ** ** Others: None ** ** ** ***************************************************************************/ -static int _nas_timer_db_is_active(int id) +static bool _nas_timer_db_is_active(int id) { return ( (id != NAS_TIMER_INACTIVE_ID) && (_nas_timer_db.tq[id].id != NAS_TIMER_INACTIVE_ID) ); @@ -562,11 +562,11 @@ static int _nas_timer_db_insert(timer_queue_t *entry) } else { /* The new entry is the first entry of the list */ _nas_timer_db.head = entry; - return TRUE; + return true; } /* The new entry is NOT the first entry of the list */ - return FALSE; + return false; } /**************************************************************************** @@ -588,7 +588,7 @@ static int _nas_timer_db_insert(timer_queue_t *entry) ***************************************************************************/ static nas_timer_entry_t *_nas_timer_db_remove_entry(int id) { - int restart; + bool restart; /* The identifier of the timer is valid within the timer queue */ assert(_nas_timer_db.tq[id].id == id); @@ -622,7 +622,7 @@ static nas_timer_entry_t *_nas_timer_db_remove_entry(int id) return (_nas_timer_db.tq[id].entry); } -static int _nas_timer_db_remove(timer_queue_t *entry) +static bool _nas_timer_db_remove(timer_queue_t *entry) { /* Update the pointer from the previous entry */ /* prev ---> entry ---> next */ @@ -644,12 +644,12 @@ static int _nas_timer_db_remove(timer_queue_t *entry) if (_nas_timer_db.head != NULL) { /* Other timers are scheduled to expire */ - return TRUE; + return true; } } /* The entry was NOT the first entry of the list */ - return FALSE; + return false; } /* diff --git a/openair3/NAS/COMMON/UTIL/socket.c b/openair3/NAS/COMMON/UTIL/socket.c index 53a6ec8823..20c071203d 100644 --- a/openair3/NAS/COMMON/UTIL/socket.c +++ b/openair3/NAS/COMMON/UTIL/socket.c @@ -397,7 +397,7 @@ static int _socket_set_option(int sfd) * and it will simply open another socket on the same port and * continue listening. */ - optval = TRUE; + optval = true; if (setsockopt (sfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) { return RETURNerror; @@ -405,12 +405,12 @@ static int _socket_set_option(int sfd) /* IPV6_V6ONLY socket option * ------------------------- - * When option is set to TRUE, the socket is restricted to sending and + * When option is set to true, the socket is restricted to sending and * receiving IPv6 packets only. - * When option is set to FALSE, the socket can be used to send and receive + * When option is set to false, the socket can be used to send and receive * packets to and from an IPv6 address or an IPv4-mapped IPv6 address. */ - optval = FALSE; + optval = false; if (setsockopt (sfd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)) < 0) { return RETURNerror; diff --git a/openair3/NAS/COMMON/UTIL/stty.c b/openair3/NAS/COMMON/UTIL/stty.c index eceb0b06b1..fe87a63e44 100644 --- a/openair3/NAS/COMMON/UTIL/stty.c +++ b/openair3/NAS/COMMON/UTIL/stty.c @@ -192,7 +192,7 @@ static sttyset_t stty_params[] = { { NULL, 0, 0, 0 } }; -static int _stty_set_this(struct termios *term, const sttyset_t *p, int turnon); +static int _stty_set_this(struct termios *term, const sttyset_t *p, bool turnon); /****************************************************************************/ /****************** E X P O R T E D F U N C T I O N S ******************/ @@ -207,7 +207,7 @@ static int _stty_set_this(struct termios *term, const sttyset_t *p, int turnon); ** ** ** Inputs: p: The TTY parameters ** ** turnon: Indicate whether the parameter should be ** - ** turned on (TRUE) or turned off (FALSE) ** + ** turned on (true) or turned off (false) ** ** Others: None ** ** ** ** Outputs: term: The termios structure to fill ** @@ -223,7 +223,7 @@ int stty_set(int fd, const char *params) register char *s; struct termios term; register int i; - int mode; + bool mode; /* Get current tty attributes */ if ( tcgetattr(fd, &term) < 0 ) { @@ -234,10 +234,10 @@ int stty_set(int fd, const char *params) p = strtok(s," \t\n"); while (p && (rc != RETURNerror)) { - mode = 1; + mode = true; if ( *p == '-' ) { - mode = 0; + mode = false; p++; } @@ -275,7 +275,7 @@ int stty_set(int fd, const char *params) ** ** ** Inputs: p: The TTY parameters ** ** turnon: Indicate whether the parameter should be ** - ** turned on (TRUE) or turned off (FALSE) ** + ** turned on (true) or turned off (false) ** ** Others: None ** ** ** ** Outputs: term: The termios structure to fill ** @@ -283,7 +283,7 @@ int stty_set(int fd, const char *params) ** Others: None ** ** ** ***************************************************************************/ -static int _stty_set_this(struct termios *term, const sttyset_t *p, int turnon) +static int _stty_set_this(struct termios *term, const sttyset_t *p, bool turnon) { int rc = RETURNok; diff --git a/openair3/NAS/TEST/AS_SIMULATOR/as_simulator.c b/openair3/NAS/TEST/AS_SIMULATOR/as_simulator.c index bbc37d18a3..387c3de3a8 100644 --- a/openair3/NAS/TEST/AS_SIMULATOR/as_simulator.c +++ b/openair3/NAS/TEST/AS_SIMULATOR/as_simulator.c @@ -120,12 +120,12 @@ static socket_id_t * _as_simulator_mme_sid = NULL; /* * UE NAS process connection manager's running indicator */ -static int _as_simulator_ue_is_running = FALSE; +static bool _as_simulator_ue_is_running = false; /* * MME NAS process connection manager's running indicator */ -static int _as_simulator_mme_is_running = FALSE; +static bool _as_simulator_mme_is_running = false; static int _set_signal_handler(int signal, void (handler)(int)); static void _signal_handler(int signal_number); @@ -307,8 +307,8 @@ static void _signal_handler(int signal_number) { printf("\nWARNING\t: %s - Signal %d received\n", __FUNCTION__, signal_number); - _as_simulator_ue_is_running = FALSE; - _as_simulator_mme_is_running = FALSE; + _as_simulator_ue_is_running = false; + _as_simulator_mme_is_running = false; } /* @@ -321,7 +321,7 @@ static void* _as_simulator_ue_mngr(void* args) int msg_id; as_message_t msg; - _as_simulator_ue_is_running = TRUE; + _as_simulator_ue_is_running = true; printf("INFO\t: %s - UE connection manager started\n", __FUNCTION__); @@ -388,7 +388,7 @@ static void* _as_simulator_ue_mngr(void* args) } /* Close the connection to the network sublayer */ - _as_simulator_ue_is_running = FALSE; + _as_simulator_ue_is_running = false; printf("ERROR\t: The UE connection manager exited\n"); return (NULL); } @@ -403,7 +403,7 @@ static void* _as_simulator_mme_mngr(void* args) int msg_id; as_message_t msg; - _as_simulator_mme_is_running = TRUE; + _as_simulator_mme_is_running = true; printf("INFO\t: %s - MME connection manager started\n", __FUNCTION__); @@ -469,7 +469,7 @@ static void* _as_simulator_mme_mngr(void* args) } /* Close the connection to the network sublayer */ - _as_simulator_mme_is_running = FALSE; + _as_simulator_mme_is_running = false; printf("ERROR\t: %s - The MME connection manager exited\n", __FUNCTION__); return (NULL); } diff --git a/openair3/NAS/TEST/NETWORK/network_simulator.c b/openair3/NAS/TEST/NETWORK/network_simulator.c index 461f701f95..492a709463 100644 --- a/openair3/NAS/TEST/NETWORK/network_simulator.c +++ b/openair3/NAS/TEST/NETWORK/network_simulator.c @@ -208,7 +208,7 @@ static const OctetString* _network_simulator_pdn[NETWORK_IP_MAX][2] = { static int _set_signal_handler(int signal, void (handler)(int)); static void _signal_handler(int signal_number); static int _process_message(int msgID, const as_message_t* req); -static int _assign_pdn_address(int ue_pdn_type, int is_initial, int* pdn_type, OctetString* pdn); +static int _assign_pdn_address(int ue_pdn_type, bool is_initial, int* pdn_type, OctetString* pdn); /* Functions used to process messages received from the Access Stratum */ static int _process_cell_info_req(const cell_info_req_t* req, cell_info_cnf_t* rsp); @@ -283,7 +283,7 @@ int main (int argc, const char* argv[]) /* * Network simulator main loop */ - while (TRUE) { + while (true) { as_message_t msg; /* Receive message from the NAS */ @@ -1072,11 +1072,11 @@ static int _process_pdn_connectivity_request(const pdn_connectivity_request_msg* /* Assign PDN address */ if (apn.length > 0) { request->accesspointname.accesspointnamevalue = apn; - esm_cause = _assign_pdn_address(requested_pdn_type, FALSE, &pdn_type, + esm_cause = _assign_pdn_address(requested_pdn_type, false, &pdn_type, &request->pdnaddress.pdnaddressinformation); } else { request->accesspointname.accesspointnamevalue = EURECOM_APN; - esm_cause = _assign_pdn_address(requested_pdn_type, TRUE, &pdn_type, + esm_cause = _assign_pdn_address(requested_pdn_type, true, &pdn_type, &request->pdnaddress.pdnaddressinformation); } diff --git a/openair3/NAS/TEST/USER/user_simulator.c b/openair3/NAS/TEST/USER/user_simulator.c index 1c429c3b85..3050c16692 100644 --- a/openair3/NAS/TEST/USER/user_simulator.c +++ b/openair3/NAS/TEST/USER/user_simulator.c @@ -192,7 +192,7 @@ int main (int argc, const char* argv[]) /* * User simulator main loop */ - while (TRUE) { + while (true) { char c; int len; @@ -293,7 +293,7 @@ static void _signal_handler(int signal_number) */ static void* _receive_thread(void* arg) { - while (TRUE) { + while (true) { /* Receive AT response from the NAS sublayer */ int rbytes = USER_RECV(_user_simulator_recv_buffer, USER_SIMULATOR_BUFFER_SIZE); diff --git a/openair3/NAS/UE/API/USER/at_command.c b/openair3/NAS/UE/API/USER/at_command.c index ab85b2d2fa..a6591c6748 100644 --- a/openair3/NAS/UE/API/USER/at_command.c +++ b/openair3/NAS/UE/API/USER/at_command.c @@ -354,7 +354,7 @@ static int ParseString(char * at_str, at_command_t* at_command) char* terminal_character_index = NULL; int num_of_chars_to_compare = -1; int handler_index; - int handler_found = FALSE; + bool handler_found = false; int check_for_carriage_return_index = 0; /* @@ -415,7 +415,7 @@ static int ParseString(char * at_str, at_command_t* at_command) if (strncasecmp(at_str, _at_command_handler[handler_index].command, num_of_chars_to_compare) != 0) continue; - handler_found = TRUE; + handler_found = true; break; } @@ -681,7 +681,7 @@ static unsigned int NumberOfParameters(const unsigned char* str) ** Others: None ** ** ** ** Outputs: None ** - ** Return: TRUE, FALSE ** + ** Return: true, false ** ** Others: None ** ** ** ***************************************************************************/ @@ -689,11 +689,11 @@ static unsigned int IsNumeric(const char* str, size_t len) { while (len-- > 0) { if (!isdigit(str[len])) { - return FALSE; + return false; } } - return TRUE; + return true; } /****************************************************************************/ @@ -719,7 +719,7 @@ static int parse_e1(const char* string, int position, at_command_t* at_command) static int parse_q0(const char* string, int position, at_command_t* at_command) { /* Result code suppression Q0 */ - at_error_code_suppression_q1 = FALSE; + at_error_code_suppression_q1 = false; at_command->id = 0; at_command->mask = AT_COMMAND_NO_PARAM; return at_command->id; @@ -728,7 +728,7 @@ static int parse_q0(const char* string, int position, at_command_t* at_command) static int parse_q1(const char* string, int position, at_command_t* at_command) { /* Result code suppression Q1 */ - at_error_code_suppression_q1 = TRUE; + at_error_code_suppression_q1 = true; at_command->id = 0; at_command->mask = AT_COMMAND_NO_PARAM; return at_command->id; @@ -738,7 +738,7 @@ static int parse_v0(const char* string, int position, at_command_t* at_command) { /* Response format V0 (numeric result code + limited header) */ at_error_format = AT_ERROR_NUMERIC; - at_response_format_v1 = FALSE; + at_response_format_v1 = false; at_command->id = 0; at_command->mask = AT_COMMAND_NO_PARAM; return at_command->id; @@ -748,7 +748,7 @@ static int parse_v1(const char* string, int position, at_command_t* at_command) { /* Response format V1 (verbose result code + full header) */ at_error_format = AT_ERROR_VERBOSE; - at_response_format_v1 = TRUE; + at_response_format_v1 = true; at_command->id = 0; at_command->mask = AT_COMMAND_NO_PARAM; return at_command->id; diff --git a/openair3/NAS/UE/API/USER/at_error.c b/openair3/NAS/UE/API/USER/at_error.c index d004c89736..bad7127adc 100644 --- a/openair3/NAS/UE/API/USER/at_error.c +++ b/openair3/NAS/UE/API/USER/at_error.c @@ -55,10 +55,10 @@ extern int at_response_format_v1; /* * Result code suppression indicator (set by ATQ0 and ATQ1) * ------------------------------------------------------- - * FALSE - Result codes are transmitted to the user application - * TRUE - Result codes are suppressed and not transmitted + * false - Result codes are transmitted to the user application + * true - Result codes are suppressed and not transmitted */ -int at_error_code_suppression_q1 = FALSE; +bool at_error_code_suppression_q1 = false; /* * Verbose mode indicator (set by ATV0, ATV1 and AT+CMEE) diff --git a/openair3/NAS/UE/API/USER/at_response.c b/openair3/NAS/UE/API/USER/at_response.c index 859db90d7e..eef0385750 100644 --- a/openair3/NAS/UE/API/USER/at_response.c +++ b/openair3/NAS/UE/API/USER/at_response.c @@ -52,10 +52,10 @@ Description Defines structure of the AT command response returned after /* * Response format indicator (set by ATV0 and ATV1) * ----------------------------------------------- - * TRUE - , - * FALSE - , + * true - , + * false - , */ -int at_response_format_v1 = TRUE; +bool at_response_format_v1 = true; /****************************************************************************/ /******************* L O C A L D E F I N I T I O N S *******************/ diff --git a/openair3/NAS/UE/EMM/Attach.c b/openair3/NAS/UE/EMM/Attach.c index 5e7a1f578b..52f7ebce44 100644 --- a/openair3/NAS/UE/EMM/Attach.c +++ b/openair3/NAS/UE/EMM/Attach.c @@ -146,7 +146,7 @@ int emm_proc_attach(nas_user_t *user, emm_proc_attach_type_t type) /* Update the emergency bearer service indicator */ if (type == EMM_ATTACH_TYPE_EMERGENCY) { - user->emm_data->is_emergency = TRUE; + user->emm_data->is_emergency = true; } /* Setup initial NAS information message to transfer */ @@ -211,7 +211,7 @@ int emm_proc_attach(nas_user_t *user, emm_proc_attach_type_t type) } /* Setup EPS NAS security data */ - emm_as_set_security_data(&emm_as->sctx, user->emm_data->security, FALSE, FALSE); + emm_as_set_security_data(&emm_as->sctx, user->emm_data->security, false, false); emm_as->ksi = EMM_AS_NO_KEY_AVAILABLE; if (user->emm_data->security) { @@ -230,8 +230,8 @@ int emm_proc_attach(nas_user_t *user, emm_proc_attach_type_t type) * is requested to setup a default EPS bearer */ esm_sap.primitive = ESM_PDN_CONNECTIVITY_REQ; - esm_sap.is_standalone = FALSE; - esm_sap.data.pdn_connect.is_defined = TRUE; + esm_sap.is_standalone = false; + esm_sap.data.pdn_connect.is_defined = true; esm_sap.data.pdn_connect.cid = 1; /* TODO: PDN type should be set according to the IP capability of the UE */ esm_sap.data.pdn_connect.pdn_type = NET_PDN_TYPE_IPV4; @@ -387,7 +387,7 @@ int emm_proc_attach_accept(nas_user_t *user, long t3412, long t3402, long t3423, if (n_eplmns > 0) { for (i = 0; (i < n_eplmns) && (i < EMM_DATA_EPLMN_MAX); i++) { - int is_forbidden = FALSE; + bool is_forbidden = false; if (!user->emm_data->is_emergency) { /* If the attach procedure is not for emergency bearer @@ -395,7 +395,7 @@ int emm_proc_attach_accept(nas_user_t *user, long t3412, long t3402, long t3423, * code that is already in the list of forbidden PLMNs */ for (j = 0; j < user->emm_data->fplmn.n_plmns; j++) { if (PLMNS_ARE_EQUAL(eplmn[i], user->emm_data->fplmn.plmn[j])) { - is_forbidden = TRUE; + is_forbidden = true; break; } } @@ -418,7 +418,7 @@ int emm_proc_attach_accept(nas_user_t *user, long t3412, long t3402, long t3423, * Notify ESM that a default EPS bearer has to be activated */ esm_sap.primitive = ESM_DEFAULT_EPS_BEARER_CONTEXT_ACTIVATE_REQ; - esm_sap.is_standalone = FALSE; + esm_sap.is_standalone = false; esm_sap.recv = esm_msg_pP; rc = esm_sap_send(user, &esm_sap); @@ -445,7 +445,7 @@ int emm_proc_attach_accept(nas_user_t *user, long t3412, long t3402, long t3423, emm_sap.u.emm_as.u.data.ueid = user->ueid; /* Setup EPS NAS security data */ emm_as_set_security_data(&emm_sap.u.emm_as.u.data.sctx, - user->emm_data->security, FALSE, TRUE); + user->emm_data->security, false, true); /* Get the activate default EPS bearer context accept message * to be transfered within the ESM container of the attach * complete message */ @@ -546,7 +546,7 @@ int emm_proc_attach_reject(nas_user_t *user, int emm_cause, const OctetString *e case EMM_CAUSE_EPS_NOT_ALLOWED: case EMM_CAUSE_BOTH_NOT_ALLOWED: /* Consider the USIM as invalid for EPS services */ - user->emm_data->usim_is_valid = FALSE; + user->emm_data->usim_is_valid = false; /* Delete the list of equivalent PLMNs */ user->emm_data->nvdata.eplmn.n_plmns = 0; break; @@ -682,7 +682,7 @@ int emm_proc_attach_reject(nas_user_t *user, int emm_cause, const OctetString *e if (esm_msg_pP != NULL) { esm_sap_t esm_sap; esm_sap.primitive = ESM_PDN_CONNECTIVITY_REJ; - esm_sap.is_standalone = FALSE; + esm_sap.is_standalone = false; esm_sap.recv = esm_msg_pP; rc = esm_sap_send(user, &esm_sap); } @@ -731,7 +731,7 @@ int emm_proc_attach_complete(void *args) /* Set the EPS update status to EU1 UPDATED */ user->emm_data->status = EU1_UPDATED; - user->emm_data->is_attached = TRUE; + user->emm_data->is_attached = true; /* * Notify EMM that network attach complete message has been delivered @@ -747,7 +747,7 @@ int emm_proc_attach_complete(void *args) * Complete message */ esm_sap.primitive = ESM_DEFAULT_EPS_BEARER_CONTEXT_ACTIVATE_CNF; - esm_sap.is_standalone = FALSE; + esm_sap.is_standalone = false; rc = esm_sap_send(user, &esm_sap); } @@ -766,7 +766,7 @@ int emm_proc_attach_complete(void *args) ** The UE shall restart the attach procedure when timer ** ** T3411 expires. ** ** ** - ** Inputs: is_initial: TRUE if the NAS message that failed to be ** + ** Inputs: is_initial: true if the NAS message that failed to be ** ** transfered is an initial NAS message (ESM ** ** message embedded within an Attach Request ** ** message) ** @@ -778,7 +778,7 @@ int emm_proc_attach_complete(void *args) ** Others: T3410, T3411 ** ** ** ***************************************************************************/ -int emm_proc_attach_failure(int is_initial, void *args) +int emm_proc_attach_failure(bool is_initial, void *args) { LOG_FUNC_IN; int rc = RETURNok; @@ -804,7 +804,7 @@ int emm_proc_attach_failure(int is_initial, void *args) * to be transmitted */ esm_sap.primitive = ESM_PDN_CONNECTIVITY_REJ; - esm_sap.is_standalone = FALSE; + esm_sap.is_standalone = false; esm_sap.recv = NULL; } else { /* @@ -813,7 +813,7 @@ int emm_proc_attach_failure(int is_initial, void *args) * has failed to be transmitted */ esm_sap.primitive = ESM_DEFAULT_EPS_BEARER_CONTEXT_ACTIVATE_REJ; - esm_sap.is_standalone = FALSE; + esm_sap.is_standalone = false; esm_sap.recv = NULL; } @@ -919,7 +919,7 @@ int emm_proc_attach_set_emergency(emm_data_t *emm_data) LOG_TRACE(WARNING, "EMM-PROC - UE is now attached to the network for " "emergency bearer services only"); - emm_data->is_emergency = TRUE; + emm_data->is_emergency = true; LOG_FUNC_RETURN(RETURNok); } @@ -950,7 +950,7 @@ int emm_proc_attach_set_detach(void *nas_user) "EMM-PROC - UE is now locally detached from the network"); /* Reset the network attachment indicator */ - user->emm_data->is_attached = FALSE; + user->emm_data->is_attached = false; /* * Notify that the UE is locally detached from the network */ diff --git a/openair3/NAS/UE/EMM/Authentication.c b/openair3/NAS/UE/EMM/Authentication.c index a2762d08e8..a3b58f89f4 100644 --- a/openair3/NAS/UE/EMM/Authentication.c +++ b/openair3/NAS/UE/EMM/Authentication.c @@ -129,7 +129,7 @@ static int _authentication_kasme(const OctetString *autn, ** authentication challenge data and respond with an AUTHEN- ** ** TICATION RESPONSE message to the network. ** ** ** - ** Inputs: native_ksi: TRUE if the security context is of type ** + ** Inputs: native_ksi: true if the security context is of type ** ** native (for KSIASME) ** ** ksi: The NAS ket sey identifier ** ** rand: Authentication parameter RAND ** @@ -179,14 +179,14 @@ int emm_proc_authentication_request(nas_user_t *user, int native_ksi, int ksi, OctetString res = {AUTH_RES_SIZE, authentication_data->res}; if ((memcmp(authentication_data->rand, rand->value, AUTH_CK_SIZE) != 0) || - (authentication_data->auth_process_started == FALSE)) { + (authentication_data->auth_process_started == false)) { /* * There is no valid stored RAND in the ME or the stored RAND is * different from the new received value in the AUTHENTICATION * REQUEST message OR if this is first time UE starting the * Authentication process */ - authentication_data->auth_process_started = TRUE; + authentication_data->auth_process_started = true; OctetString auts; auts.length = 0; auts.value = (uint8_t *)malloc(AUTH_AUTS_SIZE); @@ -308,7 +308,7 @@ int emm_proc_authentication_request(nas_user_t *user, int native_ksi, int ksi, emm_sap.u.emm_as.u.security.res = &res; /* Setup EPS NAS security data */ emm_as_set_security_data(&emm_sap.u.emm_as.u.security.sctx, - user->emm_data->security, FALSE, TRUE); + user->emm_data->security, false, true); rc = emm_sap_send(user, &emm_sap); if (rc != RETURNerror) { @@ -398,7 +398,7 @@ int emm_proc_authentication_reject(nas_user_t *user) } /* Consider the USIM invalid */ - user->emm_data->usim_is_valid = FALSE; + user->emm_data->usim_is_valid = false; /* Stop timer T3410 */ if (emm_timers->T3410.id != NAS_TIMER_INACTIVE_ID) { @@ -652,7 +652,7 @@ static int _authentication_abnormal_cases_cde(nas_user_t *user, int emm_cause, emm_sap.u.emm_as.u.security.auts = auts; /* Setup EPS NAS security data */ emm_as_set_security_data(&emm_sap.u.emm_as.u.security.sctx, - user->emm_data->security, FALSE, TRUE); + user->emm_data->security, false, true); rc = emm_sap_send(user, &emm_sap); if (rc != RETURNerror) { diff --git a/openair3/NAS/UE/EMM/Detach.c b/openair3/NAS/UE/EMM/Detach.c index b61bcdc14d..654486226e 100644 --- a/openair3/NAS/UE/EMM/Detach.c +++ b/openair3/NAS/UE/EMM/Detach.c @@ -114,7 +114,7 @@ static int _emm_detach_abort(nas_user_t *user, emm_proc_detach_type_t type); ** Return: RETURNok, RETURNerror ** ** ** ***************************************************************************/ -int emm_proc_detach(nas_user_t *user, emm_proc_detach_type_t type, int switch_off) +int emm_proc_detach(nas_user_t *user, emm_proc_detach_type_t type, bool switch_off) { LOG_FUNC_IN; @@ -154,7 +154,7 @@ int emm_proc_detach(nas_user_t *user, emm_proc_detach_type_t type, int switch_of emm_as->guti = user->emm_data->guti; emm_as->ueid = user->ueid; /* Setup EPS NAS security data */ - emm_as_set_security_data(&emm_as->sctx, user->emm_data->security, FALSE, TRUE); + emm_as_set_security_data(&emm_as->sctx, user->emm_data->security, false, true); /* * Notify EMM-AS SAP that Detach Request message has to @@ -280,7 +280,7 @@ int emm_proc_detach_accept(void* args) ** Others: None ** ** ** ***************************************************************************/ -int emm_proc_detach_failure(int is_initial, void *args) +int emm_proc_detach_failure(bool is_initial, void *args) { LOG_FUNC_IN; @@ -405,8 +405,7 @@ void *emm_detach_t3421_handler(void *args) emm_as->guti = user->emm_data->guti; emm_as->ueid = user->ueid; /* Setup EPS NAS security data */ - emm_as_set_security_data(&emm_as->sctx, user->emm_data->security, - FALSE, TRUE); + emm_as_set_security_data(&emm_as->sctx, user->emm_data->security, false, true); /* * Notify EMM-AS SAP that Detach Request message has to diff --git a/openair3/NAS/UE/EMM/EmmStatusHdl.c b/openair3/NAS/UE/EMM/EmmStatusHdl.c index 367d0327f4..9ac2fc794b 100644 --- a/openair3/NAS/UE/EMM/EmmStatusHdl.c +++ b/openair3/NAS/UE/EMM/EmmStatusHdl.c @@ -137,8 +137,7 @@ int emm_proc_status(nas_user_t *user, int emm_cause) emm_sap.u.emm_as.u.status.guti = user->emm_data->guti; sctx = user->emm_data->security; /* Setup EPS NAS security data */ - emm_as_set_security_data(&emm_sap.u.emm_as.u.status.sctx, sctx, - FALSE, TRUE); + emm_as_set_security_data(&emm_sap.u.emm_as.u.status.sctx, sctx, false, true); rc = emm_sap_send(user, &emm_sap); diff --git a/openair3/NAS/UE/EMM/Identification.c b/openair3/NAS/UE/EMM/Identification.c index 0364c6d22f..d4fc85a931 100644 --- a/openair3/NAS/UE/EMM/Identification.c +++ b/openair3/NAS/UE/EMM/Identification.c @@ -199,8 +199,7 @@ int emm_proc_identification_request(nas_user_t *user, emm_proc_identity_type_t t emm_sap.u.emm_as.u.security.ueid = user->ueid; emm_sap.u.emm_as.u.security.msgType = EMM_AS_MSG_TYPE_IDENT; /* Setup EPS NAS security data */ - emm_as_set_security_data(&emm_sap.u.emm_as.u.security.sctx, - user->emm_data->security, FALSE, TRUE); + emm_as_set_security_data(&emm_sap.u.emm_as.u.security.sctx, user->emm_data->security, false, true); rc = emm_sap_send(user, &emm_sap); LOG_FUNC_RETURN (rc); diff --git a/openair3/NAS/UE/EMM/IdleMode.c b/openair3/NAS/UE/EMM/IdleMode.c index 362d5e5b4a..50a318355c 100644 --- a/openair3/NAS/UE/EMM/IdleMode.c +++ b/openair3/NAS/UE/EMM/IdleMode.c @@ -663,8 +663,8 @@ int emm_proc_plmn_selection(nas_user_t *user, int index) ** to camp on an acceptable cell, irrespective of its PLMN ** ** identity, so that only emergency calls can be made. ** ** ** - ** Inputs: found: TRUE if a suitable cell of the chosen ** - ** PLMN has been found; FALSE otherwise. ** + ** Inputs: found: true if a suitable cell of the chosen ** + ** PLMN has been found; false otherwise. ** ** tac: The code of the location/tracking area the ** ** chosen PLMN belongs to ** ** ci: The identifier of the cell ** @@ -685,7 +685,7 @@ int emm_proc_plmn_selection_end(nas_user_t *user, int found, tac_t tac, ci_t ci, emm_plmn_list_t *emm_plmn_list = user->emm_plmn_list; user_api_id_t *user_api_id = user->user_api_id; int index = emm_plmn_list->index; - int select_next_plmn = FALSE; + bool select_next_plmn = false; LOG_TRACE(INFO, "EMM-IDLE - %s cell found for PLMN %d in %s mode", (found)? "One" : "No", index, @@ -694,7 +694,7 @@ int emm_proc_plmn_selection_end(nas_user_t *user, int found, tac_t tac, ci_t ci, "Automatic/manual"); if (found) { - int is_forbidden = FALSE; + bool is_forbidden = false; /* Select the PLMN of which a suitable cell has been found */ emm_data->splmn = *emm_plmn_list->plmn[index]; @@ -721,7 +721,7 @@ int emm_proc_plmn_selection_end(nas_user_t *user, int found, tac_t tac, ci_t ci, /* Check if the selected PLMN is in the forbidden list */ for (i = 0; i < emm_data->fplmn.n_plmns; i++) { if (PLMNS_ARE_EQUAL(emm_data->splmn, emm_data->fplmn.plmn[i])) { - is_forbidden = TRUE; + is_forbidden = true; break; } } @@ -730,7 +730,7 @@ int emm_proc_plmn_selection_end(nas_user_t *user, int found, tac_t tac, ci_t ci, for (i = 0; i < emm_data->fplmn_gprs.n_plmns; i++) { if (PLMNS_ARE_EQUAL(emm_data->splmn, emm_data->fplmn_gprs.plmn[i])) { - is_forbidden = TRUE; + is_forbidden = true; break; } } @@ -745,7 +745,7 @@ int emm_proc_plmn_selection_end(nas_user_t *user, int found, tac_t tac, ci_t ci, if (!is_forbidden) { for (i = 0; i < emm_data->ftai.n_tais; i++) { if (TAIS_ARE_EQUAL(tai, emm_data->ftai.tai[i])) { - is_forbidden = TRUE; + is_forbidden = true; break; } } @@ -754,7 +754,7 @@ int emm_proc_plmn_selection_end(nas_user_t *user, int found, tac_t tac, ci_t ci, if (!is_forbidden) { for (i = 0; i < emm_data->ftai_roaming.n_tais; i++) { if (TAIS_ARE_EQUAL(tai, emm_data->ftai_roaming.tai[i])) { - is_forbidden = TRUE; + is_forbidden = true; break; } } @@ -793,7 +793,7 @@ int emm_proc_plmn_selection_end(nas_user_t *user, int found, tac_t tac, ci_t ci, * Try to select the next PLMN in the ordered list of available PLMNs */ index += 1; - select_next_plmn = TRUE; + select_next_plmn = true; /* Bypass the previously selected PLMN */ if (index == emm_plmn_list->splmn) { @@ -809,7 +809,7 @@ int emm_proc_plmn_selection_end(nas_user_t *user, int found, tac_t tac, ci_t ci, * registered or equivalent PLMNs is ongoing */ index += 1; - select_next_plmn = TRUE; + select_next_plmn = true; } else if (emm_data->plmn_mode == EMM_DATA_PLMN_MANUAL) { @@ -830,7 +830,7 @@ int emm_proc_plmn_selection_end(nas_user_t *user, int found, tac_t tac, ci_t ci, */ emm_data->plmn_mode = EMM_DATA_PLMN_AUTO; index = emm_plmn_list->hplmn; - select_next_plmn = TRUE; + select_next_plmn = true; } /* @@ -851,7 +851,7 @@ int emm_proc_plmn_selection_end(nas_user_t *user, int found, tac_t tac, ci_t ci, } else { /* No suitable cell of any PLMN within the ordered list * of available PLMNs has been found */ - select_next_plmn = FALSE; + select_next_plmn = false; emm_sap.primitive = EMMREG_NO_CELL; } } @@ -892,11 +892,11 @@ int emm_proc_plmn_selection_end(nas_user_t *user, int found, tac_t tac, ci_t ci, if (emm_plmn_list->splmn == emm_plmn_list->rplmn) { /* The selected PLMN is the registered PLMN */ LOG_TRACE(INFO, "EMM-IDLE - The selected PLMN is the registered PLMN"); - emm_data->is_rplmn = TRUE; + emm_data->is_rplmn = true; } else if (emm_plmn_list->splmn < emm_plmn_list->hplmn) { /* The selected PLMN is in the list of equivalent PLMNs */ LOG_TRACE(INFO, "EMM-IDLE - The selected PLMN is in the list of equivalent PLMNs"); - emm_data->is_eplmn = TRUE; + emm_data->is_eplmn = true; } /* diff --git a/openair3/NAS/UE/EMM/LowerLayer.c b/openair3/NAS/UE/EMM/LowerLayer.c index 01b07fc356..538ba21099 100644 --- a/openair3/NAS/UE/EMM/LowerLayer.c +++ b/openair3/NAS/UE/EMM/LowerLayer.c @@ -208,7 +208,7 @@ int lowerlayer_data_ind(nas_user_t *user, const OctetString *data) LOG_FUNC_IN; esm_sap.primitive = ESM_UNITDATA_IND; - esm_sap.is_standalone = TRUE; + esm_sap.is_standalone = true; esm_sap.ueid = user->ueid; esm_sap.recv = data; @@ -250,7 +250,7 @@ int lowerlayer_data_req(nas_user_t *user, const OctetString *data) emm_sap.u.emm_as.u.data.NASmsg.length = data->length; emm_sap.u.emm_as.u.data.NASmsg.value = data->value; /* Setup EPS NAS security data */ - emm_as_set_security_data(&emm_sap.u.emm_as.u.data.sctx, sctx, FALSE, TRUE); + emm_as_set_security_data(&emm_sap.u.emm_as.u.data.sctx, sctx, false, true); rc = emm_sap_send(user, &emm_sap); LOG_FUNC_RETURN (rc); @@ -336,7 +336,7 @@ int emm_proc_lowerlayer_success(lowerlayer_data_t *lowerlayer_data) ** Description: Handles EMM procedure to be executed upon receiving noti- ** ** fication that data failed to be delivered to the network. ** ** ** - ** Inputs: is_initial: TRUE if the NAS message that failed to be ** + ** Inputs: is_initial: true if the NAS message that failed to be ** ** transfered is an initial NAS message ** ** Others: None ** ** ** @@ -345,7 +345,7 @@ int emm_proc_lowerlayer_success(lowerlayer_data_t *lowerlayer_data) ** Others: None ** ** ** ***************************************************************************/ -int emm_proc_lowerlayer_failure(lowerlayer_data_t *lowerlayer_data, int is_initial) +int emm_proc_lowerlayer_failure(lowerlayer_data_t *lowerlayer_data, bool is_initial) { LOG_FUNC_IN; diff --git a/openair3/NAS/UE/EMM/LowerLayer.h b/openair3/NAS/UE/EMM/LowerLayer.h index 0d8eefc7f3..ed60e379bc 100644 --- a/openair3/NAS/UE/EMM/LowerLayer.h +++ b/openair3/NAS/UE/EMM/LowerLayer.h @@ -72,7 +72,7 @@ int emm_proc_lowerlayer_initialize(lowerlayer_data_t *lowerlayer_data, lowerlaye lowerlayer_release_callback_t release, void *args); int emm_proc_lowerlayer_success(lowerlayer_data_t *lowerlayer_data); -int emm_proc_lowerlayer_failure(lowerlayer_data_t *lowerlayer_data, int is_initial); +int emm_proc_lowerlayer_failure(lowerlayer_data_t *lowerlayer_data, bool is_initial); int emm_proc_lowerlayer_release(lowerlayer_data_t *lowerlayer_data); diff --git a/openair3/NAS/UE/EMM/LowerLayer_defs.h b/openair3/NAS/UE/EMM/LowerLayer_defs.h index 6035d4ed12..1a0ae7d656 100644 --- a/openair3/NAS/UE/EMM/LowerLayer_defs.h +++ b/openair3/NAS/UE/EMM/LowerLayer_defs.h @@ -11,7 +11,7 @@ typedef int (*lowerlayer_success_callback_t)(void *); * Type of EMM procedure callback function executed when data are not * delivered to the network because a lower layer failure occurred */ -typedef int (*lowerlayer_failure_callback_t)(int, void *); +typedef int (*lowerlayer_failure_callback_t)(bool, void *); /* * Type of EMM procedure callback function executed when NAS signalling diff --git a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredAttemptingToAttach.c b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredAttemptingToAttach.c index f58cf4b9e0..3fa47094c7 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredAttemptingToAttach.c +++ b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredAttemptingToAttach.c @@ -120,7 +120,7 @@ int EmmDeregisteredAttemptingToAttach(nas_user_t *user, const emm_reg_t *evt) /* * Data failed to be delivered to the network */ - rc = emm_proc_lowerlayer_failure(user->lowerlayer_data, FALSE); + rc = emm_proc_lowerlayer_failure(user->lowerlayer_data, false); break; default: diff --git a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredLimitedService.c b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredLimitedService.c index 4310f963cd..c0763009b8 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredLimitedService.c +++ b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredLimitedService.c @@ -133,7 +133,7 @@ int EmmDeregisteredLimitedService(nas_user_t *user, const emm_reg_t *evt) /* * Initial NAS message failed to be delivered to the network */ - rc = emm_proc_lowerlayer_failure(user->lowerlayer_data, TRUE); + rc = emm_proc_lowerlayer_failure(user->lowerlayer_data, true); break; case _EMMREG_LOWERLAYER_RELEASE: diff --git a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNormalService.c b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNormalService.c index f77c2921a3..0925cb4e0f 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNormalService.c +++ b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNormalService.c @@ -141,7 +141,7 @@ int EmmDeregisteredNormalService(nas_user_t *user, const emm_reg_t *evt) /* * Initial NAS message failed to be delivered to the network */ - rc = emm_proc_lowerlayer_failure(user->lowerlayer_data, TRUE); + rc = emm_proc_lowerlayer_failure(user->lowerlayer_data, true); break; case _EMMREG_LOWERLAYER_RELEASE: diff --git a/openair3/NAS/UE/EMM/SAP/EmmRegistered.c b/openair3/NAS/UE/EMM/SAP/EmmRegistered.c index fbd3e1ce63..2cd25f77d6 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmRegistered.c +++ b/openair3/NAS/UE/EMM/SAP/EmmRegistered.c @@ -143,7 +143,7 @@ int EmmRegistered(nas_user_t *user, const emm_reg_t *evt) /* * Data transfer message failed to be delivered */ - rc = emm_proc_lowerlayer_failure(user->lowerlayer_data, FALSE); + rc = emm_proc_lowerlayer_failure(user->lowerlayer_data, false); break; case _EMMREG_LOWERLAYER_RELEASE: diff --git a/openair3/NAS/UE/EMM/SAP/EmmRegisteredInitiated.c b/openair3/NAS/UE/EMM/SAP/EmmRegisteredInitiated.c index 36929fc4d7..a770e08bab 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmRegisteredInitiated.c +++ b/openair3/NAS/UE/EMM/SAP/EmmRegisteredInitiated.c @@ -240,7 +240,7 @@ int EmmRegisteredInitiated(nas_user_t *user, const emm_reg_t *evt) * any message transfered by EMM common procedures requested * by the network. */ - rc = emm_proc_lowerlayer_failure(user->lowerlayer_data, FALSE); + rc = emm_proc_lowerlayer_failure(user->lowerlayer_data, false); break; case _EMMREG_LOWERLAYER_RELEASE: diff --git a/openair3/NAS/UE/EMM/SAP/emm_as.c b/openair3/NAS/UE/EMM/SAP/emm_as.c index ea4eefadeb..de6dee4a5e 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_as.c +++ b/openair3/NAS/UE/EMM/SAP/emm_as.c @@ -679,7 +679,7 @@ static int _emm_as_cell_info_res(nas_user_t *user, const emm_as_cell_info_t *msg int AcT = NET_ACCESS_EUTRAN; - if (msg->found == TRUE) { + if (msg->found == true) { /* Get the first supported access technology */ while (AcT != NET_ACCESS_UNAVAILABLE) { if (msg->rat & (1 << AcT)) { @@ -1081,7 +1081,7 @@ static int _emm_as_data_req(const emm_data_t *emm_data, const emm_as_data_t *msg LOG_FUNC_IN; ul_info_transfer_req_t *as_msg = (ul_info_transfer_req_t *)ul_info_transfer_req_unaligned; int size = 0; - int is_encoded = FALSE; + bool is_encoded = false; LOG_TRACE(INFO, "EMMAS-SAP - Send AS data transfer request"); @@ -1114,7 +1114,7 @@ static int _emm_as_data_req(const emm_data_t *emm_data, const emm_as_data_t *msg default: /* Send other NAS messages as already encoded ESM messages */ size = msg->NASmsg.length; - is_encoded = TRUE; + is_encoded = true; break; } diff --git a/openair3/NAS/UE/EMM/SAP/emm_asDef.h b/openair3/NAS/UE/EMM/SAP/emm_asDef.h index 7bd464ec04..4f6182a2c9 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_asDef.h +++ b/openair3/NAS/UE/EMM/SAP/emm_asDef.h @@ -150,7 +150,7 @@ typedef struct emm_as_establish_s { uint32_t ueid; /* UE lower layer identifier */ emm_as_EPS_identity_t UEid; /* UE's EPS mobile identity */ emm_as_security_data_t sctx;/* EPS NAS security context */ - int switch_off; /* TRUE if the UE is switched off */ + bool switch_off; /* true if the UE is switched off */ uint8_t type; /* Network attach/detach type */ uint8_t RRCcause; /* Connection establishment cause */ uint8_t RRCtype; /* Associated call type */ @@ -194,7 +194,7 @@ typedef struct emm_as_data_s { uint32_t ueid; /* UE lower layer identifier */ const GUTI_t *guti; /* GUTI temporary mobile identity */ emm_as_security_data_t sctx;/* EPS NAS security context */ - int switch_off; /* TRUE if the UE is switched off */ + bool switch_off; /* true if the UE is switched off */ uint8_t type; /* Network detach type */ uint8_t delivered; /* Data message delivery indicator */ #define EMM_AS_NAS_DATA_ATTACH 0x01 /* Attach complete */ diff --git a/openair3/NAS/UE/EMM/SAP/emm_esmDef.h b/openair3/NAS/UE/EMM/SAP/emm_esmDef.h index aac37b46bf..6e7065f913 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_esmDef.h +++ b/openair3/NAS/UE/EMM/SAP/emm_esmDef.h @@ -71,9 +71,9 @@ typedef enum { * --------------------------------------------- */ typedef struct { - int is_emergency; /* Indicates whether the PDN connection is established + bool is_emergency; /* Indicates whether the PDN connection is established * for emergency bearer services only */ - int is_attached; /* Indicates whether the UE remains attached to the + bool is_attached; /* Indicates whether the UE remains attached to the * network */ } emm_esm_establish_t; diff --git a/openair3/NAS/UE/EMM/SAP/emm_regDef.h b/openair3/NAS/UE/EMM/SAP/emm_regDef.h index b66c0565ea..752f328375 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_regDef.h +++ b/openair3/NAS/UE/EMM/SAP/emm_regDef.h @@ -100,7 +100,7 @@ typedef struct { * ------------------------------------- */ typedef struct { - int is_emergency; /* TRUE if the UE was attempting to register to + bool is_emergency; /* true if the UE was attempting to register to * the network for emergency services only */ } emm_reg_attach_t; @@ -109,7 +109,7 @@ typedef struct { * ------------------------------------- */ typedef struct { - int switch_off; /* TRUE if the UE is switched off */ + bool switch_off; /* true if the UE is switched off */ int type; /* Network detach type */ } emm_reg_detach_t; diff --git a/openair3/NAS/UE/EMM/SecurityModeControl.c b/openair3/NAS/UE/EMM/SecurityModeControl.c index f9a02b1a70..fd3332669b 100644 --- a/openair3/NAS/UE/EMM/SecurityModeControl.c +++ b/openair3/NAS/UE/EMM/SecurityModeControl.c @@ -124,7 +124,7 @@ static void _security_release(emm_security_context_t *ctx); ** grity algorithm and ciphered with the selected NAS ciphe- ** ** ring algorithm. ** ** ** - ** Inputs: native_ksi: TRUE if the security context is of type ** + ** Inputs: native_ksi: true if the security context is of type ** ** native (for KSIASME) ** ** ksi: The NAS ket sey identifier ** ** seea: Selected EPS cyphering algorithm ** @@ -145,7 +145,7 @@ int emm_proc_security_mode_command(nas_user_t *user, int native_ksi, int ksi, int rc = RETURNerror; int emm_cause = EMM_CAUSE_SUCCESS; - int security_context_is_new = FALSE; + int security_context_is_new = false; security_data_t *security_data = user->security_data; LOG_TRACE(INFO, "EMM-PROC - Security mode control requested (ksi=%d)", @@ -263,7 +263,7 @@ int emm_proc_security_mode_command(nas_user_t *user, int native_ksi, int ksi, user->emm_data->security->ul_count.overflow = 0; user->emm_data->security->ul_count.seq_num = 0; /* Set new security context indicator */ - security_context_is_new = TRUE; + security_context_is_new = true; } } @@ -328,7 +328,7 @@ int emm_proc_security_mode_command(nas_user_t *user, int native_ksi, int ksi, emm_sap.u.emm_as.u.security.emm_cause = emm_cause; /* Setup EPS NAS security data */ emm_as_set_security_data(&emm_sap.u.emm_as.u.security.sctx, - user->emm_data->security, security_context_is_new, TRUE); + user->emm_data->security, security_context_is_new, true); rc = emm_sap_send(user, &emm_sap); LOG_FUNC_RETURN (rc); diff --git a/openair3/NAS/UE/EMM/emmData.h b/openair3/NAS/UE/EMM/emmData.h index dfdfb34e77..50219b7883 100644 --- a/openair3/NAS/UE/EMM/emmData.h +++ b/openair3/NAS/UE/EMM/emmData.h @@ -112,7 +112,7 @@ typedef struct { #define EMM_DETACH_COUNTER_MAX 5 unsigned int count; /* Counter used to limit the number of * subsequently detach attempts */ - int switch_off; /* UE switch-off indicator */ + bool switch_off; /* UE switch-off indicator */ emm_proc_detach_type_t type; /* Type of the detach procedure * currently in progress */ } emm_detach_data_t; @@ -249,8 +249,8 @@ typedef struct emm_data_s { emm_eps_update_t status; /* The current EPS update status */ emm_ecm_state_t ecm_status; /* The EPS Connection Management status */ - int is_attached; /* Network attachment indicator */ - int is_emergency; /* Emergency bearer services indicator*/ + bool is_attached; /* Network attachment indicator */ + bool is_emergency; /* Emergency bearer services indicator*/ /* Tracking Areas list the UE is registered to * Contains the list of TAIs that identify the tracking areas that diff --git a/openair3/NAS/UE/EMM/emm_main.c b/openair3/NAS/UE/EMM/emm_main.c index 329b59fae6..74676c8b36 100644 --- a/openair3/NAS/UE/EMM/emm_main.c +++ b/openair3/NAS/UE/EMM/emm_main.c @@ -113,7 +113,7 @@ void _emm_attach_initialize(emm_attach_data_t *emm_attach_data) { void _emm_detach_initialize(emm_detach_data_t *emm_detach) { emm_detach->count = 0; - emm_detach->switch_off = FALSE; + emm_detach->switch_off = false; emm_detach->type = EMM_DETACH_TYPE_RESERVED; } @@ -137,7 +137,7 @@ void emm_main_initialize(nas_user_t *user, emm_indication_callback_t cb, const c LOG_FUNC_IN; user->emm_data = calloc_or_fail(sizeof(emm_data_t)); /* USIM validity indicator */ - user->emm_data->usim_is_valid = FALSE; + user->emm_data->usim_is_valid = false; /* The IMEI read from the UE's non-volatile memory */ user->emm_data->imei = (imei_t *)malloc(sizeof(imei_t)); user->emm_data->imei->length = _emm_main_get_imei(user->emm_data->imei, imei); @@ -157,14 +157,14 @@ void emm_main_initialize(nas_user_t *user, emm_indication_callback_t cb, const c user->emm_data->plmn_rat = NET_ACCESS_UNAVAILABLE; /* Selected PLMN */ memset(&user->emm_data->splmn, 0xFF, sizeof(plmn_t)); - user->emm_data->is_rplmn = FALSE; - user->emm_data->is_eplmn = FALSE; + user->emm_data->is_rplmn = false; + user->emm_data->is_eplmn = false; /* Radio Access Technology of the serving cell */ user->emm_data->rat = NET_ACCESS_UNAVAILABLE; /* Network registration status */ user->emm_data->stat = NET_REG_STATE_OFF; - user->emm_data->is_attached = FALSE; - user->emm_data->is_emergency = FALSE; + user->emm_data->is_attached = false; + user->emm_data->is_emergency = false; /* Location/Tracking area code */ user->emm_data->tac = 0; // two byte in hexadecimal format /* Identifier of the serving cell */ @@ -201,7 +201,7 @@ void emm_main_initialize(nas_user_t *user, emm_indication_callback_t cb, const c /* The USIM application is present and valid */ LOG_TRACE(INFO, "EMM-MAIN - USIM application data successfully read"); - user->emm_data->usim_is_valid = TRUE; + user->emm_data->usim_is_valid = true; /* print keys (for debugging) */ { @@ -844,12 +844,12 @@ AcT_t emm_main_get_plmn_rat(emm_data_t *emm_data) ** Others: user->emm_data-> ** ** ** ** Outputs: None ** - ** Return: TRUE if the UE is currently attached to ** - ** the network; FALSE otherwise. ** + ** Return: true if the UE is currently attached to ** + ** the network; false otherwise. ** ** Others: None ** ** ** ***************************************************************************/ -int emm_main_is_attached(emm_data_t *emm_data) +bool emm_main_is_attached(emm_data_t *emm_data) { LOG_FUNC_IN; LOG_FUNC_RETURN (emm_data->is_attached); @@ -866,13 +866,13 @@ int emm_main_is_attached(emm_data_t *emm_data) ** Others: user->emm_data-> ** ** ** ** Outputs: None ** - ** Return: TRUE if the UE is currently attached or is ** + ** Return: true if the UE is currently attached or is ** ** attempting to attach to the network for ** - ** emergency bearer services; FALSE otherwise ** + ** emergency bearer services; false otherwise ** ** Others: None ** ** ** ***************************************************************************/ -int emm_main_is_emergency(emm_data_t *emm_data) +bool emm_main_is_emergency(emm_data_t *emm_data) { LOG_FUNC_IN; LOG_FUNC_RETURN (emm_data->is_attached && emm_data->is_emergency); @@ -967,8 +967,8 @@ static int _emm_main_get_imei(imei_t *imei, const char *imei_str) ** Others: None ** ** ** ** Outputs: None ** - ** Return: TRUE if the first IMSI is found to match ** - ** the second; FALSE otherwise. ** + ** Return: true if the first IMSI is found to match ** + ** the second; false otherwise. ** ** Others: None ** ** ** ***************************************************************************/ @@ -977,16 +977,16 @@ static int _emm_main_imsi_cmp(imsi_t *imsi1, imsi_t *imsi2) int i; if (imsi1->length != imsi2->length) { - return FALSE; + return false; } for (i = 0; i < imsi1->length; i++) { if (imsi1->u.value[i] != imsi2->u.value[i]) { - return FALSE; + return false; } } - return TRUE; + return true; } /**************************************************************************** diff --git a/openair3/NAS/UE/EMM/emm_main.h b/openair3/NAS/UE/EMM/emm_main.h index d30f778e3b..d081024548 100644 --- a/openair3/NAS/UE/EMM/emm_main.h +++ b/openair3/NAS/UE/EMM/emm_main.h @@ -94,8 +94,8 @@ AcT_t emm_main_get_plmn_rat(emm_data_t *emm_data); const char *emm_main_get_registered_plmn(emm_plmn_list_t *emm_plmn_list, emm_data_t *emm_data, network_plmn_t *plmn, int format); /* User's getter for network attachment */ -int emm_main_is_attached(emm_data_t *emm_data); -int emm_main_is_emergency(emm_data_t *emm_data); +bool emm_main_is_attached(emm_data_t *emm_data); +bool emm_main_is_emergency(emm_data_t *emm_data); #endif /* __EMM_MAIN_H__*/ diff --git a/openair3/NAS/UE/EMM/emm_proc.h b/openair3/NAS/UE/EMM/emm_proc.h index 7d4024d9d6..b93bb33bf1 100644 --- a/openair3/NAS/UE/EMM/emm_proc.h +++ b/openair3/NAS/UE/EMM/emm_proc.h @@ -89,7 +89,7 @@ int emm_proc_attach_accept(nas_user_t *user, long T3412, long T3402, long T3423, const OctetString *esm_msg); int emm_proc_attach_reject(nas_user_t *user, int emm_cause, const OctetString *esm_msg); int emm_proc_attach_complete(void *args); -int emm_proc_attach_failure(int is_initial, void *args); +int emm_proc_attach_failure(bool is_initial, void *args); int emm_proc_attach_release(void *args); int emm_proc_attach_restart(nas_user_t *user); @@ -103,10 +103,10 @@ int emm_proc_attach_set_detach(void *user); * Detach procedure * -------------------------------------------------------------------------- */ -int emm_proc_detach(nas_user_t *user, emm_proc_detach_type_t type, int switch_off); +int emm_proc_detach(nas_user_t *user, emm_proc_detach_type_t type, bool switch_off); int emm_proc_detach_request(void *args); int emm_proc_detach_accept(void *args); -int emm_proc_detach_failure(int is_initial, void *args); +int emm_proc_detach_failure(bool is_initial, void *args); int emm_proc_detach_release(void *args); diff --git a/openair3/NAS/UE/ESM/DedicatedEpsBearerContextActivation.c b/openair3/NAS/UE/ESM/DedicatedEpsBearerContextActivation.c index 21c3da3f19..db95dd648f 100644 --- a/openair3/NAS/UE/ESM/DedicatedEpsBearerContextActivation.c +++ b/openair3/NAS/UE/ESM/DedicatedEpsBearerContextActivation.c @@ -131,7 +131,7 @@ int esm_proc_dedicated_eps_bearer_context_request(nas_user_t *user, int ebi, int } /* Assign dedicated EPS bearer context */ - int new_ebi = esm_ebr_assign(user->esm_ebr_data, ebi, pid+1, FALSE); + int new_ebi = esm_ebr_assign(user->esm_ebr_data, ebi, pid+1, false); if (new_ebi == ESM_EBI_UNASSIGNED) { /* 3GPP TS 24.301, section 6.4.2.5, abnormal cases a and b @@ -141,7 +141,7 @@ int esm_proc_dedicated_eps_bearer_context_request(nas_user_t *user, int ebi, int int old_pid, old_bid; /* Locally deactivate the existing EPS bearer context and proceed * with the requested dedicated EPS bearer context activation */ - rc = esm_proc_eps_bearer_context_deactivate(user, TRUE, ebi, + rc = esm_proc_eps_bearer_context_deactivate(user, true, ebi, &old_pid, &old_bid); if (rc != RETURNok) { @@ -149,7 +149,7 @@ int esm_proc_dedicated_eps_bearer_context_request(nas_user_t *user, int ebi, int *esm_cause = ESM_CAUSE_PROTOCOL_ERROR; } else { /* Assign new dedicated EPS bearer context */ - ebi = esm_ebr_assign(user->esm_ebr_data, ebi, pid+1, FALSE); + ebi = esm_ebr_assign(user->esm_ebr_data, ebi, pid+1, false); } } @@ -165,7 +165,7 @@ int esm_proc_dedicated_eps_bearer_context_request(nas_user_t *user, int ebi, int *esm_cause = ESM_CAUSE_SYNTACTICAL_ERROR_IN_PACKET_FILTER; } else { /* Create new dedicated EPS bearer context */ - default_ebi = esm_ebr_context_create(esm_data, user->ueid, pid, ebi, FALSE, qos, tft); + default_ebi = esm_ebr_context_create(esm_data, user->ueid, pid, ebi, false, qos, tft); if (default_ebi != ESM_EBI_UNASSIGNED) { /* Dedicated EPS bearer contextx successfully created */ @@ -197,7 +197,7 @@ int esm_proc_dedicated_eps_bearer_context_request(nas_user_t *user, int ebi, int ** Inputs: is_standalone: Not used ** ** ebi: EPS bearer identity ** ** msg: Encoded ESM message to be sent ** - ** ue_triggered: TRUE if the EPS bearer context procedure ** + ** ue_triggered: true if the EPS bearer context procedure ** ** was triggered by the UE ** ** Others: None ** ** ** @@ -206,8 +206,8 @@ int esm_proc_dedicated_eps_bearer_context_request(nas_user_t *user, int ebi, int ** Others: None ** ** ** ***************************************************************************/ -int esm_proc_dedicated_eps_bearer_context_accept(nas_user_t *user, int is_standalone, int ebi, - OctetString *msg, int ue_triggered) +int esm_proc_dedicated_eps_bearer_context_accept(nas_user_t *user, bool is_standalone, int ebi, + OctetString *msg, bool ue_triggered) { LOG_FUNC_IN; @@ -268,8 +268,8 @@ int esm_proc_dedicated_eps_bearer_context_accept(nas_user_t *user, int is_standa ** Others: None ** ** ** ***************************************************************************/ -int esm_proc_dedicated_eps_bearer_context_reject(nas_user_t *user, int is_standalone, int ebi, - OctetString *msg, int ue_triggered) +int esm_proc_dedicated_eps_bearer_context_reject(nas_user_t *user, bool is_standalone, int ebi, + OctetString *msg, bool ue_triggered) { LOG_FUNC_IN; diff --git a/openair3/NAS/UE/ESM/DefaultEpsBearerContextActivation.c b/openair3/NAS/UE/ESM/DefaultEpsBearerContextActivation.c index 7c528d7569..f61b149822 100644 --- a/openair3/NAS/UE/ESM/DefaultEpsBearerContextActivation.c +++ b/openair3/NAS/UE/ESM/DefaultEpsBearerContextActivation.c @@ -103,7 +103,7 @@ int esm_proc_default_eps_bearer_context_request(nas_user_t *user, int pid, int e "requested by the network (ebi=%d)", ebi); /* Assign default EPS bearer context */ - int new_ebi = esm_ebr_assign(user->esm_ebr_data, ebi, pid+1, TRUE); + int new_ebi = esm_ebr_assign(user->esm_ebr_data, ebi, pid+1, true); if (new_ebi == ESM_EBI_UNASSIGNED) { /* 3GPP TS 24.301, section 6.4.1.5, abnormal cases a and b @@ -113,7 +113,7 @@ int esm_proc_default_eps_bearer_context_request(nas_user_t *user, int pid, int e int old_pid, old_bid; /* Locally deactivate the existing EPS bearer context and proceed * with the requested default EPS bearer context activation */ - rc = esm_proc_eps_bearer_context_deactivate(user, TRUE, ebi, + rc = esm_proc_eps_bearer_context_deactivate(user, true, ebi, &old_pid, &old_bid); if (rc != RETURNok) { @@ -121,13 +121,13 @@ int esm_proc_default_eps_bearer_context_request(nas_user_t *user, int pid, int e *esm_cause = ESM_CAUSE_PROTOCOL_ERROR; } else { /* Assign new default EPS bearer context */ - ebi = esm_ebr_assign(user->esm_ebr_data, ebi, pid+1, TRUE); + ebi = esm_ebr_assign(user->esm_ebr_data, ebi, pid+1, true); } } if (ebi != ESM_EBI_UNASSIGNED) { /* Create new default EPS bearer context */ - ebi = esm_ebr_context_create(esm_data, user->ueid, pid, ebi, TRUE, qos, NULL); + ebi = esm_ebr_context_create(esm_data, user->ueid, pid, ebi, true, qos, NULL); if (ebi != ESM_EBI_UNASSIGNED) { /* Default EPS bearer contextx successfully created */ @@ -165,9 +165,9 @@ int esm_proc_default_eps_bearer_context_request(nas_user_t *user, int pid, int e ** te message ** ** ebi: EPS bearer identity ** ** msg: Encoded ESM message to be sent ** - ** ue_triggered: TRUE if the EPS bearer context procedure ** + ** ue_triggered: true if the EPS bearer context procedure ** ** was triggered by the UE (should be always ** - ** TRUE) ** + ** true) ** ** Others: None ** ** ** ** Outputs: None ** @@ -175,8 +175,8 @@ int esm_proc_default_eps_bearer_context_request(nas_user_t *user, int pid, int e ** Others: None ** ** ** ***************************************************************************/ -int esm_proc_default_eps_bearer_context_accept(nas_user_t *user, int is_standalone, int ebi, - OctetString *msg, int ue_triggered) +int esm_proc_default_eps_bearer_context_accept(nas_user_t *user, bool is_standalone, int ebi, + OctetString *msg, bool ue_triggered) { LOG_FUNC_IN; @@ -245,8 +245,8 @@ int esm_proc_default_eps_bearer_context_accept(nas_user_t *user, int is_standalo ** Others: None ** ** ** ***************************************************************************/ -int esm_proc_default_eps_bearer_context_reject(nas_user_t *user, int is_standalone, int ebi, - OctetString *msg, int ue_triggered) +int esm_proc_default_eps_bearer_context_reject(nas_user_t *user, bool is_standalone, int ebi, + OctetString *msg, bool ue_triggered) { LOG_FUNC_IN; @@ -344,7 +344,7 @@ int esm_proc_default_eps_bearer_context_failure(nas_user_t *user) "ESM-PROC - Default EPS bearer context activation failure"); /* Release the default EPS bearer context and enter state INACTIVE */ - int rc = esm_proc_eps_bearer_context_deactivate(user, TRUE, ebi, &pid, &bid); + int rc = esm_proc_eps_bearer_context_deactivate(user, true, ebi, &pid, &bid); if (rc != RETURNerror) { /* Reset default EPS bearer context internal data */ diff --git a/openair3/NAS/UE/ESM/EpsBearerContextDeactivation.c b/openair3/NAS/UE/ESM/EpsBearerContextDeactivation.c index 5adbae05c6..742e70cd4a 100644 --- a/openair3/NAS/UE/ESM/EpsBearerContextDeactivation.c +++ b/openair3/NAS/UE/ESM/EpsBearerContextDeactivation.c @@ -97,7 +97,7 @@ static int _eps_bearer_release(nas_user_t *user, int ebi, int *pid, int *bid); ** has an EPS bearer context with specified EPS bearer iden- ** ** tity activated. ** ** ** - ** Inputs: is local: TRUE if the EPS bearer context has to be ** + ** Inputs: is local: true if the EPS bearer context has to be ** ** locally released without peer-to-peer si- ** ** gnalling between the UE and the MME ** ** ebi: EPS bearer identity of the EPS bearer con- ** @@ -111,7 +111,7 @@ static int _eps_bearer_release(nas_user_t *user, int ebi, int *pid, int *bid); ** Others: None ** ** ** ***************************************************************************/ -int esm_proc_eps_bearer_context_deactivate(nas_user_t *user, int is_local, int ebi, +int esm_proc_eps_bearer_context_deactivate(nas_user_t *user, bool is_local, int ebi, int *pid, int *bid) { LOG_FUNC_IN; @@ -213,7 +213,7 @@ int esm_proc_eps_bearer_context_deactivate_request(nas_user_t *user, int ebi, in * the PDN connection */ if (*esm_cause == ESM_CAUSE_REACTIVATION_REQUESTED) { esm_sap_t esm_sap; - int active = FALSE; + bool active = false; /* 3GPP TS 24.301, section 6.4.4.3 * The UE should re-initiate the UE requested PDN connectivity @@ -242,8 +242,8 @@ int esm_proc_eps_bearer_context_deactivate_request(nas_user_t *user, int ebi, in * Notify ESM to re-initiate PDN connectivity procedure */ esm_sap.primitive = ESM_PDN_CONNECTIVITY_REQ; - esm_sap.is_standalone = TRUE; - esm_sap.data.pdn_connect.is_defined = TRUE; + esm_sap.is_standalone = true; + esm_sap.data.pdn_connect.is_defined = true; esm_sap.data.pdn_connect.cid = pid + 1; rc = esm_sap_send(user, &esm_sap); } @@ -265,10 +265,10 @@ int esm_proc_eps_bearer_context_deactivate_request(nas_user_t *user, int ebi, in ** DEACTIVATE EPS BEARER CONTEXT ACCEPT message and entering ** ** the state BEARER CONTEXT INACTIVE. ** ** ** - ** Inputs: is_standalone: Should be always TRUE ** + ** Inputs: is_standalone: Should be always true ** ** ebi: EPS bearer identity ** ** msg: Encoded ESM message to be sent ** - ** ue_triggered: TRUE if the EPS bearer context procedure ** + ** ue_triggered: true if the EPS bearer context procedure ** ** was triggered by the UE ** ** Others: None ** ** ** @@ -277,8 +277,8 @@ int esm_proc_eps_bearer_context_deactivate_request(nas_user_t *user, int ebi, in ** Others: None ** ** ** ***************************************************************************/ -int esm_proc_eps_bearer_context_deactivate_accept(nas_user_t *user, int is_standalone, int ebi, - OctetString *msg, int ue_triggered) +int esm_proc_eps_bearer_context_deactivate_accept(nas_user_t *user, bool is_standalone, int ebi, + OctetString *msg, bool ue_triggered) { LOG_FUNC_IN; @@ -371,7 +371,7 @@ static int _eps_bearer_release(nas_user_t *user, int ebi, int *pid, int *bid) LOG_TRACE(WARNING, "ESM-PROC - Failed to release EPS bearer context"); } else { /* Set the EPS bearer context state to INACTIVE */ - rc = esm_ebr_set_status(user_api_id, esm_ebr_data, ebi, ESM_EBR_INACTIVE, FALSE); + rc = esm_ebr_set_status(user_api_id, esm_ebr_data, ebi, ESM_EBR_INACTIVE, false); if (rc != RETURNok) { /* The EPS bearer context was already in INACTIVE state */ diff --git a/openair3/NAS/UE/ESM/EsmStatusHdl.c b/openair3/NAS/UE/ESM/EsmStatusHdl.c index def498a89b..88f6550251 100644 --- a/openair3/NAS/UE/ESM/EsmStatusHdl.c +++ b/openair3/NAS/UE/ESM/EsmStatusHdl.c @@ -149,7 +149,7 @@ int esm_proc_status_ind( ** ** ** Description: Initiates ESM status procedure. ** ** ** - ** Inputs: is_standalone: Not used - Always TRUE ** + ** Inputs: is_standalone: Not used - Always true ** ** ueid: UE lower layer identifier ** ** ebi: Not used ** ** msg: Encoded ESM status message to be sent ** @@ -161,9 +161,9 @@ int esm_proc_status_ind( ** Others: None ** ** ** ***************************************************************************/ -int esm_proc_status(nas_user_t *user, int is_standalone, +int esm_proc_status(nas_user_t *user, bool is_standalone, int ebi, OctetString *msg, - int ue_triggered) + bool ue_triggered) { LOG_FUNC_IN; diff --git a/openair3/NAS/UE/ESM/PdnConnectivity.c b/openair3/NAS/UE/ESM/PdnConnectivity.c index d17b5fde3c..a79320cccb 100644 --- a/openair3/NAS/UE/ESM/PdnConnectivity.c +++ b/openair3/NAS/UE/ESM/PdnConnectivity.c @@ -80,7 +80,7 @@ Description Defines the PDN connectivity ESM procedure executed by the * PDN connection handlers */ static int _pdn_connectivity_create(esm_data_t *esm_data, int pid, const OctetString *apn, - esm_proc_pdn_type_t pdn_type, int is_emergency); + esm_proc_pdn_type_t pdn_type, bool is_emergency); static int _pdn_connectivity_update(esm_data_t *esm_data, int pid, const OctetString *apn, esm_proc_pdn_type_t pdn_type, const OctetString *pdn_addr, int esm_cause); static int _pdn_connectivity_delete(esm_data_t *esm_data, int pid); @@ -121,7 +121,7 @@ static void *_pdn_connectivity_t3482_handler(void *); ** to be defined or undefined ** ** pdn_type: PDN connection type (IPv4, IPv6, IPv4v6) ** ** apn: Access Point logical Name to be used ** - ** is_emergency: TRUE if the PDN connection has to be esta- ** + ** is_emergency: true if the PDN connection has to be esta- ** ** blished for emergency bearer services ** ** Others: None ** ** ** @@ -133,7 +133,7 @@ static void *_pdn_connectivity_t3482_handler(void *); ***************************************************************************/ int esm_proc_pdn_connectivity(nas_user_t *user, int cid, int is_to_define, esm_proc_pdn_type_t pdn_type, - const OctetString *apn, int is_emergency, + const OctetString *apn, bool is_emergency, unsigned int *pti) { LOG_FUNC_IN; @@ -270,7 +270,7 @@ int esm_proc_pdn_connectivity(nas_user_t *user, int cid, int is_to_define, ** pti: Procedure transaction identity ** ** msg: Encoded PDN connectivity request message ** ** to be sent ** - ** sent_by_ue: Not used - Always TRUE ** + ** sent_by_ue: Not used - Always true ** ** Others: None ** ** ** ** Outputs: None ** @@ -278,8 +278,8 @@ int esm_proc_pdn_connectivity(nas_user_t *user, int cid, int is_to_define, ** Others: None ** ** ** ***************************************************************************/ -int esm_proc_pdn_connectivity_request(nas_user_t *user, int is_standalone, int pti, - OctetString *msg, int sent_by_ue) +int esm_proc_pdn_connectivity_request(nas_user_t *user, bool is_standalone, int pti, + OctetString *msg, bool sent_by_ue) { LOG_FUNC_IN; esm_pt_data_t *esm_pt_data = user->esm_pt_data; @@ -523,7 +523,7 @@ int esm_proc_pdn_connectivity_complete(nas_user_t *user) ** PDN connectivity procedure which is still pending in the ** ** PROCEDURE TRANSACTION INACTIVE or PENDING state. ** ** ** - ** Inputs: is_pending: TRUE if this PDN connectivity procedure ** + ** Inputs: is_pending: true if this PDN connectivity procedure ** ** transaction is in the PENDING state ** ** Others: None ** ** ** @@ -679,7 +679,7 @@ static void *_pdn_connectivity_t3482_handler(void *args) ** Inputs: pid: Identifier of the PDN connection entry ** ** apn: Access Point Name of the PDN connection ** ** pdn_type: PDN type (IPv4, IPv6, IPv4v6) ** - ** is_emergency: TRUE if the PDN connection has to be esta- ** + ** is_emergency: true if the PDN connection has to be esta- ** ** blished for emergency bearer services ** ** ** ** Outputs: None ** @@ -688,7 +688,7 @@ static void *_pdn_connectivity_t3482_handler(void *args) ***************************************************************************/ static int _pdn_connectivity_create(esm_data_t *esm_data, int pid, const OctetString *apn, esm_proc_pdn_type_t pdn_type, - int is_emergency) + bool is_emergency) { esm_pdn_t *pdn = NULL; @@ -720,7 +720,7 @@ static int _pdn_connectivity_create(esm_data_t *esm_data, int pid, const OctetSt /* Set the PDN connection identifier */ esm_data->pdn[pid].pid = pid; /* Reset the PDN connection active indicator */ - esm_data->pdn[pid].is_active = FALSE; + esm_data->pdn[pid].is_active = false; /* Setup the PDN connection data */ esm_data->pdn[pid].data = pdn; } @@ -744,7 +744,7 @@ static int _pdn_connectivity_create(esm_data_t *esm_data, int pid, const OctetSt } pdn->type = pdn_type; - pdn->addr_realloc = FALSE; + pdn->addr_realloc = false; return (RETURNok); } @@ -825,7 +825,7 @@ static int _pdn_connectivity_update(esm_data_t *esm_data, int pid, const OctetSt * the other IP version using the UE requested PDN connectivity * procedure to the same APN with a single address PDN type * (IPv4 or IPv6) other than the one already activated */ - pdn->addr_realloc = TRUE; + pdn->addr_realloc = true; } else if ( (esm_cause == ESM_CAUSE_PDN_TYPE_IPV4_ONLY_ALLOWED) || (esm_cause == ESM_CAUSE_PDN_TYPE_IPV6_ONLY_ALLOWED) ) { /* The UE requested IPv4 or IPv6 address and the network allows @@ -833,9 +833,9 @@ static int _pdn_connectivity_update(esm_data_t *esm_data, int pid, const OctetSt * The UE shall not subsequently initiate another UE requested * PDN connectivity procedure to the same APN to obtain a PDN * type different from the one allowed by the network */ - pdn->addr_realloc = FALSE; + pdn->addr_realloc = false; } else if (pdn_type != ESM_PDN_TYPE_IPV4V6) { - pdn->addr_realloc = TRUE; + pdn->addr_realloc = true; } return (RETURNok); diff --git a/openair3/NAS/UE/ESM/PdnDisconnect.c b/openair3/NAS/UE/ESM/PdnDisconnect.c index 6665126e40..cb7b3225bc 100644 --- a/openair3/NAS/UE/ESM/PdnDisconnect.c +++ b/openair3/NAS/UE/ESM/PdnDisconnect.c @@ -155,7 +155,7 @@ int esm_proc_pdn_disconnect(esm_data_t *esm_data, int cid, unsigned int *pti, un ** PDN DISCONNECT REQUEST message to the MME, starting timer ** ** T3492 and entering state PROCEDURE TRANSACTION PENDING. ** ** ** - ** Inputs: is_standalone: Should be always TRUE ** + ** Inputs: is_standalone: Should be always true ** ** pti: Procedure transaction identity ** ** msg: Encoded PDN disconnect request message to ** ** be sent ** @@ -167,8 +167,8 @@ int esm_proc_pdn_disconnect(esm_data_t *esm_data, int cid, unsigned int *pti, un ** Others: None ** ** ** ***************************************************************************/ -int esm_proc_pdn_disconnect_request(nas_user_t *user, int is_standalone, int pti, - OctetString *msg, int sent_by_ue) +int esm_proc_pdn_disconnect_request(nas_user_t *user, bool is_standalone, int pti, + OctetString *msg, bool sent_by_ue) { LOG_FUNC_IN; @@ -326,7 +326,7 @@ int esm_proc_pdn_disconnect_reject(nas_user_t *user, int pti, int *esm_cause) */ esm_sap_t esm_sap; esm_sap.primitive = ESM_EPS_BEARER_CONTEXT_DEACTIVATE_REQ; - esm_sap.is_standalone = TRUE; + esm_sap.is_standalone = true; esm_sap.recv = NULL; esm_sap.send.length = 0; esm_sap.data.eps_bearer_context_deactivate.ebi = ebi; @@ -444,7 +444,7 @@ static void *_pdn_disconnect_t3492_handler(void *args) */ esm_sap_t esm_sap; esm_sap.primitive = ESM_EPS_BEARER_CONTEXT_DEACTIVATE_REQ; - esm_sap.is_standalone = TRUE; + esm_sap.is_standalone = true; esm_sap.recv = NULL; esm_sap.send.length = 0; esm_sap.data.eps_bearer_context_deactivate.ebi = ebi; diff --git a/openair3/NAS/UE/ESM/SAP/esm_sap.c b/openair3/NAS/UE/ESM/SAP/esm_sap.c index e039f66a3a..f1663175d4 100644 --- a/openair3/NAS/UE/ESM/SAP/esm_sap.c +++ b/openair3/NAS/UE/ESM/SAP/esm_sap.c @@ -63,9 +63,9 @@ Description Defines the ESM Service Access Points at which the EPS /******************* L O C A L D E F I N I T I O N S *******************/ /****************************************************************************/ -static int _esm_sap_recv(nas_user_t *user, int msg_type, int is_standalone, +static int _esm_sap_recv(nas_user_t *user, int msg_type, bool is_standalone, const OctetString *req, OctetString *rsp, esm_sap_error_t *err); -static int _esm_sap_send(nas_user_t *user, int msg_type, int is_standalone, int pti, int ebi, +static int _esm_sap_send(nas_user_t *user, int msg_type, bool is_standalone, int pti, int ebi, const esm_sap_data_t *data, OctetString *rsp); @@ -171,7 +171,7 @@ int esm_sap_send(nas_user_t *user, esm_sap_t *msg) } /* Define new PDN context */ - rc = esm_proc_pdn_connectivity(user, pdn_connect->cid, TRUE, + rc = esm_proc_pdn_connectivity(user, pdn_connect->cid, true, pdn_connect->pdn_type, &apn, pdn_connect->is_emergency, NULL); @@ -183,7 +183,7 @@ int esm_sap_send(nas_user_t *user, esm_sap_t *msg) if (pdn_connect->is_defined) { unsigned int pti; /* Assign new procedure transaction identity */ - rc = esm_proc_pdn_connectivity(user, pdn_connect->cid, TRUE, + rc = esm_proc_pdn_connectivity(user, pdn_connect->cid, true, pdn_connect->pdn_type, NULL, pdn_connect->is_emergency, &pti); @@ -205,7 +205,7 @@ int esm_sap_send(nas_user_t *user, esm_sap_t *msg) if ( msg->is_standalone && pdn_connect->is_defined ) { /* Undefine the specified PDN context */ - rc = esm_proc_pdn_connectivity(user, pdn_connect->cid, FALSE, + rc = esm_proc_pdn_connectivity(user, pdn_connect->cid, false, pdn_connect->pdn_type, NULL, pdn_connect->is_emergency, NULL); } else if (msg->recv != NULL) { @@ -214,7 +214,7 @@ int esm_sap_send(nas_user_t *user, esm_sap_t *msg) msg->recv, &msg->send, &msg->err); } else { /* The PDN connectivity procedure locally failed */ - rc = esm_proc_pdn_connectivity_failure(user, TRUE); + rc = esm_proc_pdn_connectivity_failure(user, true); } } break; @@ -230,7 +230,7 @@ int esm_sap_send(nas_user_t *user, esm_sap_t *msg) if (rc != RETURNerror) { /* Send PDN disconnect request */ - rc = _esm_sap_send(user, PDN_DISCONNECT_REQUEST, TRUE, pti, ebi, + rc = _esm_sap_send(user, PDN_DISCONNECT_REQUEST, true, pti, ebi, &msg->data, &msg->send); } } @@ -278,7 +278,7 @@ int esm_sap_send(nas_user_t *user, esm_sap_t *msg) rc = esm_proc_default_eps_bearer_context_failure(user); if (rc != RETURNerror) { - rc = esm_proc_pdn_connectivity_failure(user, FALSE); + rc = esm_proc_pdn_connectivity_failure(user, false); } break; @@ -306,7 +306,7 @@ int esm_sap_send(nas_user_t *user, esm_sap_t *msg) /* * Locally deactivate EPS bearer context */ - rc = esm_proc_eps_bearer_context_deactivate(user, TRUE, + rc = esm_proc_eps_bearer_context_deactivate(user, true, msg->data.eps_bearer_context_deactivate.ebi, &pid, &bid); } break; @@ -359,7 +359,7 @@ int esm_sap_send(nas_user_t *user, esm_sap_t *msg) ** Return: RETURNok, RETURNerror ** ** ** ***************************************************************************/ -static int _esm_sap_recv(nas_user_t *user, int msg_type, int is_standalone, +static int _esm_sap_recv(nas_user_t *user, int msg_type, bool is_standalone, const OctetString *req, OctetString *rsp, esm_sap_error_t *err) { @@ -422,7 +422,7 @@ static int _esm_sap_recv(nas_user_t *user, int msg_type, int is_standalone, * was triggered network-internally */ int triggered_by_ue = (pti != PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED); /* Indicate whether the received message shall be ignored */ - int is_discarded = FALSE; + bool is_discarded = false; if (esm_cause != ESM_CAUSE_SUCCESS) { LOG_TRACE(ERROR, "ESM-SAP - Failed to decode expected ESM message " @@ -455,7 +455,7 @@ static int _esm_sap_recv(nas_user_t *user, int msg_type, int is_standalone, * of already accepted activate default EPS bearer context * request message */ - is_discarded = TRUE; + is_discarded = true; } } else { /* Return reject message */ @@ -493,7 +493,7 @@ static int _esm_sap_recv(nas_user_t *user, int msg_type, int is_standalone, * of already accepted activate dedicated EPS bearer context * request message */ - is_discarded = TRUE; + is_discarded = true; } } else { /* Return reject message */ @@ -525,7 +525,7 @@ static int _esm_sap_recv(nas_user_t *user, int msg_type, int is_standalone, * received with PTI reserved value, or assigned value * that does not match any PTI in use */ - is_discarded = TRUE; + is_discarded = true; } else if ( (esm_cause == ESM_CAUSE_SUCCESS) || (esm_cause == ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY) ) { /* Return accept message */ @@ -541,7 +541,7 @@ static int _esm_sap_recv(nas_user_t *user, int msg_type, int is_standalone, * message with the EPS bearer identity set to the received * EPS bearer identity */ - is_discarded = TRUE; + is_discarded = true; } } @@ -565,7 +565,7 @@ static int _esm_sap_recv(nas_user_t *user, int msg_type, int is_standalone, * Ignore PDN connectivity reject message received with * reserved or unassigned EPS bearer identity value */ - is_discarded = TRUE; + is_discarded = true; } break; @@ -588,7 +588,7 @@ static int _esm_sap_recv(nas_user_t *user, int msg_type, int is_standalone, * Ignore PDN disconnect reject message received with * reserved or unassigned EPS bearer identity value */ - is_discarded = TRUE; + is_discarded = true; } break; @@ -629,7 +629,7 @@ static int _esm_sap_recv(nas_user_t *user, int msg_type, int is_standalone, * onto the network */ esm_procedure = esm_proc_status; /* Discard received ESM message */ - is_discarded = TRUE; + is_discarded = true; } } else { /* ESM message processing succeed */ @@ -687,7 +687,7 @@ static int _esm_sap_recv(nas_user_t *user, int msg_type, int is_standalone, ** Return: RETURNok, RETURNerror ** ** ** ***************************************************************************/ -static int _esm_sap_send(nas_user_t *user, int msg_type, int is_standalone, +static int _esm_sap_send(nas_user_t *user, int msg_type, bool is_standalone, int pti, int ebi, const esm_sap_data_t *data, OctetString *rsp) { @@ -697,7 +697,7 @@ static int _esm_sap_send(nas_user_t *user, int msg_type, int is_standalone, int rc = RETURNok; /* Indicate whether the message is sent by the UE or the MME */ - int sent_by_ue = TRUE; + bool sent_by_ue = true; ESM_msg esm_msg; memset(&esm_msg, 0 , sizeof(ESM_msg)); diff --git a/openair3/NAS/UE/ESM/SAP/esm_sapDef.h b/openair3/NAS/UE/ESM/SAP/esm_sapDef.h index 4ff7c7e9dd..2d3227ba75 100644 --- a/openair3/NAS/UE/ESM/SAP/esm_sapDef.h +++ b/openair3/NAS/UE/ESM/SAP/esm_sapDef.h @@ -109,11 +109,11 @@ typedef struct esm_activate_eps_default_bearer_context_s { */ typedef struct esm_pdn_connectivity_s { int cid; /* PDN connection local identifier */ - int is_defined; /* Indicates whether a PDN context has been defined + bool is_defined; /* Indicates whether a PDN context has been defined * for the specified APN */ int pdn_type; /* PDN address type (IPv4, IPv6, IPv4v6) */ const char *apn; /* PDN's Access Point Name */ - int is_emergency; /* Indicates whether the PDN context has been + bool is_emergency; /* Indicates whether the PDN context has been * defined to establish connection for emergency * bearer services */ } esm_pdn_connectivity_t; @@ -149,7 +149,7 @@ typedef union { typedef struct esm_sap_s { esm_primitive_t primitive; /* ESM-SAP primitive to process */ - int is_standalone; /* Indicates whether the ESM message handled + bool is_standalone; /* Indicates whether the ESM message handled * within this primitive has to be sent/received * standalone or together within an EMM related * message */ diff --git a/openair3/NAS/UE/ESM/SAP/esm_send.c b/openair3/NAS/UE/ESM/SAP/esm_send.c index 020d9d89e3..e710d745ad 100644 --- a/openair3/NAS/UE/ESM/SAP/esm_send.c +++ b/openair3/NAS/UE/ESM/SAP/esm_send.c @@ -132,7 +132,7 @@ int esm_send_status(int pti, int ebi, esm_status_msg *msg, int esm_cause) ** Others: None ** ** ** ***************************************************************************/ -int esm_send_pdn_connectivity_request(int pti, int is_emergency, int pdn_type, +int esm_send_pdn_connectivity_request(int pti, bool is_emergency, int pdn_type, const char *apn, pdn_connectivity_request_msg *msg) { diff --git a/openair3/NAS/UE/ESM/SAP/esm_send.h b/openair3/NAS/UE/ESM/SAP/esm_send.h index f97454027a..b9bcab0f39 100644 --- a/openair3/NAS/UE/ESM/SAP/esm_send.h +++ b/openair3/NAS/UE/ESM/SAP/esm_send.h @@ -40,6 +40,8 @@ Description Defines functions executed at the ESM Service Access #ifndef __ESM_SEND_H__ #define __ESM_SEND_H__ +#include + #include "EsmStatus.h" @@ -90,7 +92,7 @@ int esm_send_status(int pti, int ebi, esm_status_msg *msg, int esm_cause); * Transaction related messages * ---------------------------- */ -int esm_send_pdn_connectivity_request(int pti, int is_emergency, int pdn_type, +int esm_send_pdn_connectivity_request(int pti, bool is_emergency, int pdn_type, const char *apn, pdn_connectivity_request_msg *msg); int esm_send_pdn_disconnect_request(int pti, int ebi, pdn_disconnect_request_msg *msg); diff --git a/openair3/NAS/UE/ESM/esmData.h b/openair3/NAS/UE/ESM/esmData.h index 16f4707a37..525f4ec00a 100644 --- a/openair3/NAS/UE/ESM/esmData.h +++ b/openair3/NAS/UE/ESM/esmData.h @@ -37,6 +37,7 @@ Description Defines internal private data handled by EPS Session *****************************************************************************/ #include // sprintf +#include #include "networkDef.h" #include "OctetString.h" @@ -92,7 +93,7 @@ typedef enum { typedef struct esm_ebr_context_s { unsigned char ebi; /* EPS bearer identity */ esm_ebr_state status; /* EPS bearer context status */ - int is_default_ebr; /* TRUE if the bearer context is associated + bool is_default_ebr; /* bool if the bearer context is associated * to a default EPS bearer */ char cid; /* Identifier of the PDN context the EPS * bearer context has been assigned to */ @@ -137,7 +138,7 @@ typedef struct esm_bearer_s { typedef struct esm_pdn_s { unsigned int pti; /* Identity of the procedure transaction executed * to activate the PDN connection entry */ - int is_emergency; /* Emergency bearer services indicator */ + bool is_emergency; /* Emergency bearer services indicator */ OctetString apn; /* Access Point Name currently in used */ int ambr; /* Aggregate Maximum Bit Rate of this APN */ int type; /* Address PDN type (IPv4, IPv6, IPv4v6) */ @@ -147,7 +148,7 @@ typedef struct esm_pdn_s { ESM_DATA_IPV6_ADDRESS_SIZE) /* IPv4 PDN address and/or IPv6 prefix */ char ip_addr[ESM_DATA_IP_ADDRESS_SIZE+1]; - int addr_realloc; /* Indicates whether the UE is allowed to subsequently + bool addr_realloc; /* Indicates whether the UE is allowed to subsequently * request another PDN connectivity to the same APN * using an address PDN type (IPv4 or IPv6) other * than the one already activated */ @@ -175,7 +176,7 @@ typedef struct esm_data_context_s { #define ESM_DATA_PDN_MAX 4 struct { int pid; /* Identifier of the PDN connection */ - int is_active; /* TRUE/FALSE if the PDN connection is active/inactive + bool is_active; /* true/false if the PDN connection is active/inactive * or the process to activate/deactivate the PDN * connection is in progress */ esm_pdn_t *data; /* Active PDN connection data */ diff --git a/openair3/NAS/UE/ESM/esm_ebr.c b/openair3/NAS/UE/ESM/esm_ebr.c index 3a62812eca..4c6b56cec9 100644 --- a/openair3/NAS/UE/ESM/esm_ebr.c +++ b/openair3/NAS/UE/ESM/esm_ebr.c @@ -153,7 +153,7 @@ void esm_ebr_register_callback(esm_indication_callback_t cb) ** ebi: Identity of the new EPS bearer context ** ** cid: Identifier of the PDN context the EPS bea- ** ** rer context is associated to ** - ** default_ebr TRUE if the new bearer context is associa- ** + ** default_ebr bool if the new bearer context is associa- ** ** ted to a default EPS bearer ** ** Others: None ** ** ** @@ -163,7 +163,7 @@ void esm_ebr_register_callback(esm_indication_callback_t cb) ** the not assigned EBI (0) otherwise. ** ** ** ***************************************************************************/ -int esm_ebr_assign(esm_ebr_data_t *esm_ebr_data, int ebi, int cid, int default_ebr) +int esm_ebr_assign(esm_ebr_data_t *esm_ebr_data, int ebi, int cid, bool default_ebr) { esm_ebr_context_t *ebr_ctx = NULL; int i; @@ -284,7 +284,7 @@ int esm_ebr_release(esm_ebr_data_t *esm_ebr_data, ** ** ** ebi: The identity of the EPS bearer ** ** status: The new EPS bearer context status ** - ** ue_requested: TRUE/FALSE if the modification of the EPS ** + ** ue_requested: true/false if the modification of the EPS ** ** bearer context status was requested by the ** ** UE/network ** ** Others: None ** @@ -294,7 +294,7 @@ int esm_ebr_release(esm_ebr_data_t *esm_ebr_data, ** ** ***************************************************************************/ int esm_ebr_set_status(user_api_id_t *user_api_id, esm_ebr_data_t *esm_ebr_data, - int ebi, esm_ebr_state status, int ue_requested) + int ebi, esm_ebr_state status, bool ue_requested) { esm_ebr_context_t *ebr_ctx; esm_ebr_state old_status; @@ -385,11 +385,11 @@ esm_ebr_state esm_ebr_get_status(esm_ebr_data_t *esm_ebr_data, ** Others: None ** ** ** ** Outputs: None ** - ** Return: TRUE, FALSE ** + ** Return: true, false ** ** Others: None ** ** ** ***************************************************************************/ -int esm_ebr_is_reserved(esm_ebr_data_t *esm_ebr_data, int ebi) +bool esm_ebr_is_reserved(esm_ebr_data_t *esm_ebr_data, int ebi) { return ( (ebi != ESM_EBI_UNASSIGNED) && (ebi < ESM_EBI_MIN) ); } @@ -404,12 +404,11 @@ int esm_ebr_is_reserved(esm_ebr_data_t *esm_ebr_data, int ebi) ** ebi: The identity of the EPS bearer ** ** ** ** Outputs: None ** - ** Return: TRUE, FALSE ** + ** Return: true, false ** ** Others: None ** ** ** ***************************************************************************/ -int esm_ebr_is_not_in_use(esm_ebr_data_t *esm_ebr_data, - int ebi) +bool esm_ebr_is_not_in_use(esm_ebr_data_t *esm_ebr_data, int ebi) { return ( (ebi == ESM_EBI_UNASSIGNED) || diff --git a/openair3/NAS/UE/ESM/esm_ebr.h b/openair3/NAS/UE/ESM/esm_ebr.h index 6de4a048a4..4447a227ba 100644 --- a/openair3/NAS/UE/ESM/esm_ebr.h +++ b/openair3/NAS/UE/ESM/esm_ebr.h @@ -75,15 +75,15 @@ typedef int (*esm_indication_callback_t) (user_api_id_t *user_api_id, int, netwo void esm_ebr_register_callback(esm_indication_callback_t cb); -int esm_ebr_is_reserved(esm_ebr_data_t *esm_ebr_data, int ebi); +bool esm_ebr_is_reserved(esm_ebr_data_t *esm_ebr_data, int ebi); esm_ebr_data_t *esm_ebr_initialize(void); -int esm_ebr_assign(esm_ebr_data_t *esm_ebr_data, int ebi, int cid, int default_ebr); +int esm_ebr_assign(esm_ebr_data_t *esm_ebr_data, int ebi, int cid, bool default_ebr); int esm_ebr_release(esm_ebr_data_t *esm_ebr_data, int ebi); -int esm_ebr_set_status(user_api_id_t *user_api_id, esm_ebr_data_t *esm_ebr_data, int ebi, esm_ebr_state status, int ue_requested); +int esm_ebr_set_status(user_api_id_t *user_api_id, esm_ebr_data_t *esm_ebr_data, int ebi, esm_ebr_state status, bool ue_requested); esm_ebr_state esm_ebr_get_status(esm_ebr_data_t *esm_ebr_data, int ebi); -int esm_ebr_is_not_in_use(esm_ebr_data_t *esm_ebr_data, int ebi); +bool esm_ebr_is_not_in_use(esm_ebr_data_t *esm_ebr_data, int ebi); #endif /* __ESM_EBR_H__*/ diff --git a/openair3/NAS/UE/ESM/esm_ebr_context.c b/openair3/NAS/UE/ESM/esm_ebr_context.c index b801ca2ad5..ca69687abe 100644 --- a/openair3/NAS/UE/ESM/esm_ebr_context.c +++ b/openair3/NAS/UE/ESM/esm_ebr_context.c @@ -84,7 +84,7 @@ static int _esm_ebr_context_check_precedence(const network_tft_t *, ** Inputs: ** ** pid: PDN connection identifier ** ** ebi: EPS bearer identity ** - ** is_default: TRUE if the new bearer is a default EPS ** + ** is_default: true if the new bearer is a default EPS ** ** bearer context ** ** esm_qos: EPS bearer level QoS parameters ** ** tft: Traffic flow template parameters ** @@ -98,7 +98,7 @@ static int _esm_ebr_context_check_precedence(const network_tft_t *, ***************************************************************************/ int esm_ebr_context_create( esm_data_t *esm_data, int ueid, - int pid, int ebi, int is_default, + int pid, int ebi, bool is_default, const network_qos_t *qos, const network_tft_t *tft) { int bid = 0; esm_data_context_t *esm_ctx = NULL; @@ -185,11 +185,11 @@ int esm_ebr_context_create( if (is_default) { /* Set the PDN connection activation indicator */ - esm_ctx->pdn[pid].is_active = TRUE; + esm_ctx->pdn[pid].is_active = true; /* Update the emergency bearer services indicator */ if (pdn->is_emergency) { - esm_ctx->emergency = TRUE; + esm_ctx->emergency = true; } // LG ADD TEMP @@ -383,7 +383,7 @@ int esm_ebr_context_create( ***************************************************************************/ int esm_ebr_context_release(nas_user_t *user, int ebi, int *pid, int *bid) { - int found = FALSE; + bool found = false; esm_pdn_t *pdn = NULL; esm_data_context_t *esm_ctx; esm_ebr_data_t *esm_ebr_data = user->esm_ebr_data; @@ -416,7 +416,7 @@ int esm_ebr_context_release(nas_user_t *user, } /* The EPS bearer context entry is found */ - found = TRUE; + found = true; break; } } @@ -450,7 +450,7 @@ int esm_ebr_context_release(nas_user_t *user, if (pdn->bearer[*bid] != NULL) { ebi = pdn->bearer[*bid]->ebi; - found = TRUE; + found = true; } } } @@ -503,7 +503,7 @@ int esm_ebr_context_release(nas_user_t *user, /* Set the EPS bearer context state to INACTIVE */ esm_ebr_set_status(user_api_id, esm_ebr_data, pdn->bearer[i]->ebi, - ESM_EBR_INACTIVE, TRUE); + ESM_EBR_INACTIVE, true); /* Release EPS bearer data */ esm_ebr_release(esm_ebr_data, pdn->bearer[i]->ebi); // esm_ebr_release() @@ -519,11 +519,11 @@ int esm_ebr_context_release(nas_user_t *user, } /* Reset the PDN connection activation indicator */ - esm_ctx->pdn[*pid].is_active = FALSE; + esm_ctx->pdn[*pid].is_active = false; /* Update the emergency bearer services indicator */ if (pdn->is_emergency) { - esm_ctx->emergency = FALSE; + esm_ctx->emergency = false; } } @@ -534,7 +534,7 @@ int esm_ebr_context_release(nas_user_t *user, if (esm_ctx->n_ebrs == 0) { emm_sap_t emm_sap; emm_sap.primitive = EMMESM_ESTABLISH_CNF; - emm_sap.u.emm_esm.u.establish.is_attached = FALSE; + emm_sap.u.emm_esm.u.establish.is_attached = false; (void) emm_sap_send(user, &emm_sap); } /* 3GPP TS 24.301, section 6.4.4.3, 6.4.4.6 @@ -546,8 +546,8 @@ int esm_ebr_context_release(nas_user_t *user, else if (esm_ctx->emergency && (esm_ctx->n_ebrs == 1) ) { emm_sap_t emm_sap; emm_sap.primitive = EMMESM_ESTABLISH_CNF; - emm_sap.u.emm_esm.u.establish.is_attached = TRUE; - emm_sap.u.emm_esm.u.establish.is_emergency = TRUE; + emm_sap.u.emm_esm.u.establish.is_attached = true; + emm_sap.u.emm_esm.u.establish.is_emergency = true; (void) emm_sap_send(user, &emm_sap); } diff --git a/openair3/NAS/UE/ESM/esm_ebr_context.h b/openair3/NAS/UE/ESM/esm_ebr_context.h index d7dfb1da70..c72f3f0e8b 100644 --- a/openair3/NAS/UE/ESM/esm_ebr_context.h +++ b/openair3/NAS/UE/ESM/esm_ebr_context.h @@ -66,7 +66,7 @@ typedef enum { /****************** E X P O R T E D F U N C T I O N S ******************/ /****************************************************************************/ -int esm_ebr_context_create(esm_data_t *esm_data, int ueid, int pid, int ebi, int is_default, +int esm_ebr_context_create(esm_data_t *esm_data, int ueid, int pid, int ebi, bool is_default, const network_qos_t *qos, const network_tft_t *tft); int esm_ebr_context_release(nas_user_t *user, int ebi, int *pid, int *bid); diff --git a/openair3/NAS/UE/ESM/esm_main.c b/openair3/NAS/UE/ESM/esm_main.c index 288e748679..895e463726 100644 --- a/openair3/NAS/UE/ESM/esm_main.c +++ b/openair3/NAS/UE/ESM/esm_main.c @@ -96,12 +96,12 @@ void esm_main_initialize(nas_user_t *user, esm_indication_callback_t cb) for (i = 0; i < ESM_DATA_PDN_MAX + 1; i++) { esm_data->pdn[i].pid = -1; - esm_data->pdn[i].is_active = FALSE; + esm_data->pdn[i].is_active = false; esm_data->pdn[i].data = NULL; } /* Emergency bearer services indicator */ - esm_data->emergency = FALSE; + esm_data->emergency = false; /* Initialize the procedure transaction identity manager */ @@ -225,12 +225,12 @@ int esm_main_get_nb_pdns(esm_data_t *esm_data) ** Inputs: None ** ** ** ** Outputs: None ** - ** Return: TRUE if a PDN connection for emergency ** + ** Return: true if a PDN connection for emergency ** ** bearer services is established ** ** Others: None ** ** ** ***************************************************************************/ -int esm_main_has_emergency(esm_data_t *esm_data) +bool esm_main_has_emergency(esm_data_t *esm_data) { LOG_FUNC_IN; @@ -245,16 +245,16 @@ int esm_main_has_emergency(esm_data_t *esm_data) ** ** ** Inputs: cid: PDN connection identifier ** ** ** - ** Outputs: state: TRUE if the current state of the PDN con- ** - ** nection is ACTIVE; FALSE otherwise. ** - ** Return: TRUE if the specified PDN connection has a ** - ** PDN context defined; FALSE if no any PDN ** + ** Outputs: state: true if the current state of the PDN con- ** + ** nection is ACTIVE; false otherwise. ** + ** Return: true if the specified PDN connection has a ** + ** PDN context defined; false if no any PDN ** ** context has been defined for the specified ** ** connection. ** ** Others: None ** ** ** ***************************************************************************/ -int esm_main_get_pdn_status(nas_user_t *user, int cid, int *state) +bool esm_main_get_pdn_status(nas_user_t *user, int cid, bool *state) { LOG_FUNC_IN; @@ -263,14 +263,14 @@ int esm_main_get_pdn_status(nas_user_t *user, int cid, int *state) esm_ebr_data_t *esm_ebr_data = user-> esm_ebr_data; if (pid >= ESM_DATA_PDN_MAX) { - return (FALSE); + return (false); } else if (pid != esm_data->pdn[pid].pid) { LOG_TRACE(WARNING, "ESM-MAIN - PDN connection %d is not defined", cid); - return (FALSE); + return (false); } else if (esm_data->pdn[pid].data == NULL) { LOG_TRACE(ERROR, "ESM-MAIN - PDN connection %d has not been allocated", cid); - return (FALSE); + return (false); } if (esm_data->pdn[pid].data->bearer[0] != NULL) { @@ -281,7 +281,7 @@ int esm_main_get_pdn_status(nas_user_t *user, int cid, int *state) } /* The PDN connection has not been activated yet */ - LOG_FUNC_RETURN (TRUE); + LOG_FUNC_RETURN (true); } /**************************************************************************** @@ -301,7 +301,7 @@ int esm_main_get_pdn_status(nas_user_t *user, int cid, int *state) ** ** ***************************************************************************/ int esm_main_get_pdn(esm_data_t *esm_data, int cid, int *type, const char **apn, - int *is_emergency, int *is_active) + bool *is_emergency, bool *is_active) { LOG_FUNC_IN; diff --git a/openair3/NAS/UE/ESM/esm_main.h b/openair3/NAS/UE/ESM/esm_main.h index 6e6ecc0db4..ca8679c5b7 100644 --- a/openair3/NAS/UE/ESM/esm_main.h +++ b/openair3/NAS/UE/ESM/esm_main.h @@ -69,10 +69,9 @@ void esm_main_cleanup(esm_data_t *esm_data); /* User's getter for PDN connections and EPS bearer contexts */ int esm_main_get_nb_pdns_max(esm_data_t *esm_data); int esm_main_get_nb_pdns(esm_data_t *esm_data); -int esm_main_has_emergency(esm_data_t *esm_data); -int esm_main_get_pdn_status(nas_user_t *user, int cid, int *state); -int esm_main_get_pdn(esm_data_t *esm_data, int cid, int *type, const char **apn, int *is_emergency, - int *is_active); +bool esm_main_has_emergency(esm_data_t *esm_data); +bool esm_main_get_pdn_status(nas_user_t *user, int cid, bool *state); +int esm_main_get_pdn(esm_data_t *esm_data, int cid, int *type, const char **apn, bool *is_emergency, bool *is_active); int esm_main_get_pdn_addr(esm_data_t *esm_data, int cid, const char **ipv4addr, const char **ipv6addr); diff --git a/openair3/NAS/UE/ESM/esm_proc.h b/openair3/NAS/UE/ESM/esm_proc.h index 941cfa620d..42a925327e 100644 --- a/openair3/NAS/UE/ESM/esm_proc.h +++ b/openair3/NAS/UE/ESM/esm_proc.h @@ -79,7 +79,7 @@ typedef enum { * Type of the ESM procedure callback executed when requested by the UE * or initiated by the network */ -typedef int (*esm_proc_procedure_t) (nas_user_t *user, int, int, OctetString *, int); +typedef int (*esm_proc_procedure_t) (nas_user_t *user, bool, int, OctetString *, bool); /* EPS bearer level QoS parameters */ typedef network_qos_t esm_proc_qos_t; @@ -113,8 +113,7 @@ typedef struct { * -------------------------------------------------------------------------- */ int esm_proc_status_ind(int pti, int ebi, int *esm_cause); -int esm_proc_status(nas_user_t *user, int is_standalone, int pti, OctetString *msg, - int sent_by_ue); +int esm_proc_status(nas_user_t *user, bool is_standalone, int pti, OctetString *msg, bool sent_by_ue); /* @@ -123,10 +122,10 @@ int esm_proc_status(nas_user_t *user, int is_standalone, int pti, OctetString *m * -------------------------------------------------------------------------- */ int esm_proc_pdn_connectivity(nas_user_t *user, int cid, int to_define, - esm_proc_pdn_type_t pdn_type, const OctetString *apn, int is_emergency, + esm_proc_pdn_type_t pdn_type, const OctetString *apn, bool is_emergency, unsigned int *pti); -int esm_proc_pdn_connectivity_request(nas_user_t *user, int is_standalone, int pti, - OctetString *msg, int sent_by_ue); +int esm_proc_pdn_connectivity_request(nas_user_t *user, bool is_standalone, int pti, + OctetString *msg, bool sent_by_ue); int esm_proc_pdn_connectivity_accept(nas_user_t *user, int pti, esm_proc_pdn_type_t pdn_type, const OctetString *pdn_address, const OctetString *apn, int *esm_cause); int esm_proc_pdn_connectivity_reject(nas_user_t *user, int pti, int *esm_cause); @@ -140,8 +139,8 @@ int esm_proc_pdn_connectivity_failure(nas_user_t *user, int is_pending); * -------------------------------------------------------------------------- */ int esm_proc_pdn_disconnect(esm_data_t *esm_data, int cid, unsigned int *pti, unsigned int *ebi); -int esm_proc_pdn_disconnect_request(nas_user_t *user, int is_standalone, int pti, - OctetString *msg, int sent_by_ue); +int esm_proc_pdn_disconnect_request(nas_user_t *user, bool is_standalone, int pti, + OctetString *msg, bool sent_by_ue); int esm_proc_pdn_disconnect_accept(esm_pt_data_t *esm_pt_data, int pti, int *esm_cause); int esm_proc_pdn_disconnect_reject(nas_user_t *user, int pti, int *esm_cause); @@ -157,10 +156,10 @@ int esm_proc_default_eps_bearer_context_request(nas_user_t *user, int pid, int e int esm_proc_default_eps_bearer_context_complete(default_eps_bearer_context_data_t *default_eps_bearer_context_data); int esm_proc_default_eps_bearer_context_failure(nas_user_t *user); -int esm_proc_default_eps_bearer_context_accept(nas_user_t *user, int is_standalone, int ebi, - OctetString *msg, int ue_triggered); -int esm_proc_default_eps_bearer_context_reject(nas_user_t *user, int is_standalone, int ebi, - OctetString *msg, int ue_triggered); +int esm_proc_default_eps_bearer_context_accept(nas_user_t *user, bool is_standalone, int ebi, + OctetString *msg, bool ue_triggered); +int esm_proc_default_eps_bearer_context_reject(nas_user_t *user, bool is_standalone, int ebi, + OctetString *msg, bool ue_triggered); /* * -------------------------------------------------------------------------- @@ -171,10 +170,10 @@ int esm_proc_default_eps_bearer_context_reject(nas_user_t *user, int is_standalo int esm_proc_dedicated_eps_bearer_context_request(nas_user_t *user, int ebi, int default_ebi, const esm_proc_qos_t *qos, const esm_proc_tft_t *tft, int *esm_cause); -int esm_proc_dedicated_eps_bearer_context_accept(nas_user_t *user, int is_standalone, int ebi, - OctetString *msg, int ue_triggered); -int esm_proc_dedicated_eps_bearer_context_reject(nas_user_t *user, int is_standalone, int ebi, - OctetString *msg, int ue_triggered); +int esm_proc_dedicated_eps_bearer_context_accept(nas_user_t *user, bool is_standalone, int ebi, + OctetString *msg, bool ue_triggered); +int esm_proc_dedicated_eps_bearer_context_reject(nas_user_t *user, bool is_standalone, int ebi, + OctetString *msg, bool ue_triggered); /* * -------------------------------------------------------------------------- @@ -182,11 +181,11 @@ int esm_proc_dedicated_eps_bearer_context_reject(nas_user_t *user, int is_standa * -------------------------------------------------------------------------- */ -int esm_proc_eps_bearer_context_deactivate(nas_user_t *user, int is_local, int ebi, int *pid, +int esm_proc_eps_bearer_context_deactivate(nas_user_t *user, bool is_local, int ebi, int *pid, int *bid); int esm_proc_eps_bearer_context_deactivate_request(nas_user_t *user, int ebi, int *esm_cause); -int esm_proc_eps_bearer_context_deactivate_accept(nas_user_t *user, int is_standalone, int ebi, - OctetString *msg, int ue_triggered); +int esm_proc_eps_bearer_context_deactivate_accept(nas_user_t *user, bool is_standalone, int ebi, + OctetString *msg, bool ue_triggered); #endif /* __ESM_PROC_H__*/ diff --git a/openair3/NAS/UE/ESM/esm_pt.c b/openair3/NAS/UE/ESM/esm_pt.c index f253291fd9..d9f593fb57 100644 --- a/openair3/NAS/UE/ESM/esm_pt.c +++ b/openair3/NAS/UE/ESM/esm_pt.c @@ -482,11 +482,11 @@ int esm_pt_get_pending_pti(esm_pt_data_t *esm_pt_data, esm_pt_state status) ** Inputs: pti: The identity of the procedure transaction ** ** ** ** Outputs: None ** - ** Return: TRUE, FALSE ** + ** Return: true, false ** ** Others: None ** ** ** ***************************************************************************/ -int esm_pt_is_not_in_use(esm_pt_data_t *esm_pt_data, int pti) +bool esm_pt_is_not_in_use(esm_pt_data_t *esm_pt_data, int pti) { return ( (pti == ESM_PT_UNASSIGNED) || (esm_pt_data->context[pti - ESM_PTI_MIN] == NULL) || @@ -504,11 +504,11 @@ int esm_pt_is_not_in_use(esm_pt_data_t *esm_pt_data, int pti) ** Others: None ** ** ** ** Outputs: None ** - ** Return: TRUE, FALSE ** + ** Return: true, false ** ** Others: None ** ** ** ***************************************************************************/ -int esm_pt_is_reserved(int pti) +bool esm_pt_is_reserved(int pti) { return ( (pti != ESM_PT_UNASSIGNED) && (pti > ESM_PTI_MAX) ); } diff --git a/openair3/NAS/UE/ESM/esm_pt.h b/openair3/NAS/UE/ESM/esm_pt.h index 3179e0f47b..b0c62253ab 100644 --- a/openair3/NAS/UE/ESM/esm_pt.h +++ b/openair3/NAS/UE/ESM/esm_pt.h @@ -64,7 +64,7 @@ Description Defines functions used to handle ESM procedure transactions. /****************** E X P O R T E D F U N C T I O N S ******************/ /****************************************************************************/ -int esm_pt_is_reserved(int pti); +bool esm_pt_is_reserved(int pti); esm_pt_data_t *esm_pt_initialize(void); @@ -79,6 +79,6 @@ int esm_pt_set_status(esm_pt_data_t *esm_pt_data, int pti, esm_pt_state status); esm_pt_state esm_pt_get_status(esm_pt_data_t *esm_pt_data, int pti); int esm_pt_get_pending_pti(esm_pt_data_t *esm_pt_data, esm_pt_state status); -int esm_pt_is_not_in_use(esm_pt_data_t *esm_pt_data, int pti); +bool esm_pt_is_not_in_use(esm_pt_data_t *esm_pt_data, int pti); #endif /* __ESM_PT_H__*/ diff --git a/openair3/NAS/UE/UEprocess.c b/openair3/NAS/UE/UEprocess.c index 7b9a1be422..a3a1c9c79b 100644 --- a/openair3/NAS/UE/UEprocess.c +++ b/openair3/NAS/UE/UEprocess.c @@ -205,7 +205,7 @@ static void *_nas_user_mngr(void *args) LOG_FUNC_IN; pthread_setname_np( pthread_self(), "nas_user_mngr"); - int exit_loop = FALSE; + bool exit_loop = false; int *fd = (int *) args; @@ -251,7 +251,7 @@ static void *_nas_network_mngr(void *args) LOG_TRACE (INFO, "UE-MAIN - Network connection manager started (%d)", *fd); /* Network receiving loop */ - while (TRUE) { + while (true) { /* Read the network data message */ bytes = network_api_read_data (*fd); diff --git a/openair3/NAS/UE/nas_proc.c b/openair3/NAS/UE/nas_proc.c index 9350590788..41230696a4 100644 --- a/openair3/NAS/UE/nas_proc.c +++ b/openair3/NAS/UE/nas_proc.c @@ -64,8 +64,8 @@ Description NAS procedure call manager #define NAS_PROC_RSRP_UNKNOWN 255 -static int _nas_proc_activate(nas_user_t *user, int cid, int apply_to_all); -static int _nas_proc_deactivate(nas_user_t *user, int cid, int apply_to_all); +static int _nas_proc_activate(nas_user_t *user, int cid, bool apply_to_all); +static int _nas_proc_deactivate(nas_user_t *user, int cid, bool apply_to_all); /****************************************************************************/ /****************** E X P O R T E D F U N C T I O N S ******************/ @@ -93,7 +93,7 @@ void nas_proc_initialize(nas_user_t *user, emm_indication_callback_t emm_cb, LOG_FUNC_IN; /* Initialize local NAS data */ - user->proc.EPS_capability_status = FALSE; + user->proc.EPS_capability_status = false; user->proc.rsrq = NAS_PROC_RSRQ_UNKNOWN; user->proc.rsrp = NAS_PROC_RSRP_UNKNOWN; @@ -129,7 +129,7 @@ void nas_proc_cleanup(nas_user_t *user) LOG_FUNC_IN; /* Detach the UE from the EPS network */ - int rc = nas_proc_detach(user, TRUE); + int rc = nas_proc_detach(user, true); if (rc != RETURNok) { LOG_TRACE(ERROR, "NAS-PROC - Failed to detach from the network"); @@ -176,7 +176,7 @@ int nas_proc_enable_s1_mode(nas_user_t *user) * Notify the EMM procedure call manager that EPS capability * of the UE is enabled */ - user->proc.EPS_capability_status = TRUE; + user->proc.EPS_capability_status = true; emm_sap.primitive = EMMREG_S1_ENABLED; rc = emm_sap_send(user, &emm_sap); @@ -209,7 +209,7 @@ int nas_proc_disable_s1_mode(nas_user_t *user) * Notify the EMM procedure call manager that EPS capability * of the UE is disabled */ - user->proc.EPS_capability_status = FALSE; + user->proc.EPS_capability_status = false; emm_sap.primitive = EMMREG_S1_DISABLED; rc = emm_sap_send(user, &emm_sap); @@ -231,7 +231,7 @@ int nas_proc_disable_s1_mode(nas_user_t *user) ** Others: None ** ** ** ***************************************************************************/ -int nas_proc_get_eps(nas_user_t *user, int *stat) +int nas_proc_get_eps(nas_user_t *user, bool *stat) { LOG_FUNC_IN; @@ -449,7 +449,7 @@ int nas_proc_deregister(nas_user_t *user) ** Others: None ** ** ** ***************************************************************************/ -int nas_proc_get_reg_data(nas_user_t *user, int *mode, int *selected, int format, +int nas_proc_get_reg_data(nas_user_t *user, int *mode, bool *selected, int format, network_plmn_t *oper, int *AcT) { LOG_FUNC_IN; @@ -462,12 +462,12 @@ int nas_proc_get_reg_data(nas_user_t *user, int *mode, int *selected, int format if (oper_name != NULL) { /* An operator is currently selected */ - *selected = TRUE; + *selected = true; /* Get the supported Radio Access Technology */ *AcT = emm_main_get_plmn_rat(user->emm_data); } else { /* No any operator is selected */ - *selected = FALSE; + *selected = false; *AcT = NET_ACCESS_UNAVAILABLE; } @@ -558,7 +558,7 @@ int nas_proc_get_loc_info(nas_user_t *user, char *tac, char *ci, int *AcT) ** ** ** Description: Initiates a detach procedure ** ** ** - ** Inputs: switch_off: TRUE if the detach is due to UE switch-off ** + ** Inputs: switch_off: true if the detach is due to UE switch-off ** ** Others: None ** ** ** ** Outputs: None ** @@ -566,7 +566,7 @@ int nas_proc_get_loc_info(nas_user_t *user, char *tac, char *ci, int *AcT) ** Others: None ** ** ** ***************************************************************************/ -int nas_proc_detach(nas_user_t *user, int switch_off) +int nas_proc_detach(nas_user_t *user, bool switch_off) { LOG_FUNC_IN; @@ -607,7 +607,7 @@ int nas_proc_attach(nas_user_t *user) if ( !emm_main_is_attached(user->emm_data) ) { /* Initiate an Attach procedure */ emm_sap.primitive = EMMREG_ATTACH_INIT; - emm_sap.u.emm_reg.u.attach.is_emergency = FALSE; + emm_sap.u.emm_reg.u.attach.is_emergency = false; rc = emm_sap_send(user, &emm_sap); } @@ -624,16 +624,16 @@ int nas_proc_attach(nas_user_t *user) ** Others: None ** ** ** ** Outputs: None ** - ** Return: TRUE if the UE is currently attached to ** + ** Return: true if the UE is currently attached to ** ** the network ** ** Others: None ** ** ** ***************************************************************************/ -int nas_proc_get_attach_status(nas_user_t *user) +bool nas_proc_get_attach_status(nas_user_t *user) { LOG_FUNC_IN; - int is_attached = emm_main_is_attached(user->emm_data); + bool is_attached = emm_main_is_attached(user->emm_data); LOG_FUNC_RETURN (is_attached); } @@ -690,10 +690,10 @@ int nas_proc_get_pdn_status(nas_user_t *user, int *cids, int *states, int n_pdn_ /* For all PDN contexts */ for (cid = 1; (cid < n_pdn+1) && (n_defined_pdn < n_pdn_max); cid++) { /* Get the status of this PDN */ - int state = FALSE; - int is_defined = esm_main_get_pdn_status(user, cid, &state); + bool state = false; + bool is_defined = esm_main_get_pdn_status(user, cid, &state); - if (is_defined != FALSE) { + if (is_defined != false) { /* This PDN has been defined */ *(cids++) = cid; *(states++) = state; @@ -734,7 +734,7 @@ int nas_proc_get_pdn_param(esm_data_t *esm_data, int *cids, int *types, const ch /* For all PDN contexts */ for (cid = 1; (cid < n_pdn+1) && (n_defined_pdn < n_pdn_max); cid++) { - int emergency, active; + bool emergency, active; /* Get PDN connection parameters */ int rc = esm_main_get_pdn(esm_data, cid, types, apns, &emergency, &active); @@ -845,8 +845,8 @@ int nas_proc_set_pdn(nas_user_t *user, int cid, int type, const char *apn, int i esm_sap_t esm_sap; esm_sap.primitive = ESM_PDN_CONNECTIVITY_REQ; - esm_sap.is_standalone = TRUE; - esm_sap.data.pdn_connect.is_defined = FALSE; + esm_sap.is_standalone = true; + esm_sap.data.pdn_connect.is_defined = false; esm_sap.data.pdn_connect.cid = cid; esm_sap.data.pdn_connect.pdn_type = type; esm_sap.data.pdn_connect.apn = apn; @@ -882,8 +882,8 @@ int nas_proc_reset_pdn(nas_user_t *user, int cid) esm_sap_t esm_sap; esm_sap.primitive = ESM_PDN_CONNECTIVITY_REJ; - esm_sap.is_standalone = TRUE; - esm_sap.data.pdn_connect.is_defined = TRUE; + esm_sap.is_standalone = true; + esm_sap.data.pdn_connect.is_defined = true; esm_sap.data.pdn_connect.cid = cid; /* * Notify ESM that the specified PDN context has to be undefined @@ -916,7 +916,7 @@ int nas_proc_deactivate_pdn(nas_user_t *user, int cid) if (cid > 0) { /* Deactivate only the specified PDN context */ - rc = _nas_proc_deactivate(user, cid, FALSE); + rc = _nas_proc_deactivate(user, cid, false); } else { /* Do not deactivate the PDN connection established during initial * network attachment (identifier 1) */ @@ -924,7 +924,7 @@ int nas_proc_deactivate_pdn(nas_user_t *user, int cid) /* Deactivate all active PDN contexts */ while ((rc != RETURNerror) && (cid < esm_main_get_nb_pdns_max(user->esm_data)+1)) { - rc = _nas_proc_deactivate(user, cid++, TRUE); + rc = _nas_proc_deactivate(user, cid++, true); } } @@ -970,13 +970,13 @@ int nas_proc_activate_pdn(nas_user_t *user, int cid) if (rc != RETURNerror) { if (cid > 0) { /* Activate only the specified PDN context */ - rc = _nas_proc_activate(user, cid, FALSE); + rc = _nas_proc_activate(user, cid, false); } else { cid = 1; /* Activate all defined PDN contexts */ while ((rc != RETURNerror) && (cid < esm_main_get_nb_pdns_max(user->esm_data)+1)) { - rc = _nas_proc_activate(user, cid++, TRUE); + rc = _nas_proc_activate(user, cid++, true); } } } @@ -1177,7 +1177,7 @@ int nas_proc_ul_transfer_cnf(nas_user_t *user) */ emm_sap.primitive = EMMAS_DATA_IND; emm_sap.u.emm_as.u.data.ueid = user->ueid; - emm_sap.u.emm_as.u.data.delivered = TRUE; + emm_sap.u.emm_as.u.data.delivered = true; emm_sap.u.emm_as.u.data.NASmsg.length = 0; rc = emm_sap_send(user, &emm_sap); @@ -1214,7 +1214,7 @@ int nas_proc_ul_transfer_rej(nas_user_t *user) */ emm_sap.primitive = EMMAS_DATA_IND; emm_sap.u.emm_as.u.data.ueid = user->ueid; - emm_sap.u.emm_as.u.data.delivered = FALSE; + emm_sap.u.emm_as.u.data.delivered = false; emm_sap.u.emm_as.u.data.NASmsg.length = 0; rc = emm_sap_send(user, &emm_sap); @@ -1251,7 +1251,7 @@ int nas_proc_dl_transfer_ind(nas_user_t *user, const Byte_t *data, uint32_t len) */ emm_sap.primitive = EMMAS_DATA_IND; emm_sap.u.emm_as.u.data.ueid = user->ueid; - emm_sap.u.emm_as.u.data.delivered = TRUE; + emm_sap.u.emm_as.u.data.delivered = true; emm_sap.u.emm_as.u.data.NASmsg.length = len; emm_sap.u.emm_as.u.data.NASmsg.value = (uint8_t *)data; rc = emm_sap_send(user, &emm_sap); @@ -1274,7 +1274,7 @@ int nas_proc_dl_transfer_ind(nas_user_t *user, const Byte_t *data, uint32_t len) ** ** ** Inputs: cid: Identifier of the PDN context used to es- ** ** tablished connectivity to specified PDN ** - ** apply_to_all: TRUE if the PDN connectivity procedure is ** + ** apply_to_all: true if the PDN connectivity procedure is ** ** initiated to establish connectivity to all ** ** defined PDNs ** ** Others: None ** @@ -1284,12 +1284,12 @@ int nas_proc_dl_transfer_ind(nas_user_t *user, const Byte_t *data, uint32_t len) ** Others: None ** ** ** ***************************************************************************/ -static int _nas_proc_activate(nas_user_t *user, int cid, int apply_to_all) +static int _nas_proc_activate(nas_user_t *user, int cid, bool apply_to_all) { LOG_FUNC_IN; int rc; - int active = FALSE; + bool active = false; esm_sap_t esm_sap; @@ -1332,8 +1332,8 @@ static int _nas_proc_activate(nas_user_t *user, int cid, int apply_to_all) * for the specified PDN */ esm_sap.primitive = ESM_PDN_CONNECTIVITY_REQ; - esm_sap.is_standalone = TRUE; - esm_sap.data.pdn_connect.is_defined = TRUE; + esm_sap.is_standalone = true; + esm_sap.data.pdn_connect.is_defined = true; esm_sap.data.pdn_connect.cid = cid; rc = esm_sap_send(user, &esm_sap); @@ -1347,7 +1347,7 @@ static int _nas_proc_activate(nas_user_t *user, int cid, int apply_to_all) ** Description: Initiates a PDN disconnect procedure ** ** ** ** Inputs: cid: Identifier of the PDN context ** - ** apply_to_all: TRUE if the PDN disconnect procedure is ** + ** apply_to_all: true if the PDN disconnect procedure is ** ** initiated to request disconnection from ** ** all active PDNs ** ** Others: None ** @@ -1357,15 +1357,15 @@ static int _nas_proc_activate(nas_user_t *user, int cid, int apply_to_all) ** Others: None ** ** ** ***************************************************************************/ -static int _nas_proc_deactivate(nas_user_t *user, int cid, int apply_to_all) +static int _nas_proc_deactivate(nas_user_t *user, int cid, bool apply_to_all) { LOG_FUNC_IN; int rc; int pdn_type; const char *apn; - int emergency = FALSE; - int active = FALSE; + bool emergency = false; + bool active = false; /* Get PDN context parameters */ rc = esm_main_get_pdn(user->esm_data, cid, &pdn_type, &apn, &emergency, &active); diff --git a/openair3/NAS/UE/nas_proc.h b/openair3/NAS/UE/nas_proc.h index 4e653549ae..bd88691de8 100644 --- a/openair3/NAS/UE/nas_proc.h +++ b/openair3/NAS/UE/nas_proc.h @@ -74,7 +74,7 @@ void nas_proc_cleanup(nas_user_t *user); int nas_proc_enable_s1_mode(nas_user_t *user); int nas_proc_disable_s1_mode(nas_user_t *user); -int nas_proc_get_eps(nas_user_t *user, int *stat); +int nas_proc_get_eps(nas_user_t *user, bool *stat); int nas_proc_get_imsi(emm_data_t *emm_data, char *imsi_str); int nas_proc_get_msisdn(nas_user_t *user, char *msisdn_str, int *ton_npi); @@ -83,16 +83,16 @@ int nas_proc_get_signal_quality(nas_user_t *user, int *rsrq, int *rsrp); int nas_proc_register(nas_user_t *user, int mode, int format, const network_plmn_t *oper, int AcT); int nas_proc_deregister(nas_user_t *user); -int nas_proc_get_reg_data(nas_user_t *user, int *mode, int *selected, int format, +int nas_proc_get_reg_data(nas_user_t *user, int *mode, bool *selected, int format, network_plmn_t *oper, int *AcT); int nas_proc_get_oper_list(nas_user_t *user, const char **oper_list); int nas_proc_get_reg_status(nas_user_t *user, int *stat); int nas_proc_get_loc_info(nas_user_t *user, char *tac, char *ci, int *AcT); -int nas_proc_detach(nas_user_t *user, int switch_off); +int nas_proc_detach(nas_user_t *user, bool switch_off); int nas_proc_attach(nas_user_t *user); -int nas_proc_get_attach_status(nas_user_t *user); +bool nas_proc_get_attach_status(nas_user_t *user); int nas_proc_reset_pdn(nas_user_t *user, int cid); int nas_proc_set_pdn(nas_user_t *user, int cid, int type, const char *apn, int ipv4_addr, diff --git a/openair3/NAS/UE/nas_proc_defs.h b/openair3/NAS/UE/nas_proc_defs.h index 1ce2bfd929..09cf8e834e 100644 --- a/openair3/NAS/UE/nas_proc_defs.h +++ b/openair3/NAS/UE/nas_proc_defs.h @@ -1,12 +1,14 @@ #ifndef _NAS_PROC_DEFS_H #define _NAS_PROC_DEFS_H +#include + /* * Local NAS data */ typedef struct { /* EPS capibility status */ - int EPS_capability_status; + bool EPS_capability_status; /* Reference signal received quality */ int rsrq; /* Reference signal received power */ diff --git a/openair3/NAS/UE/nas_ue_task.c b/openair3/NAS/UE/nas_ue_task.c index a94445349c..34bf6cb3ad 100644 --- a/openair3/NAS/UE/nas_ue_task.c +++ b/openair3/NAS/UE/nas_ue_task.c @@ -43,10 +43,10 @@ uint16_t ue_idx_standalone = 0xFFFF; char *make_port_str_from_ueid(const char *base_port_str, int ueid); -static int nas_ue_process_events(nas_user_container_t *users, struct epoll_event *events, int nb_events) +static bool nas_ue_process_events(nas_user_container_t *users, struct epoll_event *events, int nb_events) { int event; - int exit_loop = FALSE; + bool exit_loop = false; LOG_I(NAS, "[UE] Received %d events\n", nb_events); @@ -310,7 +310,7 @@ void *nas_ue_task(void *args_p) nb_events = itti_get_events(TASK_NAS_UE, &events); if ((nb_events > 0) && (events != NULL)) { - if (nas_ue_process_events(users, events, nb_events) == TRUE) { + if (nas_ue_process_events(users, events, nb_events) == true) { LOG_E(NAS, "[UE] Received exit loop\n"); } } diff --git a/openair3/NAS/UE/nas_user.c b/openair3/NAS/UE/nas_user.c index d3467eddd5..56e41e4610 100644 --- a/openair3/NAS/UE/nas_user.c +++ b/openair3/NAS/UE/nas_user.c @@ -187,10 +187,10 @@ void nas_user_initialize(nas_user_t *user, emm_indication_callback_t emm_cb, ** from which data have been received ** ** Others: None ** ** ** - ** Outputs: Return: FALSE, TRUE ** + ** Outputs: Return: false, true ** ** ** ***************************************************************************/ -int nas_user_receive_and_process(nas_user_t *user, char *message) +bool nas_user_receive_and_process(nas_user_t *user, char *message) { LOG_FUNC_IN; @@ -212,13 +212,13 @@ int nas_user_receive_and_process(nas_user_t *user, char *message) * exit from the receiving loop */ LOG_TRACE (ERROR, "UE-MAIN - " "Failed to read data from the user application layer"); - LOG_FUNC_RETURN(TRUE); + LOG_FUNC_RETURN(true); } } if (bytes == 0) { /* A signal was caught before any data were available */ - LOG_FUNC_RETURN(FALSE); + LOG_FUNC_RETURN(false); } /* Decode the user data message */ @@ -268,12 +268,12 @@ int nas_user_receive_and_process(nas_user_t *user, char *message) * exit from the receiving loop */ LOG_TRACE (ERROR, "UE-MAIN - " "Failed to send data to the user application layer"); - LOG_FUNC_RETURN(TRUE); + LOG_FUNC_RETURN(true); } } } - LOG_FUNC_RETURN(FALSE); + LOG_FUNC_RETURN(false); } /**************************************************************************** @@ -989,7 +989,7 @@ static int _nas_user_proc_cops(nas_user_t *user, const at_command_t *data) char oper_buffer[NET_FORMAT_MAX_SIZE], *oper = oper_buffer; memset(oper, 0, NET_FORMAT_MAX_SIZE); - int oper_is_selected; + bool oper_is_selected; at_response->id = data->id; at_response->type = data->type; @@ -1266,7 +1266,7 @@ static int _nas_user_proc_cgatt(nas_user_t *user, const at_command_t *data) if (data->command.cgatt.state == AT_CGATT_ATTACHED) { ret_code = nas_proc_attach(user); } else if (data->command.cgatt.state == AT_CGATT_DETACHED) { - ret_code = nas_proc_detach(user, FALSE); + ret_code = nas_proc_detach(user, false); } if (ret_code != RETURNok) { @@ -1284,7 +1284,7 @@ static int _nas_user_proc_cgatt(nas_user_t *user, const at_command_t *data) /* * Read command returns the current EPS service state. */ - if (nas_proc_get_attach_status(user) != TRUE) { + if (nas_proc_get_attach_status(user) != true) { cgatt->state = AT_CGATT_DETACHED; } else { cgatt->state = AT_CGATT_ATTACHED; @@ -1821,7 +1821,7 @@ static int _nas_user_proc_cgdcont(nas_user_t *user, const at_command_t *data) int emergency = AT_CGDCONT_EBS_DEFAULT; int p_cscf = AT_CGDCONT_PCSCF_DEFAULT; int im_cn_signalling = AT_CGDCONT_IM_CM_DEFAULT; - int reset_pdn = TRUE; + bool reset_pdn = true; at_response->id = data->id; at_response->type = data->type; @@ -1870,7 +1870,7 @@ static int _nas_user_proc_cgdcont(nas_user_t *user, const at_command_t *data) break; } - reset_pdn = FALSE; + reset_pdn = false; } if (data->mask & AT_CGDCONT_APN_MASK) { diff --git a/openair3/NAS/UE/nas_user.h b/openair3/NAS/UE/nas_user.h index 1ded438ddd..63920540d4 100644 --- a/openair3/NAS/UE/nas_user.h +++ b/openair3/NAS/UE/nas_user.h @@ -63,7 +63,7 @@ Description NAS procedure functions triggered by the user void nas_user_initialize(nas_user_t *user, emm_indication_callback_t emm_cb, esm_indication_callback_t esm_cb, const char *version); -int nas_user_receive_and_process(nas_user_t *user, char *message); +bool nas_user_receive_and_process(nas_user_t *user, char *message); int nas_user_process_data(nas_user_t *user, const void *data); diff --git a/openair3/NGAP/ngap_common.h b/openair3/NGAP/ngap_common.h index 60f7beacd0..a550b6e436 100644 --- a/openair3/NGAP/ngap_common.h +++ b/openair3/NGAP/ngap_common.h @@ -102,13 +102,6 @@ # error "You are compiling ngap with the wrong version of ASN1C" #endif -#ifndef FALSE -# define FALSE (0) -#endif -#ifndef TRUE -# define TRUE (!FALSE) -#endif - #define NGAP_UE_ID_FMT "0x%06"PRIX32 extern int asn_debug; diff --git a/openair3/S1AP/s1ap_common.h b/openair3/S1AP/s1ap_common.h index 3c07f92a7f..d383b622b6 100644 --- a/openair3/S1AP/s1ap_common.h +++ b/openair3/S1AP/s1ap_common.h @@ -61,13 +61,6 @@ # error "You are compiling s1ap with the wrong version of ASN1C" #endif -#ifndef FALSE -# define FALSE (0) -#endif -#ifndef TRUE -# define TRUE (!FALSE) -#endif - #define S1AP_UE_ID_FMT "0x%06"PRIX32 extern int asn_debug; diff --git a/openair3/S1AP/s1ap_eNB_trace.c b/openair3/S1AP/s1ap_eNB_trace.c index 695eeb4ef8..de84682ec1 100644 --- a/openair3/S1AP/s1ap_eNB_trace.c +++ b/openair3/S1AP/s1ap_eNB_trace.c @@ -115,7 +115,7 @@ int s1ap_eNB_handle_trace_start(uint32_t assoc_id, container = &pdu->choice.initiatingMessage.value.choice.TraceStart; S1AP_FIND_PROTOCOLIE_BY_ID(S1AP_TraceStartIEs_t, ie, container, - S1AP_ProtocolIE_ID_id_eNB_UE_S1AP_ID, TRUE); + S1AP_ProtocolIE_ID_id_eNB_UE_S1AP_ID, true); mme_ref_p = s1ap_eNB_get_MME(NULL, assoc_id, 0); DevAssert(mme_ref_p != NULL); if (ie != NULL) { diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index a6bda28b57..3626e0b8ed 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -21,7 +21,7 @@ extern "C" { #include "openair2/SDAP/nr_sdap/nr_sdap.h" //#include -static boolean_t is_gnb = false; +static bool is_gnb = false; #pragma pack(1) @@ -969,7 +969,7 @@ static int Gtpv1uHandleGpdu(int h, int offset = sizeof(Gtpv1uMsgHeaderT); uint8_t qfi = 0; - boolean_t rqi = FALSE; + bool rqi = false; uint32_t NR_PDCP_PDU_SN = 0; /* if E, S, or PN is set then there are 4 more bytes of header */ diff --git a/openair3/ocp-gtpu/gtp_itf.h b/openair3/ocp-gtpu/gtp_itf.h index dd52481729..51a47e8c82 100644 --- a/openair3/ocp-gtpu/gtp_itf.h +++ b/openair3/ocp-gtpu/gtp_itf.h @@ -8,32 +8,30 @@ extern "C" { #endif -typedef boolean_t (*gtpCallback)( - protocol_ctxt_t *ctxt_pP, - const srb_flag_t srb_flagP, - const rb_id_t rb_idP, - const mui_t muiP, - const confirm_t confirmP, - const sdu_size_t sdu_buffer_sizeP, - unsigned char *const sdu_buffer_pP, - const pdcp_transmission_mode_t modeP, - const uint32_t *sourceL2Id, - const uint32_t *destinationL2Id); +typedef bool (*gtpCallback)(protocol_ctxt_t *ctxt_pP, + const srb_flag_t srb_flagP, + const rb_id_t rb_idP, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_buffer_sizeP, + unsigned char *const sdu_buffer_pP, + const pdcp_transmission_mode_t modeP, + const uint32_t *sourceL2Id, + const uint32_t *destinationL2Id); -typedef boolean_t (*gtpCallbackSDAP)( - protocol_ctxt_t *ctxt_pP, - const srb_flag_t srb_flagP, - const rb_id_t rb_idP, - const mui_t muiP, - const confirm_t confirmP, - const sdu_size_t sdu_buffer_sizeP, - unsigned char *const sdu_buffer_pP, - const pdcp_transmission_mode_t modeP, - const uint32_t *sourceL2Id, - const uint32_t *destinationL2Id, - const uint8_t qfi, - const boolean_t rqi, - const int pdusession_id); +typedef bool (*gtpCallbackSDAP)(protocol_ctxt_t *ctxt_pP, + const srb_flag_t srb_flagP, + const rb_id_t rb_idP, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_buffer_sizeP, + unsigned char *const sdu_buffer_pP, + const pdcp_transmission_mode_t modeP, + const uint32_t *sourceL2Id, + const uint32_t *destinationL2Id, + const uint8_t qfi, + const bool rqi, + const int pdusession_id); typedef struct openAddr_s { char originHost[HOST_NAME_MAX]; diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h index 78acc373ee..0f11447bf4 100644 --- a/targets/ARCH/COMMON/common_lib.h +++ b/targets/ARCH/COMMON/common_lib.h @@ -380,7 +380,7 @@ struct openair0_device_t { @param buff Buffer which holds the samples (2 dimensional) @param nsamps number of samples to be sent @param number of antennas - @param flags flags must be set to TRUE if timestamp parameter needs to be applied + @param flags flags must be set to true if timestamp parameter needs to be applied */ int (*trx_write_func)(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int antenna_id, int flags); @@ -390,7 +390,7 @@ struct openair0_device_t { @param buff Buffer which holds the samples (1 dimensional) @param nsamps number of samples to be sent @param antenna_id index of the antenna if the device has multiple anteannas - @param flags flags must be set to TRUE if timestamp parameter needs to be applied + @param flags flags must be set to true if timestamp parameter needs to be applied */ int (*trx_write_func2)(openair0_device *device, openair0_timestamp timestamp, void *buff, int nsamps,int antenna_id, int flags); diff --git a/targets/ARCH/IRIS/USERSPACE/LIB/iris_lib.cpp b/targets/ARCH/IRIS/USERSPACE/LIB/iris_lib.cpp index 1273097f3b..47bbadfe28 100644 --- a/targets/ARCH/IRIS/USERSPACE/LIB/iris_lib.cpp +++ b/targets/ARCH/IRIS/USERSPACE/LIB/iris_lib.cpp @@ -134,7 +134,7 @@ static void trx_iris_end(openair0_device *device) { @param buff Buffer which holds the samples @param nsamps number of samples to be sent @param antenna_id index of the antenna if the device has multiple anteannas - @param flags flags must be set to TRUE if timestamp parameter needs to be applied + @param flags flags must be set to true if timestamp parameter needs to be applied */ diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp index 8976284345..c68a36e799 100644 --- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp +++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp @@ -331,7 +331,7 @@ static void trx_usrp_end(openair0_device *device) { @param buff Buffer which holds the samples @param nsamps number of samples to be sent @param antenna_id index of the antenna if the device has multiple antennas - @param flags flags must be set to TRUE if timestamp parameter needs to be applied + @param flags flags must be set to true if timestamp parameter needs to be applied */ static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, @@ -352,7 +352,7 @@ static int trx_usrp_write(openair0_device *device, AssertFatal( MAX_WRITE_THREAD_BUFFER_SIZE >= cc,"Do not support more than %d cc number\n", MAX_WRITE_THREAD_BUFFER_SIZE); - boolean_t first_packet_state=false,last_packet_state=false; + bool first_packet_state=false,last_packet_state=false; if (flags_lsb == 2) { // start of burst // s->tx_md.start_of_burst = true; @@ -481,7 +481,7 @@ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_BEAM_SWITCHI @param buff Buffer which holds the samples @param nsamps number of samples to be sent @param antenna_id index of the antenna if the device has multiple antennas - @param flags flags must be set to TRUE if timestamp parameter needs to be applied + @param flags flags must be set to true if timestamp parameter needs to be applied */ void *trx_usrp_write_thread(void * arg){ int ret=0; diff --git a/targets/ARCH/iqplayer/iqplayer_lib.c b/targets/ARCH/iqplayer/iqplayer_lib.c index b62c1935d3..f6578d6e9a 100644 --- a/targets/ARCH/iqplayer/iqplayer_lib.c +++ b/targets/ARCH/iqplayer/iqplayer_lib.c @@ -158,7 +158,7 @@ static void trx_iqplayer_end(openair0_device *device) { @param buff Buffer which holds the samples @param nsamps number of samples to be sent @param antenna_id index of the antenna if the device has multiple antennas - @param flags flags must be set to TRUE if timestamp parameter needs to be applied + @param flags flags must be set to true if timestamp parameter needs to be applied */ static int trx_iqplayer_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) { struct timespec req; diff --git a/targets/ARCH/rfsimulator/stored_node.c b/targets/ARCH/rfsimulator/stored_node.c index cf025680cd..17ab3cb734 100644 --- a/targets/ARCH/rfsimulator/stored_node.c +++ b/targets/ARCH/rfsimulator/stored_node.c @@ -187,7 +187,7 @@ int main(int argc, char *argv[]) { } uint64_t typeStamp=ENB_MAGICDL; - boolean_t raw=false; + bool raw = false; if ( argc == 5 ) { raw=true; diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index a3048995a5..3d62d5c19a 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -231,9 +231,9 @@ static inline int rxtx(PHY_VARS_eNB *eNB, dlsch_ue_select_tbl_in_use = !dlsch_ue_select_tbl_in_use; // L2-emulator can work only one eNB. // memcpy(&pre_scd_eNB_UE_stats,&RC.mac[ru->eNB_list[0]->Mod_id]->UE_info.eNB_UE_stats, sizeof(eNB_UE_STATS)*MAX_NUM_CCs*NUMBER_OF_UE_MAX); - // memcpy(&pre_scd_activeUE, &RC.mac[ru->eNB_list[0]->Mod_id]->UE_info.active, sizeof(boolean_t)*NUMBER_OF_UE_MAX); + // memcpy(&pre_scd_activeUE, &RC.mac[ru->eNB_list[0]->Mod_id]->UE_info.active, sizeof(bool)*NUMBER_OF_UE_MAX); memcpy(&pre_scd_eNB_UE_stats,&RC.mac[0]->UE_info.eNB_UE_stats, sizeof(eNB_UE_STATS)*MAX_NUM_CCs*NUMBER_OF_UE_MAX); - memcpy(&pre_scd_activeUE, &RC.mac[0]->UE_info.active, sizeof(boolean_t)*NUMBER_OF_UE_MAX); + memcpy(&pre_scd_activeUE, &RC.mac[0]->UE_info.active, sizeof(bool)*NUMBER_OF_UE_MAX); AssertFatal((ret= pthread_mutex_lock(&ru->proc.mutex_pre_scd))==0,"[eNB] error locking proc mutex for eNB pre scd, return %d\n",ret); ru->proc.instance_pre_scd++; diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index 836709b473..a7a0d2de32 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -1834,7 +1834,7 @@ static void *ru_thread( void *param ) { new_dlsch_ue_select_tbl_in_use = dlsch_ue_select_tbl_in_use; dlsch_ue_select_tbl_in_use = !dlsch_ue_select_tbl_in_use; memcpy(&pre_scd_eNB_UE_stats,&RC.mac[ru->eNB_list[0]->Mod_id]->UE_info.eNB_UE_stats, sizeof(eNB_UE_STATS)*MAX_NUM_CCs*NUMBER_OF_UE_MAX); - memcpy(&pre_scd_activeUE, &RC.mac[ru->eNB_list[0]->Mod_id]->UE_info.active, sizeof(boolean_t)*NUMBER_OF_UE_MAX); + memcpy(&pre_scd_activeUE, &RC.mac[ru->eNB_list[0]->Mod_id]->UE_info.active, sizeof(bool)*NUMBER_OF_UE_MAX); AssertFatal((ret=pthread_mutex_lock(&ru->proc.mutex_pre_scd))==0,"[eNB] error locking proc mutex for eNB pre scd\n"); ru->proc.instance_pre_scd++; diff --git a/targets/TEST/PDCP/test_pdcp.c b/targets/TEST/PDCP/test_pdcp.c index b62edf1215..d6becf87c1 100644 --- a/targets/TEST/PDCP/test_pdcp.c +++ b/targets/TEST/PDCP/test_pdcp.c @@ -100,7 +100,7 @@ int main(int argc, char **argv) list_init(&test_pdu_rx_list, NULL); logInit(); - if (init_pdcp_entity(&pdcp_array[0]) == TRUE && init_pdcp_entity(&pdcp_array[1]) == TRUE) + if (init_pdcp_entity(&pdcp_array[0]) == true && init_pdcp_entity(&pdcp_array[1]) == true) msg("[TEST] PDCP entity initialization OK\n"); else { msg("[TEST] Cannot initialize PDCP entities!\n"); @@ -109,7 +109,7 @@ int main(int argc, char **argv) /* Initialize PDCP state variables */ for (index = 0; index < 2; ++index) { - if (pdcp_init_seq_numbers(&pdcp_array[index]) == FALSE) { + if (pdcp_init_seq_numbers(&pdcp_array[index]) == false) { msg("[TEST] Cannot initialize sequence numbers of PDCP entity %d!\n", index); exit(1); } else { @@ -120,11 +120,11 @@ int main(int argc, char **argv) #if TEST_RX_AND_TX_WINDOW /* Test TX window */ - if (test_tx_window() == FALSE) + if (test_tx_window() == false) test_result = 1; /* Test RX window */ - if (test_rx_window() == FALSE) + if (test_rx_window() == false) test_result = 1; #endif @@ -132,11 +132,11 @@ int main(int argc, char **argv) #if TEST_PDCP_DATA_REQUEST_AND_INDICATION /* Test pdcp_data_req() method in pdcp.c */ - if (test_pdcp_data_req() == FALSE) + if (test_pdcp_data_req() == false) test_result = 1; /* Test pdcp_data_ind() method in pdcp.c */ - if (test_pdcp_data_ind() == FALSE) + if (test_pdcp_data_ind() == false) test_result = 1; #endif @@ -150,10 +150,10 @@ int main(int argc, char **argv) return test_result; } -BOOL init_pdcp_entity(pdcp_t *pdcp_entity) +bool init_pdcp_entity(pdcp_t *pdcp_entity) { if (pdcp_entity == NULL) - return FALSE; + return false; /* * Initialize sequence number state variables of relevant PDCP entity @@ -171,10 +171,10 @@ BOOL init_pdcp_entity(pdcp_t *pdcp_entity) pdcp_entity->next_pdcp_rx_sn, pdcp_entity->tx_hfn, pdcp_entity->rx_hfn, \ pdcp_entity->last_submitted_pdcp_rx_sn, pdcp_entity->seq_num_size); - return TRUE; + return true; } -BOOL test_tx_window(void) +bool test_tx_window(void) { unsigned long index = 0; @@ -185,33 +185,33 @@ BOOL test_tx_window(void) msg("TX packet # %07lu seq # %04d hfn # %04d\n", index, pseudo_tx_sn, pdcp_array[0].tx_hfn); else { msg("TX packet is out-of-window!\n"); - return FALSE; + return false; } } - return TRUE; + return true; } -BOOL test_rx_window(void) +bool test_rx_window(void) { unsigned long index = 0; for (index = 0; index < NUMBER_OF_TEST_PACKETS; ++index) { u16 pseudo_rx_sn = (index == 0) ? 0 : index % WINDOW_SIZE; - if (pdcp_is_rx_seq_number_valid(pseudo_rx_sn, &pdcp_array[1]) == TRUE) { + if (pdcp_is_rx_seq_number_valid(pseudo_rx_sn, &pdcp_array[1]) == true) { msg("RX packet # %07lu seq # %04d last-submitted # %04d hfn # %04d\n", \ index, pdcp_array[1].next_pdcp_rx_sn, pdcp_array[1].last_submitted_pdcp_rx_sn, pdcp_array[1].rx_hfn); } else { msg("RX packet seq # %04lu is not valid!\n", index); - return FALSE; + return false; } } - return TRUE; + return true; } -BOOL test_pdcp_data_req(void) +bool test_pdcp_data_req(void) { unsigned char* pdcp_test_pdu_buffer = NULL; unsigned char pdcp_test_pdu_buffer_size = DUMMY_BUFFER_SIZE + PDCP_USER_PLANE_DATA_PDU_LONG_SN_HEADER_SIZE; @@ -224,7 +224,7 @@ BOOL test_pdcp_data_req(void) if (pdcp_test_pdu_buffer == NULL) { msg("Cannot allocate a buffer for test!\n"); - return FALSE; + return false; } /* @@ -241,7 +241,7 @@ BOOL test_pdcp_data_req(void) /* * Ask PDCP to create a PDU with given buffer and enqueue it to `test_pdu_tx_list` */ - if (pdcp_data_req(0, 0, 10, DUMMY_BUFFER, &pdcp_array[0], &test_pdu_tx_list) == TRUE) { + if (pdcp_data_req(0, 0, 10, DUMMY_BUFFER, &pdcp_array[0], &test_pdu_tx_list) == true) { msg("[TEST] Starting to dissect PDU created by PDCP...\n"); /* @@ -251,7 +251,7 @@ BOOL test_pdcp_data_req(void) if (pdcp_test_pdu_buffer_size == 0 ) { msg("[TEST] PDU created by pdcp_data_req() is invalid!\n"); - return FALSE; + return false; } /* @@ -269,7 +269,7 @@ BOOL test_pdcp_data_req(void) */ if (pdcp_test_pdu_buffer[0] & 0x80) { msg("[TEST] First bit is not 0, which means this is not a Data PDU!\n"); - return FALSE; + return false; } else { msg("[TEST] First bit is 0 so this is a Data PDU, OK\n"); } @@ -279,7 +279,7 @@ BOOL test_pdcp_data_req(void) */ if ((pdcp_test_pdu_buffer[0] & 0x70) != 0) { msg("[TEST] Reserved bits are not 0!\n"); - return FALSE; + return false; } else { msg("[TEST] Reserved bits are all 0, OK\n"); } @@ -292,21 +292,21 @@ BOOL test_pdcp_data_req(void) if (sequence_number != index % WINDOW_SIZE) { msg("[TEST] Sequence numbers are out-of-order!\n"); - return FALSE; + return false; } else { msg("[TEST] Sequence number is correct\n"); } } else { msg("[TEST] pdcp_data_req() returned FALSE!\n"); - return FALSE; + return false; } } - return TRUE; + return true; } -BOOL test_pdcp_data_ind(void) +bool test_pdcp_data_ind(void) { /* * This is the list that pdcp_data_ind() takes to put pdcp_data_ind_header_t @@ -341,9 +341,9 @@ BOOL test_pdcp_data_ind(void) test_sdu = list_remove_head(&test_pdu_rx_list); - if (pdcp_data_ind(0, 0, test_sdu_size, test_sdu, &pdcp_array[0], &test_pdu_indication_list) == FALSE) { + if (pdcp_data_ind(0, 0, test_sdu_size, test_sdu, &pdcp_array[0], &test_pdu_indication_list) == false) { msg("[TEST] pdcp_data_ind() failed to handle data indication!\n"); - return FALSE; + return false; } else { msg("[TEST] pdcp_data_ind() succcessfuly handled data indication\n"); } @@ -359,7 +359,7 @@ BOOL test_pdcp_data_ind(void) if (test_data_ind_header == NULL) { msg("[TEST] Data indication header is not valid!\n"); - return FALSE; + return false; } else { pdcp_data_ind_header_t* indication_header = (pdcp_data_ind_header_t*)test_data_ind_header->data; @@ -370,7 +370,7 @@ BOOL test_pdcp_data_ind(void) msg("[TEST] Radio bearer ID is correct\n"); } else { msg("[TEST] Radio bearer ID is not correct! (expected: 0, parsed: %d)\n", indication_header->rb_id); - return FALSE; + return false; } /* @@ -380,7 +380,7 @@ BOOL test_pdcp_data_ind(void) msg("[TEST] SDU size is correct\n"); } else { msg("[TEST] SDU size is not correct! (expected: %d, parsed: %d)\n", DUMMY_BUFFER_SIZE, indication_header->data_size); - return FALSE; + return false; } /* @@ -412,11 +412,11 @@ BOOL test_pdcp_data_ind(void) print_byte_stream("[TEST] TXed data: ", DUMMY_BUFFER, DUMMY_BUFFER_SIZE); print_byte_stream("[TEST] RXed data: ", (unsigned char*)&(test_data_ind_header->data[data_index]), DUMMY_BUFFER_SIZE); - return FALSE; + return false; } } - return TRUE; + return true; } diff --git a/targets/TEST/PDCP/test_pdcp.h b/targets/TEST/PDCP/test_pdcp.h index 0da174cc8c..629f6f2539 100644 --- a/targets/TEST/PDCP/test_pdcp.h +++ b/targets/TEST/PDCP/test_pdcp.h @@ -42,17 +42,17 @@ int pdcp_fifo_flush_sdus (void) { return 0; } int pdcp_fifo_read_input_sdus_remaining_bytes (void) { return 0; } int pdcp_fifo_read_input_sdus (void) { return 0; } -BOOL init_pdcp_entity(pdcp_t *pdcp_entity); -BOOL test_tx_window(void); -BOOL test_rx_window(void); -BOOL test_pdcp_data_req(void); -BOOL test_pdcp_data_ind(void); +bool init_pdcp_entity(pdcp_t *pdcp_entity); +bool test_tx_window(void); +bool test_rx_window(void); +bool test_pdcp_data_req(void); +bool test_pdcp_data_ind(void); /* * PDCP methods that are going to be utilised throughout the test */ -extern BOOL pdcp_init_seq_numbers(pdcp_t* pdcp_entity); +extern bool pdcp_init_seq_numbers(pdcp_t* pdcp_entity); extern u16 pdcp_get_next_tx_seq_number(pdcp_t* pdcp_entity); -extern BOOL pdcp_is_rx_seq_number_valid(u16 seq_num, pdcp_t* pdcp_entity); +extern bool pdcp_is_rx_seq_number_valid(u16 seq_num, pdcp_t* pdcp_entity); #endif diff --git a/targets/TEST/PDCP/with_rlc/test_pdcp_rlc.c b/targets/TEST/PDCP/with_rlc/test_pdcp_rlc.c index 378ee95c3b..7b80171724 100644 --- a/targets/TEST/PDCP/with_rlc/test_pdcp_rlc.c +++ b/targets/TEST/PDCP/with_rlc/test_pdcp_rlc.c @@ -109,7 +109,7 @@ int pdcp_fifo_flush_sdus () {} int pdcp_fifo_read_input_sdus_remaining_bytes () {} int pdcp_fifo_read_input_sdus () {} -BOOL init_pdcp_entity(pdcp_t *pdcp_entity); +bool init_pdcp_entity(pdcp_t *pdcp_entity); //----------------------------------------------------------------------------- void pdcp_rlc_test_mac_rlc_loop (struct mac_data_ind *data_indP, struct mac_data_req *data_requestP, int* drop_countP, int *tx_packetsP, int* dropped_tx_packetsP) //----------------------------------------------------------------------------- @@ -230,7 +230,7 @@ int main(int argc, char **argv) pdcp_module_init(); logInit(); - if (init_pdcp_entity(&pdcp_array[0][1]) == TRUE && init_pdcp_entity(&pdcp_array[1][1]) == TRUE) + if (init_pdcp_entity(&pdcp_array[0][1]) == true && init_pdcp_entity(&pdcp_array[1][1]) == true) msg("PDCP entity initialization OK\n"); else { msg("Cannot initialize PDCP entities!\n"); @@ -239,7 +239,7 @@ int main(int argc, char **argv) /* Initialize PDCP state variables */ for (index = 0; index < 2; ++index) { - if (pdcp_init_seq_numbers(&pdcp_array[index][1]) == FALSE) { + if (pdcp_init_seq_numbers(&pdcp_array[index][1]) == false) { msg("Cannot initialize %s PDCP entity!\n", ((index == 0) ? "first" : "second")); exit(1); } @@ -275,11 +275,11 @@ int main(int argc, char **argv) } //----------------------------------------------------------------------------- -BOOL init_pdcp_entity(pdcp_t *pdcp_entity) +bool init_pdcp_entity(pdcp_t *pdcp_entity) //----------------------------------------------------------------------------- { if (pdcp_entity == NULL) - return FALSE; + return false; /* * Initialize sequence number state variables of relevant PDCP entity @@ -292,6 +292,6 @@ BOOL init_pdcp_entity(pdcp_t *pdcp_entity) pdcp_entity->last_submitted_pdcp_rx_sn = 4095; pdcp_entity->seq_num_size = 12; - return TRUE; + return true; } From bf219fc24fa75c5a057dc6f2bb6d0a3ae5baaa35 Mon Sep 17 00:00:00 2001 From: Laurent Thomas Date: Thu, 16 Jun 2022 14:41:23 +0200 Subject: [PATCH 173/267] avx2 and better simd algo --- openair1/PHY/TOOLS/cmult_sv.c | 224 +++++--------------------------- openair1/PHY/TOOLS/tools_defs.h | 12 +- 2 files changed, 31 insertions(+), 205 deletions(-) diff --git a/openair1/PHY/TOOLS/cmult_sv.c b/openair1/PHY/TOOLS/cmult_sv.c index dc57964ca5..720b5da7e8 100644 --- a/openair1/PHY/TOOLS/cmult_sv.c +++ b/openair1/PHY/TOOLS/cmult_sv.c @@ -144,205 +144,39 @@ void multadd_real_four_symbols_vector_complex_scalar(int16_t *x, _m_empty(); } - -/* -int rotate_cpx_vector(int16_t *x, +#ifdef __AVX2__ +void rotate_cpx_vector(int16_t *x, int16_t *alpha, int16_t *y, uint32_t N, - uint16_t output_shift, - uint8_t format) + uint16_t output_shift) { - // Multiply elementwise two complex vectors of N elements - // x - input 1 in the format |Re0 Im0 Re0 Im0|,......,|Re(N-1) Im(N-1) Re(N-1) Im(N-1)| - // We assume x1 with a dynamic of 15 bit maximum - // - // alpha - input 2 in the format |Re0 Im0| - // We assume x2 with a dynamic of 15 bit maximum - // - // y - output in the format |Re0 Im0 Re0 Im0|,......,|Re(N-1) Im(N-1) Re(N-1) Im(N-1)| - // - // N - the size f the vectors (this function does N cpx mpy. WARNING: N>=4; - // - // output_shift - shift at output to return in Q1.15 - // format - 0 means alpha is in shuffled format, 1 means x is in shuffled format - - uint32_t i; // loop counter - - register __m128i m0,m1; - - - - __m128i *x_128; - __m128i *y_128; - - - shift = _mm_cvtsi32_si128(output_shift); - x_128 = (__m128i *)&x[0]; - - if (format==0) { // alpha is in shuffled format for complex multiply - ((int16_t *)&alpha_128)[0] = alpha[0]; - ((int16_t *)&alpha_128)[1] = -alpha[1]; - ((int16_t *)&alpha_128)[2] = alpha[1]; - ((int16_t *)&alpha_128)[3] = alpha[0]; - ((int16_t *)&alpha_128)[4] = alpha[0]; - ((int16_t *)&alpha_128)[5] = -alpha[1]; - ((int16_t *)&alpha_128)[6] = alpha[1]; - ((int16_t *)&alpha_128)[7] = alpha[0]; - } else { // input is in shuffled format for complex multiply - ((int16_t *)&alpha_128)[0] = alpha[0]; - ((int16_t *)&alpha_128)[1] = alpha[1]; - ((int16_t *)&alpha_128)[2] = alpha[0]; - ((int16_t *)&alpha_128)[3] = alpha[1]; - ((int16_t *)&alpha_128)[4] = alpha[0]; - ((int16_t *)&alpha_128)[5] = alpha[1]; - ((int16_t *)&alpha_128)[6] = alpha[0]; - ((int16_t *)&alpha_128)[7] = alpha[1]; + // multiply a complex vector with a complex value (alpha) + // stores result in y + // N is the number of complex numbers + // output_shift reduces the result of the multiplication by this number of bits + AssertFatal(N%8==0, "To be developped"); + const c16_t for_re={alpha[0], -alpha[1]}; + __m256i const alpha_for_real = _mm256_set1_epi32(*(uint32_t*)&for_re); + const c16_t for_im={alpha[1], alpha[0]}; + __m256i const alpha_for_im= _mm256_set1_epi32(*(uint32_t*)&for_im); + __m256i const perm_mask = + _mm256_set_epi8(31,30,23,22,29,28,21,20,27,26,19,18,25,24,17,16, + 15,14,7,6,13,12,5,4,11,10,3,2,9,8,1,0); + __m256i* xd= (__m256i*)x; + const __m256i *end=xd+N/8; + for( __m256i* yd = (__m256i *)y; xd>3); i++) { - - m0 = _mm_madd_epi16(x_128[0],alpha_128); //pmaddwd_r2r(mm1,mm0); // 1- compute x1[0]*x2[0] - m0 = _mm_sra_epi32(m0,shift); // 1- shift right by shift in order to compensate for the input amplitude - m1=m0; - m0 = _mm_packs_epi32(m1,m0); // 1- pack in a 128 bit register [re im re im] - y_128[0] = _mm_unpacklo_epi32(m0,m0); // 1- pack in a 128 bit register [re im re im] - m0 = _mm_madd_epi16(x_128[1],alpha_128); //pmaddwd_r2r(mm1,mm0); // 1- compute x1[0]*x2[0] - m0 = _mm_sra_epi32(m0,shift); // 1- shift right by shift in order to compensate for the input amplitude - m1 = m0; - m1 = _mm_packs_epi32(m1,m0); // 1- pack in a 128 bit register [re im re im] - y_128[1] = _mm_unpacklo_epi32(m1,m1); // 1- pack in a 128 bit register [re im re im] - m0 = _mm_madd_epi16(x_128[2],alpha_128); //pmaddwd_r2r(mm1,mm0); // 1- compute x1[0]*x2[0] - m0 = _mm_sra_epi32(m0,shift); // 1- shift right by shift in order to compensate for the input amplitude - m1 = m0; - m1 = _mm_packs_epi32(m1,m0); // 1- pack in a 128 bit register [re im re im] - y_128[2] = _mm_unpacklo_epi32(m1,m1); // 1- pack in a 128 bit register [re im re im] - m0 = _mm_madd_epi16(x_128[3],alpha_128); //pmaddwd_r2r(mm1,mm0); // 1- compute x1[0]*x2[0] - m0 = _mm_sra_epi32(m0,shift); // 1- shift right by shift in order to compensate for the input amplitude - m1 = m0; - m1 = _mm_packs_epi32(m1,m0); // 1- pack in a 128 bit register [re im re im] - y_128[3] = _mm_unpacklo_epi32(m1,m1); // 1- pack in a 128 bit register [re im re im] - if (format==1) { // Put output in proper format (Re,-Im,Im,Re), shuffle = (0,1,3,2) = 0x1e - - y_128[0] = _mm_shufflelo_epi16(y_128[0],0x1e); - y_128[0] = _mm_shufflehi_epi16(y_128[0],0x1e); - ((int16_t*)&y_128[0])[1] = -((int16_t*)&y_128[0])[1]; - ((int16_t*)&y_128[0])[5] = -((int16_t*)&y_128[0])[5]; - y_128[1] = _mm_shufflelo_epi16(y_128[1],0x1e); - y_128[1] = _mm_shufflehi_epi16(y_128[1],0x1e); - ((int16_t*)&y_128[1])[1] = -((int16_t*)&y_128[1])[1]; - ((int16_t*)&y_128[1])[5] = -((int16_t*)&y_128[1])[5]; - y_128[2] = _mm_shufflelo_epi16(y_128[2],0x1e); - y_128[2] = _mm_shufflehi_epi16(y_128[2],0x1e); - ((int16_t*)&y_128[2])[1] = -((int16_t*)&y_128[2])[1]; - ((int16_t*)&y_128[2])[5] = -((int16_t*)&y_128[2])[5]; - y_128[3] = _mm_shufflelo_epi16(y_128[3],0x1e); - y_128[3] = _mm_shufflehi_epi16(y_128[3],0x1e); - ((int16_t*)&y_128[3])[1] = -((int16_t*)&y_128[3])[1]; - ((int16_t*)&y_128[3])[5] = -((int16_t*)&y_128[3])[5]; - } - - - x_128+=4; - y_128 +=4; - } - - - _mm_empty(); - _m_empty(); - - return(0); } - -int rotate_cpx_vector2(int16_t *x, - int16_t *alpha, - int16_t *y, - uint32_t N, - uint16_t output_shift, - uint8_t format) -{ - // Multiply elementwise two complex vectors of N elements - // x - input 1 in the format |Re0 Im0 Re0 Im0|,......,|Re(N-1) Im(N-1) Re(N-1) Im(N-1)| - // We assume x1 with a dynamic of 15 bit maximum - // - // alpha - input 2 in the format |Re0 Im0| - // We assume x2 with a dynamic of 15 bit maximum - // - // y - output in the format |Re0 Im0 Re0 Im0|,......,|Re(N-1) Im(N-1) Re(N-1) Im(N-1)| - // - // N - the size f the vectors (this function does N cpx mpy. WARNING: N>=4; - // - // log2_amp - increase the output amplitude by a factor 2^log2_amp (default is 0) - // WARNING: log2_amp>0 can cause overflow!! - - uint32_t i; // loop counter - - register __m128i m0,m1; - - - __m128i *x_128; - __m128i *y_128; - - - shift = _mm_cvtsi32_si128(output_shift); - x_128 = (__m128i *)&x[0]; - - if (format==0) { // alpha is in shuffled format for complex multiply - ((int16_t *)&alpha_128)[0] = alpha[0]; - ((int16_t *)&alpha_128)[1] = -alpha[1]; - ((int16_t *)&alpha_128)[2] = alpha[1]; - ((int16_t *)&alpha_128)[3] = alpha[0]; - ((int16_t *)&alpha_128)[4] = alpha[0]; - ((int16_t *)&alpha_128)[5] = -alpha[1]; - ((int16_t *)&alpha_128)[6] = alpha[1]; - ((int16_t *)&alpha_128)[7] = alpha[0]; - } else { // input is in shuffled format for complex multiply - ((int16_t *)&alpha_128)[0] = alpha[0]; - ((int16_t *)&alpha_128)[1] = alpha[1]; - ((int16_t *)&alpha_128)[2] = alpha[0]; - ((int16_t *)&alpha_128)[3] = alpha[1]; - ((int16_t *)&alpha_128)[4] = alpha[0]; - ((int16_t *)&alpha_128)[5] = alpha[1]; - ((int16_t *)&alpha_128)[6] = alpha[0]; - ((int16_t *)&alpha_128)[7] = alpha[1]; - } - - y_128 = (__m128i *)&y[0]; - - // we compute 4 cpx multiply for each loop - for(i=0; i<(N>>1); i++) { - - - m0 = _mm_madd_epi16(x_128[i],alpha_128); //pmaddwd_r2r(mm1,mm0); // 1- compute x1[0]*x2[0] - m0 = _mm_sra_epi32(m0,shift); // 1- shift right by shift in order to compensate for the input amplitude - m1=m0; - m1 = _mm_packs_epi32(m1,m0); // 1- pack in a 128 bit register [re im re im] - y_128[i] = _mm_unpacklo_epi32(m1,m1); // 1- pack in a 128 bit register [re im re im] - if (format==1) { // Put output in proper format (Re,-Im,Im,Re), shuffle = (0,1,3,2) = 0x1e - - y_128[i] = _mm_shufflelo_epi16(y_128[i],0x1e); - y_128[i] = _mm_shufflehi_epi16(y_128[i],0x1e); - ((int16_t*)&y_128[i])[1] = -((int16_t*)&y_128[i])[1]; - ((int16_t*)&y_128[i])[5] = -((int16_t*)&y_128[i])[5]; - } - } - - - _mm_empty(); - _m_empty(); - - - return(0); -} -*/ - -int rotate_cpx_vector(int16_t *x, +#else +void rotate_cpx_vector(int16_t *x, int16_t *alpha, int16_t *y, uint32_t N, @@ -439,9 +273,9 @@ int rotate_cpx_vector(int16_t *x, _mm_empty(); _m_empty(); - return(0); + return; } - +#endif /* int mult_vector32_scalar(int16_t *x1, int x2, diff --git a/openair1/PHY/TOOLS/tools_defs.h b/openair1/PHY/TOOLS/tools_defs.h index 839beb3dc9..954301d938 100644 --- a/openair1/PHY/TOOLS/tools_defs.h +++ b/openair1/PHY/TOOLS/tools_defs.h @@ -37,6 +37,7 @@ extern "C" { #include #include #include "PHY/sse_intrin.h" +#include "common/utils/assertions.h" #define CEILIDIV(a,b) ((a+b-1)/b) #define ROUNDIDIV(a,b) (((a<<1)+b)/(b<<1)) @@ -104,15 +105,6 @@ void multadd_complex_vector_real_scalar(int16_t *x, uint8_t zero_flag, uint32_t N); -int rotate_cpx_vector(int16_t *x, - int16_t *alpha, - int16_t *y, - uint32_t N, - uint16_t output_shift); - - - - /*!\fn void init_fft(uint16_t size,uint8_t logsize,uint16_t *rev) \brief Initialize the FFT engine for a given size @param size Size of the FFT @@ -471,7 +463,7 @@ This function performs componentwise multiplication of a vector with a complex s The function implemented is : \f$\mathbf{y} = \alpha\mathbf{x}\f$ */ -int32_t rotate_cpx_vector(int16_t *x, +void rotate_cpx_vector(int16_t *x, int16_t *alpha, int16_t *y, uint32_t N, From 980bb2420b7713c11fba117c68f35aa1d7e0628f Mon Sep 17 00:00:00 2001 From: Laurent Thomas Date: Fri, 24 Jun 2022 17:04:40 +0200 Subject: [PATCH 174/267] fix CI discovered bug in avx2 rotate --- .../lte_ul_channel_estimation.c | 34 ++++----- openair1/PHY/MODULATION/ofdm_mod.c | 6 +- openair1/PHY/MODULATION/slot_fep_nr.c | 36 ++++----- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 24 +++--- .../nr_dl_channel_estimation.c | 23 +++--- openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 17 ++--- openair1/PHY/TOOLS/cmult_sv.c | 75 ++++++------------- openair1/PHY/TOOLS/tools_defs.h | 12 +-- 8 files changed, 97 insertions(+), 130 deletions(-) diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c index c867292942..e42f5f787c 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c @@ -41,10 +41,10 @@ extern int16_t *ul_ref_sigs_rx[30][2][34]; int32_t lte_ul_channel_estimation(LTE_DL_FRAME_PARMS *frame_parms, L1_rxtx_proc_t *proc, - LTE_eNB_ULSCH_t * ulsch, - int32_t **ul_ch_estimates, - int32_t **ul_ch_estimates_time, - int32_t **rxdataF_ext, + LTE_eNB_ULSCH_t * ulsch, + int32_t **ul_ch_estimates, + int32_t **ul_ch_estimates_time, + int32_t **rxdataF_ext, module_id_t UE_id, unsigned char l, unsigned char Ns) { @@ -88,7 +88,7 @@ int32_t lte_ul_channel_estimation(LTE_DL_FRAME_PARMS *frame_parms, } uint16_t N_rb_alloc = ulsch->harq_processes[harq_pid]->nb_rb; - int32_t tmp_estimates[N_rb_alloc*12] __attribute__((aligned(16))); + int32_t tmp_estimates[N_rb_alloc*12] __attribute__((aligned(32))); Msc_RS = N_rb_alloc*12; cyclic_shift = (frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift + ulsch->harq_processes[harq_pid]->n_DMRS2 + @@ -334,14 +334,14 @@ int32_t lte_ul_channel_estimation(LTE_DL_FRAME_PARMS *frame_parms, current_phase2 = cmin(abs(current_phase2),127); // msg("sym: %d, current_phase1: %d, ru: %d + j%d, current_phase2: %d, ru: %d + j%d\n",k,current_phase1,ru1[2*current_phase1],ru1[2*current_phase1+1],current_phase2,ru2[2*current_phase2],ru2[2*current_phase2+1]); // rotate channel estimates by estimated phase - rotate_cpx_vector((int16_t *) ul_ch1, - &ru1[2*current_phase1], - (int16_t *) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k], + rotate_cpx_vector((c16_t *) ul_ch1, + (c16_t *)&ru1[2*current_phase1], + (c16_t *) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k], Msc_RS, 15); - rotate_cpx_vector((int16_t *) ul_ch2, - &ru2[2*current_phase2], - (int16_t *) &tmp_estimates[0], + rotate_cpx_vector((c16_t *) ul_ch2, + (c16_t *)&ru2[2*current_phase2], + (c16_t *) &tmp_estimates[0], Msc_RS, 15); // Combine the two rotated estimates @@ -657,14 +657,14 @@ int32_t lte_ul_channel_estimation_RRU(LTE_DL_FRAME_PARMS *frame_parms, current_phase2 = cmin(abs(current_phase2),127); // msg("sym: %d, current_phase1: %d, ru: %d + j%d, current_phase2: %d, ru: %d + j%d\n",k,current_phase1,ru1[2*current_phase1],ru1[2*current_phase1+1],current_phase2,ru2[2*current_phase2],ru2[2*current_phase2+1]); // rotate channel estimates by estimated phase - rotate_cpx_vector((int16_t *) ul_ch1, - &ru1[2*current_phase1], - (int16_t *) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k], + rotate_cpx_vector((c16_t *) ul_ch1, + (c16_t *)&ru1[2*current_phase1], + (c16_t *) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k], Msc_RS, 15); - rotate_cpx_vector((int16_t *) ul_ch2, - &ru2[2*current_phase2], - (int16_t *) &tmp_estimates[0], + rotate_cpx_vector((c16_t *) ul_ch2, + (c16_t *)&ru2[2*current_phase2], + (c16_t *) &tmp_estimates[0], Msc_RS, 15); // Combine the two rotated estimates diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index 2f075e8218..678eac2f3a 100644 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -360,9 +360,9 @@ void apply_nr_rotation(NR_DL_FRAME_PARMS *fp, symbol_rotation[2 * (sidx + first_symbol + symb_offset)], symbol_rotation[1 + 2 * (sidx + first_symbol + symb_offset)]); - rotate_cpx_vector(trxdata + (sidx * length * 2), - &symbol_rotation[2 * (sidx + first_symbol + symb_offset)], - trxdata + (sidx * length * 2), + rotate_cpx_vector((c16_t*)trxdata + (sidx * length * 2), + (c16_t*)&symbol_rotation[2 * (sidx + first_symbol + symb_offset)], + (c16_t*) trxdata + (sidx * length * 2), length, 15); } diff --git a/openair1/PHY/MODULATION/slot_fep_nr.c b/openair1/PHY/MODULATION/slot_fep_nr.c index 139b730ce1..5b0c4dc23a 100644 --- a/openair1/PHY/MODULATION/slot_fep_nr.c +++ b/openair1/PHY/MODULATION/slot_fep_nr.c @@ -98,18 +98,18 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, stop_meas(&ue->rx_dft_stats); int symb_offset = (Ns%frame_parms->slots_per_subframe)*frame_parms->symbols_per_slot; - int32_t rot2 = ((uint32_t*)frame_parms->symbol_rotation[0])[symbol+symb_offset]; - ((int16_t*)&rot2)[1]=-((int16_t*)&rot2)[1]; + c16_t rot2 = ((c16_t*)frame_parms->symbol_rotation[0])[symbol+symb_offset]; + rot2.i=-rot2.i; #ifdef DEBUG_FEP // if (ue->frame <100) printf("slot_fep: slot %d, symbol %d rx_offset %u, rotation symbol %d %d.%d\n", Ns,symbol, rx_offset, - symbol+symb_offset,((int16_t*)&rot2)[0],((int16_t*)&rot2)[1]); + symbol+symb_offset,rot2.r,rot2.i); #endif - rotate_cpx_vector((int16_t *)&common_vars->common_vars_rx_data_per_thread[proc->thread_id].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol], - (int16_t*)&rot2, - (int16_t *)&common_vars->common_vars_rx_data_per_thread[proc->thread_id].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol], + rotate_cpx_vector((c16_t *)&common_vars->common_vars_rx_data_per_thread[proc->thread_id].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol], + &rot2, + (c16_t *)&common_vars->common_vars_rx_data_per_thread[proc->thread_id].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol], frame_parms->ofdm_symbol_size, 15); @@ -214,18 +214,18 @@ int nr_slot_fep_init_sync(PHY_VARS_NR_UE *ue, stop_meas(&ue->rx_dft_stats); int symb_offset = (Ns%frame_parms->slots_per_subframe)*frame_parms->symbols_per_slot; - int32_t rot2 = ((uint32_t*)frame_parms->symbol_rotation[0])[symbol + symb_offset]; - ((int16_t*)&rot2)[1]=-((int16_t*)&rot2)[1]; + c16_t rot2 = ((c16_t*)frame_parms->symbol_rotation[0])[symbol + symb_offset]; + rot2.i=-rot2.i; #ifdef DEBUG_FEP // if (ue->frame <100) printf("slot_fep: slot %d, symbol %d rx_offset %u, rotation symbol %d %d.%d\n", Ns,symbol, rx_offset, - symbol+symb_offset,((int16_t*)&rot2)[0],((int16_t*)&rot2)[1]); + symbol+symb_offset,rot2.r,rot2.i); #endif - rotate_cpx_vector((int16_t *)&common_vars->common_vars_rx_data_per_thread[proc->thread_id].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol], - (int16_t*)&rot2, - (int16_t *)&common_vars->common_vars_rx_data_per_thread[proc->thread_id].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol], + rotate_cpx_vector((c16_t *)&common_vars->common_vars_rx_data_per_thread[proc->thread_id].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol], + &rot2, + (c16_t *)&common_vars->common_vars_rx_data_per_thread[proc->thread_id].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol], frame_parms->ofdm_symbol_size, 15); } @@ -310,12 +310,12 @@ void apply_nr_rotation_ul(NR_DL_FRAME_PARMS *frame_parms, for (int symbol=first_symbol;symbolsymbol_rotation[1])[symbol + symb_offset]; - ((int16_t*)&rot2)[1]=-((int16_t*)&rot2)[1]; - LOG_D(PHY,"slot %d, symb_offset %d rotating by %d.%d\n",slot,symb_offset,((int16_t*)&rot2)[0],((int16_t*)&rot2)[1]); - rotate_cpx_vector((int16_t *)&rxdataF[soffset+(frame_parms->ofdm_symbol_size*symbol)], - (int16_t*)&rot2, - (int16_t *)&rxdataF[soffset+(frame_parms->ofdm_symbol_size*symbol)], + c16_t rot2 = ((c16_t*)frame_parms->symbol_rotation[1])[symbol + symb_offset]; + rot2.i=-rot2.i; + LOG_D(PHY,"slot %d, symb_offset %d rotating by %d.%d\n",slot,symb_offset,rot2.r,rot2.i); + rotate_cpx_vector((c16_t *)&rxdataF[soffset+(frame_parms->ofdm_symbol_size*symbol)], + &rot2, + (c16_t *)&rxdataF[soffset+(frame_parms->ofdm_symbol_size*symbol)], length, 15); diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index cd3b535b3f..5404afd432 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -854,7 +854,7 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, uint32_t nb_re_pusch) { //#define DEBUG_UL_PTRS 1 - int16_t *phase_per_symbol = NULL; + c16_t *phase_per_symbol = NULL; int32_t *ptrs_re_symbol = NULL; int8_t ret = 0; @@ -871,20 +871,20 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, uint8_t *ptrsReOffset = &rel15_ul->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset; /* loop over antennas */ for (int aarx=0; aarxnb_antennas_rx; aarx++) { - phase_per_symbol = (int16_t*)gNB->pusch_vars[ulsch_id]->ptrs_phase_per_slot[aarx]; + phase_per_symbol = (c16_t*)gNB->pusch_vars[ulsch_id]->ptrs_phase_per_slot[aarx]; ptrs_re_symbol = &gNB->pusch_vars[ulsch_id]->ptrs_re_per_slot; *ptrs_re_symbol = 0; - phase_per_symbol[(2*symbol)+1] = 0; // Imag + phase_per_symbol[symbol].i = 0; /* set DMRS estimates to 0 angle with magnitude 1 */ if(is_dmrs_symbol(symbol,*dmrsSymbPos)) { /* set DMRS real estimation to 32767 */ - phase_per_symbol[2*symbol]=(int16_t)((1<<15)-1); // 32767 + phase_per_symbol[symbol].r=INT16_MAX; // 32767 #ifdef DEBUG_UL_PTRS - printf("[PHY][PTRS]: DMRS Symbol %d -> %4d + j*%4d\n", symbol, phase_per_symbol[2*symbol],phase_per_symbol[(2*symbol)+1]); + printf("[PHY][PTRS]: DMRS Symbol %d -> %4d + j*%4d\n", symbol, phase_per_symbol[symbol].r,phase_per_symbol[symbol].i); #endif } else {// real ptrs value is set to 0 - phase_per_symbol[2*symbol] = 0; // Real + phase_per_symbol[symbol].r = 0; } if(symbol == *startSymbIndex) { @@ -909,7 +909,7 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, symbol,frame_parms->ofdm_symbol_size, (int16_t*)&gNB->pusch_vars[ulsch_id]->rxdataF_comp[aarx][(symbol * nb_re_pusch)], gNB->nr_gold_pusch_dmrs[rel15_ul->scid][nr_tti_rx][symbol], - &phase_per_symbol[2* symbol], + (int16_t*)&phase_per_symbol[symbol], ptrs_re_symbol); } /* For last OFDM symbol at each antenna perform interpolation and compensation for the slot*/ @@ -919,7 +919,7 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, /*------------------------------------------------------------------------------------------------------- */ /* If L-PTRS is > 0 then we need interpolation */ if(*L_ptrs > 0) { - ret = nr_ptrs_process_slot(*dmrsSymbPos, *ptrsSymbPos, phase_per_symbol, *startSymbIndex, *nbSymb); + ret = nr_ptrs_process_slot(*dmrsSymbPos, *ptrsSymbPos, (int16_t*)phase_per_symbol, *startSymbIndex, *nbSymb); if(ret != 0) { LOG_W(PHY,"[PTRS] Compensation is skipped due to error in PTRS slot processing !!\n"); } @@ -938,11 +938,11 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, /* Skip rotation if the slot processing is wrong */ if((!is_dmrs_symbol(i,*dmrsSymbPos)) && (ret == 0)) { #ifdef DEBUG_UL_PTRS - printf("[PHY][UL][PTRS]: Rotate Symbol %2d with %d + j* %d\n", i, phase_per_symbol[2* i],phase_per_symbol[(2* i) +1]); + printf("[PHY][UL][PTRS]: Rotate Symbol %2d with %d + j* %d\n", i, phase_per_symbol[i].r,phase_per_symbol[i].i); #endif - rotate_cpx_vector((int16_t*)&gNB->pusch_vars[ulsch_id]->rxdataF_comp[aarx][(i * rel15_ul->rb_size * NR_NB_SC_PER_RB)], - &phase_per_symbol[2* i], - (int16_t*)&gNB->pusch_vars[ulsch_id]->rxdataF_comp[aarx][(i * rel15_ul->rb_size * NR_NB_SC_PER_RB)], + rotate_cpx_vector((c16_t*)&gNB->pusch_vars[ulsch_id]->rxdataF_comp[aarx][(i * rel15_ul->rb_size * NR_NB_SC_PER_RB)], + &phase_per_symbol[i], + (c16_t*)&gNB->pusch_vars[ulsch_id]->rxdataF_comp[aarx][(i * rel15_ul->rb_size * NR_NB_SC_PER_RB)], ((*nb_rb) * NR_NB_SC_PER_RB), 15); }// if not DMRS Symbol }// symbol loop diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c index 8936a69e70..ba7e61afe6 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c @@ -1657,7 +1657,6 @@ void nr_pdsch_ptrs_processing(PHY_VARS_NR_UE *ue, RX_type_t rx_type) { //#define DEBUG_DL_PTRS 1 - int16_t *phase_per_symbol = NULL; int32_t *ptrs_re_symbol = NULL; int8_t ret = 0; /* harq specific variables */ @@ -1701,20 +1700,20 @@ void nr_pdsch_ptrs_processing(PHY_VARS_NR_UE *ue, } /* loop over antennas */ for (int aarx=0; aarxnb_antennas_rx; aarx++) { - phase_per_symbol = (int16_t*)pdsch_vars[gNB_id]->ptrs_phase_per_slot[aarx]; + c16_t *phase_per_symbol = (c16_t*)pdsch_vars[gNB_id]->ptrs_phase_per_slot[aarx]; ptrs_re_symbol = (int32_t*)pdsch_vars[gNB_id]->ptrs_re_per_slot[aarx]; ptrs_re_symbol[symbol] = 0; - phase_per_symbol[(2*symbol)+1] = 0; // Imag + phase_per_symbol[symbol].i = 0; // Imag /* set DMRS estimates to 0 angle with magnitude 1 */ if(is_dmrs_symbol(symbol,*dmrsSymbPos)) { /* set DMRS real estimation to 32767 */ - phase_per_symbol[2*symbol]=(int16_t)((1<<15)-1); // 32767 + phase_per_symbol[symbol].r=INT16_MAX; // 32767 #ifdef DEBUG_DL_PTRS - printf("[PHY][PTRS]: DMRS Symbol %d -> %4d + j*%4d\n", symbol, phase_per_symbol[2*symbol],phase_per_symbol[(2*symbol)+1]); + printf("[PHY][PTRS]: DMRS Symbol %d -> %4d + j*%4d\n", symbol, phase_per_symbol[symbol].r,phase_per_symbol[symbol].i); #endif } else { // real ptrs value is set to 0 - phase_per_symbol[2*symbol] = 0; // Real + phase_per_symbol[symbol].r = 0; // Real } if(dlsch0_harq->status == ACTIVE) { @@ -1740,7 +1739,7 @@ void nr_pdsch_ptrs_processing(PHY_VARS_NR_UE *ue, symbol,frame_parms->ofdm_symbol_size, (int16_t*)&pdsch_vars[gNB_id]->rxdataF_comp0[aarx][(symbol * nb_re_pdsch)], ue->nr_gold_pdsch[gNB_id][nr_slot_rx][symbol][0], - &phase_per_symbol[2* symbol], + (int16_t*)&phase_per_symbol[symbol], &ptrs_re_symbol[symbol]); } }// HARQ 0 @@ -1752,7 +1751,7 @@ void nr_pdsch_ptrs_processing(PHY_VARS_NR_UE *ue, /*------------------------------------------------------------------------------------------------------- */ /* If L-PTRS is > 0 then we need interpolation */ if(*L_ptrs > 0) { - ret = nr_ptrs_process_slot(*dmrsSymbPos, *ptrsSymbPos, phase_per_symbol, *startSymbIndex, *nbSymb); + ret = nr_ptrs_process_slot(*dmrsSymbPos, *ptrsSymbPos, (int16_t*)phase_per_symbol, *startSymbIndex, *nbSymb); if(ret != 0) { LOG_W(PHY,"[PTRS] Compensation is skipped due to error in PTRS slot processing !!\n"); } @@ -1771,11 +1770,11 @@ void nr_pdsch_ptrs_processing(PHY_VARS_NR_UE *ue, /* Skip rotation if the slot processing is wrong */ if((!is_dmrs_symbol(i,*dmrsSymbPos)) && (ret == 0)) { #ifdef DEBUG_DL_PTRS - printf("[PHY][DL][PTRS]: Rotate Symbol %2d with %d + j* %d\n", i, phase_per_symbol[2* i],phase_per_symbol[(2* i) +1]); + printf("[PHY][DL][PTRS]: Rotate Symbol %2d with %d + j* %d\n", i, phase_per_symbol[i].r,phase_per_symbol[i].i); #endif - rotate_cpx_vector((int16_t*)&pdsch_vars[gNB_id]->rxdataF_comp0[aarx][(i * (*nb_rb) * NR_NB_SC_PER_RB)], - &phase_per_symbol[2* i], - (int16_t*)&pdsch_vars[gNB_id]->rxdataF_comp0[aarx][(i * (*nb_rb) * NR_NB_SC_PER_RB)], + rotate_cpx_vector((c16_t*)&pdsch_vars[gNB_id]->rxdataF_comp0[aarx][(i * (*nb_rb) * NR_NB_SC_PER_RB)], + &phase_per_symbol[i], + (c16_t*)&pdsch_vars[gNB_id]->rxdataF_comp0[aarx][(i * (*nb_rb) * NR_NB_SC_PER_RB)], ((*nb_rb) * NR_NB_SC_PER_RB), 15); }// if not DMRS Symbol }// symbol loop diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index a07a19d085..22d7d5689f 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -597,17 +597,16 @@ uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE, int symb_offset = (slot%frame_parms->slots_per_subframe)*frame_parms->symbols_per_slot; for(ap = 0; ap < n_antenna_ports; ap++) { for (int s=0;ssymbol_rotation[1])[s + symb_offset]; LOG_D(PHY,"In %s: rotating txdataF symbol %d (%d) => (%d.%d)\n", - __FUNCTION__, - s, - s + symb_offset, - frame_parms->symbol_rotation[1][2 * (s + symb_offset)], - frame_parms->symbol_rotation[1][1 + (2 * (s + symb_offset))]); + __FUNCTION__, + s, + s + symb_offset, + rot.r, rot.i); - rotate_cpx_vector((int16_t *)&txdataF[ap][frame_parms->ofdm_symbol_size * s], - &frame_parms->symbol_rotation[1][2 * (s + symb_offset)], - (int16_t *)&txdataF[ap][frame_parms->ofdm_symbol_size * s], + rotate_cpx_vector((c16_t *)&txdataF[ap][frame_parms->ofdm_symbol_size * s], + &rot, + (c16_t *)&txdataF[ap][frame_parms->ofdm_symbol_size * s], frame_parms->ofdm_symbol_size, 15); } diff --git a/openair1/PHY/TOOLS/cmult_sv.c b/openair1/PHY/TOOLS/cmult_sv.c index 720b5da7e8..a9d502b9eb 100644 --- a/openair1/PHY/TOOLS/cmult_sv.c +++ b/openair1/PHY/TOOLS/cmult_sv.c @@ -145,40 +145,9 @@ void multadd_real_four_symbols_vector_complex_scalar(int16_t *x, } #ifdef __AVX2__ -void rotate_cpx_vector(int16_t *x, - int16_t *alpha, - int16_t *y, - uint32_t N, - uint16_t output_shift) -{ - // multiply a complex vector with a complex value (alpha) - // stores result in y - // N is the number of complex numbers - // output_shift reduces the result of the multiplication by this number of bits - AssertFatal(N%8==0, "To be developped"); - const c16_t for_re={alpha[0], -alpha[1]}; - __m256i const alpha_for_real = _mm256_set1_epi32(*(uint32_t*)&for_re); - const c16_t for_im={alpha[1], alpha[0]}; - __m256i const alpha_for_im= _mm256_set1_epi32(*(uint32_t*)&for_im); - __m256i const perm_mask = - _mm256_set_epi8(31,30,23,22,29,28,21,20,27,26,19,18,25,24,17,16, - 15,14,7,6,13,12,5,4,11,10,3,2,9,8,1,0); - __m256i* xd= (__m256i*)x; - const __m256i *end=xd+N/8; - for( __m256i* yd = (__m256i *)y; xdr; + ((int16_t *)&alpha_128)[1] = -alpha->i; + ((int16_t *)&alpha_128)[2] = alpha->i; + ((int16_t *)&alpha_128)[3] = alpha->r; + ((int16_t *)&alpha_128)[4] = alpha->r; + ((int16_t *)&alpha_128)[5] = -alpha->i; + ((int16_t *)&alpha_128)[6] = alpha->i; + ((int16_t *)&alpha_128)[7] = alpha->r; #elif defined(__arm__) int32x4_t shift; int32x4_t ab_re0,ab_re1,ab_im0,ab_im1,re32,im32; int16_t reflip[8] __attribute__((aligned(16))) = {1,-1,1,-1,1,-1,1,-1}; int32x4x2_t xtmp; - ((int16_t *)&alpha_128)[0] = alpha[0]; - ((int16_t *)&alpha_128)[1] = alpha[1]; - ((int16_t *)&alpha_128)[2] = alpha[0]; - ((int16_t *)&alpha_128)[3] = alpha[1]; - ((int16_t *)&alpha_128)[4] = alpha[0]; - ((int16_t *)&alpha_128)[5] = alpha[1]; - ((int16_t *)&alpha_128)[6] = alpha[0]; - ((int16_t *)&alpha_128)[7] = alpha[1]; + ((int16_t *)&alpha_128)[0] = alpha->r; + ((int16_t *)&alpha_128)[1] = alpha->i; + ((int16_t *)&alpha_128)[2] = alpha->r; + ((int16_t *)&alpha_128)[3] = alpha->i; + ((int16_t *)&alpha_128)[4] = alpha->r; + ((int16_t *)&alpha_128)[5] = alpha->i; + ((int16_t *)&alpha_128)[6] = alpha->r; + ((int16_t *)&alpha_128)[7] = alpha->i; int16x8_t bflip = vrev32q_s16(alpha_128); int16x8_t bconj = vmulq_s16(alpha_128,*(int16x8_t *)reflip); shift = vdupq_n_s32(-output_shift); @@ -370,7 +339,7 @@ main () int16_t input[256] __attribute__((aligned(16))); int16_t input2[256] __attribute__((aligned(16))); int16_t output[256] __attribute__((aligned(16))); - int16_t alpha[2]; + c16_t alpha; int i; @@ -408,8 +377,8 @@ main () input2[14] = 1000; input2[15] = 2000; - alpha[0]=32767; - alpha[1]=0; + alpha->r=32767; + alpha->i=0; //mult_cpx_vector(input,input2,output,L,0); rotate_cpx_vector_norep(input,alpha,input,L,15); diff --git a/openair1/PHY/TOOLS/tools_defs.h b/openair1/PHY/TOOLS/tools_defs.h index 954301d938..18d1533166 100644 --- a/openair1/PHY/TOOLS/tools_defs.h +++ b/openair1/PHY/TOOLS/tools_defs.h @@ -453,7 +453,7 @@ idft_size_idx_t get_idft(int ofdm_symbol_size) } -/*!\fn int32_t rotate_cpx_vector(int16_t *x,int16_t *alpha,int16_t *y,uint32_t N,uint16_t output_shift) +/*!\fn int32_t rotate_cpx_vector(c16_t *x,c16_t *alpha,c16_t *y,uint32_t N,uint16_t output_shift) This function performs componentwise multiplication of a vector with a complex scalar. @param x Vector input (Q1.15) in the format |Re0 Im0|,......,|Re(N-1) Im(N-1)| @param alpha Scalar input (Q1.15) in the format |Re0 Im0| @@ -463,11 +463,11 @@ This function performs componentwise multiplication of a vector with a complex s The function implemented is : \f$\mathbf{y} = \alpha\mathbf{x}\f$ */ -void rotate_cpx_vector(int16_t *x, - int16_t *alpha, - int16_t *y, - uint32_t N, - uint16_t output_shift); +void rotate_cpx_vector(c16_t *x, + c16_t *alpha, + c16_t *y, + uint32_t N, + uint16_t output_shift); //cadd_sv.c From ef469b9b517828b1515e19618c1a58633711fc71 Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 27 Jun 2022 18:35:38 +0200 Subject: [PATCH 175/267] code review remarks --- openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c | 3 +-- openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 3 +-- openair1/PHY/TOOLS/tools_defs.h | 8 ++++---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 5404afd432..fe23e1b56f 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -854,7 +854,6 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, uint32_t nb_re_pusch) { //#define DEBUG_UL_PTRS 1 - c16_t *phase_per_symbol = NULL; int32_t *ptrs_re_symbol = NULL; int8_t ret = 0; @@ -871,7 +870,7 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, uint8_t *ptrsReOffset = &rel15_ul->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset; /* loop over antennas */ for (int aarx=0; aarxnb_antennas_rx; aarx++) { - phase_per_symbol = (c16_t*)gNB->pusch_vars[ulsch_id]->ptrs_phase_per_slot[aarx]; + c16_t *phase_per_symbol = (c16_t*)gNB->pusch_vars[ulsch_id]->ptrs_phase_per_slot[aarx]; ptrs_re_symbol = &gNB->pusch_vars[ulsch_id]->ptrs_re_per_slot; *ptrs_re_symbol = 0; phase_per_symbol[symbol].i = 0; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index 22d7d5689f..eaeffd0809 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -598,8 +598,7 @@ uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE, for(ap = 0; ap < n_antenna_ports; ap++) { for (int s=0;ssymbol_rotation[1])[s + symb_offset]; - LOG_D(PHY,"In %s: rotating txdataF symbol %d (%d) => (%d.%d)\n", - __FUNCTION__, + LOG_D(PHY,"rotating txdataF symbol %d (%d) => (%d.%d)\n", s, s + symb_offset, rot.r, rot.i); diff --git a/openair1/PHY/TOOLS/tools_defs.h b/openair1/PHY/TOOLS/tools_defs.h index 18d1533166..c471978f46 100644 --- a/openair1/PHY/TOOLS/tools_defs.h +++ b/openair1/PHY/TOOLS/tools_defs.h @@ -464,10 +464,10 @@ This function performs componentwise multiplication of a vector with a complex s The function implemented is : \f$\mathbf{y} = \alpha\mathbf{x}\f$ */ void rotate_cpx_vector(c16_t *x, - c16_t *alpha, - c16_t *y, - uint32_t N, - uint16_t output_shift); + c16_t *alpha, + c16_t *y, + uint32_t N, + uint16_t output_shift); //cadd_sv.c From 5894bcac227d20ad6be47c7b0670bfbc98fc3f87 Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 27 Jun 2022 18:48:45 +0200 Subject: [PATCH 176/267] rebase develop --- openair1/PHY/MODULATION/ofdm_mod.c | 34 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index 678eac2f3a..609f0c75df 100644 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -46,18 +46,18 @@ void normal_prefix_mod(int32_t *txdataF,int32_t *txdata,uint8_t nsymb,LTE_DL_FRA PHY_ofdm_mod(txdataF, // input - txdata, // output - frame_parms->ofdm_symbol_size, + txdata, // output + frame_parms->ofdm_symbol_size, - 1, // number of symbols - frame_parms->nb_prefix_samples0, // number of prefix samples - CYCLIC_PREFIX); + 1, // number of symbols + frame_parms->nb_prefix_samples0, // number of prefix samples + CYCLIC_PREFIX); PHY_ofdm_mod(txdataF+frame_parms->ofdm_symbol_size, // input - txdata+OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES0, // output - frame_parms->ofdm_symbol_size, - nsymb-1, - frame_parms->nb_prefix_samples, // number of prefix samples - CYCLIC_PREFIX); + txdata+OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES0, // output + frame_parms->ofdm_symbol_size, + nsymb-1, + frame_parms->nb_prefix_samples, // number of prefix samples + CYCLIC_PREFIX); @@ -341,11 +341,11 @@ void do_OFDM_mod(int32_t **txdataF, int32_t **txdata, uint32_t frame,uint16_t ne } void apply_nr_rotation(NR_DL_FRAME_PARMS *fp, - int16_t* trxdata, - int slot, - int first_symbol, - int nsymb, - int length) { + int16_t* trxdata, + int slot, + int first_symbol, + int nsymb, + int length) { int symb_offset = (slot%fp->slots_per_subframe)*fp->symbols_per_slot; int16_t *symbol_rotation = fp->symbol_rotation[0]; @@ -362,9 +362,9 @@ void apply_nr_rotation(NR_DL_FRAME_PARMS *fp, rotate_cpx_vector((c16_t*)trxdata + (sidx * length * 2), (c16_t*)&symbol_rotation[2 * (sidx + first_symbol + symb_offset)], - (c16_t*) trxdata + (sidx * length * 2), + (c16_t*) trxdata + (sidx * length * 2), length, 15); } } - + From d6e58c94364aadfbf046f80d43e28fb1cc50f8e6 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Mon, 27 Jun 2022 23:18:06 +0100 Subject: [PATCH 177/267] Fix decoding multiple ULSCH in the same slot in the case of a ULSCH fails to be detected --- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 2c56e2e4b2..1428987d40 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -625,6 +625,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { /* those variables to log T_GNB_PHY_PUCCH_PUSCH_IQ only when we try to decode */ int pucch_decode_done = 0; int pusch_decode_done = 0; + int phy_procedures_errors = 0; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_UESPEC_RX,1); LOG_D(PHY,"phy_procedures_gNB_uespec_RX frame %d, slot %d\n",frame_rx,slot_rx); @@ -764,7 +765,8 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { if (no_sig) { LOG_D(PHY, "PUSCH not detected in frame %d, slot %d\n", frame_rx, slot_rx); nr_fill_indication(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid, 1,1); - return 1; + phy_procedures_errors++; + continue; } gNB->pusch_vars[ULSCH_id]->ulsch_power_tot=0; gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot=0; @@ -788,7 +790,8 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { /* in case of phy_test mode, we still want to decode to measure execution time. Therefore, we don't yet call nr_fill_indication, it will be called later */ nr_fill_indication(gNB,frame_rx, slot_rx, ULSCH_id, harq_pid, 1,1); - return 1; + phy_procedures_errors++; + continue; } } else { LOG_D(PHY, "PUSCH detected in %d.%d (%d,%d,%d)\n",frame_rx,slot_rx, @@ -855,5 +858,5 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_UESPEC_RX,0); - return 0; + return phy_procedures_errors; } From ff5ec94d339fab462e8f8cc1e64a993a58e11330 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 28 Jun 2022 09:38:48 +0200 Subject: [PATCH 178/267] Address review: drop bool defines --- openair2/RRC/NR/rrc_gNB_reconfig.c | 3 --- openair2/UTIL/OMG/defs.h | 6 ------ 2 files changed, 9 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index 44212cbf7a..2ee3a26c4b 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -47,9 +47,6 @@ #include "LAYER2/nr_rlc/nr_rlc_oai_api.h" #include "nr_rrc_config.h" -#define false 0 -#define true 1 - void fix_servingcellconfigdedicated(NR_ServingCellConfig_t *scd) { int b = 0; diff --git a/openair2/UTIL/OMG/defs.h b/openair2/UTIL/OMG/defs.h index 06c9bf6e73..1102a69cc5 100644 --- a/openair2/UTIL/OMG/defs.h +++ b/openair2/UTIL/OMG/defs.h @@ -29,12 +29,6 @@ #include -// TYPEDEFS - -#define true 1 -#define false 0 - -//typedef char bool; #include #include "omg_constants.h" From df1cffbc7f3f323cfe8e674546673e9f9592588d Mon Sep 17 00:00:00 2001 From: laurent Date: Wed, 29 Jun 2022 16:52:47 +0200 Subject: [PATCH 179/267] fix bug introduced by avx2 rotate_cpx change to c16_t --- cmake_targets/tools/build_helper | 4 +-- .../lte_ul_channel_estimation.c | 6 ++--- openair1/PHY/MODULATION/nr_modulation.c | 26 +++++++++---------- openair1/PHY/MODULATION/ofdm_mod.c | 12 ++++----- openair1/PHY/MODULATION/slot_fep_nr.c | 14 +++++----- openair1/PHY/defs_nr_common.h | 4 +-- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index 95f237ab33..d35f90fcce 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -197,8 +197,8 @@ check_warnings() { #argument: # $1: log file check_errors() { - #we look for 'warning:' in the compilation log file - error_count=`grep "error:" "$1" | wc -l` + #we look for 'error:' in the compilation log file + error_count=`grep -c "error:" "$1"` if [ $error_count -gt 0 ]; then echo_error "ERROR: $error_count error. See $1" fi diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c index e42f5f787c..9327fe9fe8 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c @@ -341,7 +341,7 @@ int32_t lte_ul_channel_estimation(LTE_DL_FRAME_PARMS *frame_parms, 15); rotate_cpx_vector((c16_t *) ul_ch2, (c16_t *)&ru2[2*current_phase2], - (c16_t *) &tmp_estimates[0], + (c16_t *) tmp_estimates, Msc_RS, 15); // Combine the two rotated estimates @@ -658,12 +658,12 @@ int32_t lte_ul_channel_estimation_RRU(LTE_DL_FRAME_PARMS *frame_parms, // msg("sym: %d, current_phase1: %d, ru: %d + j%d, current_phase2: %d, ru: %d + j%d\n",k,current_phase1,ru1[2*current_phase1],ru1[2*current_phase1+1],current_phase2,ru2[2*current_phase2],ru2[2*current_phase2+1]); // rotate channel estimates by estimated phase rotate_cpx_vector((c16_t *) ul_ch1, - (c16_t *)&ru1[2*current_phase1], + (c16_t *) &ru1[2*current_phase1], (c16_t *) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k], Msc_RS, 15); rotate_cpx_vector((c16_t *) ul_ch2, - (c16_t *)&ru2[2*current_phase2], + (c16_t *) &ru2[2*current_phase2], (c16_t *) &tmp_estimates[0], Msc_RS, 15); diff --git a/openair1/PHY/MODULATION/nr_modulation.c b/openair1/PHY/MODULATION/nr_modulation.c index 8352a7f5a6..8ebd70fb92 100644 --- a/openair1/PHY/MODULATION/nr_modulation.c +++ b/openair1/PHY/MODULATION/nr_modulation.c @@ -618,20 +618,20 @@ void init_symbol_rotation(NR_DL_FRAME_PARMS *fp) { double f0 = f[ll]; double Ncpm1 = Ncp0; - int16_t *symbol_rotation = fp->symbol_rotation[ll]; + c16_t *symbol_rotation = fp->symbol_rotation[ll]; double tl = 0; double poff = 2 * M_PI * ((Ncp0 * Tc)) * f0; double exp_re = cos(poff); double exp_im = sin(-poff); - symbol_rotation[0] = (int16_t)floor(exp_re * 32767); - symbol_rotation[1] = (int16_t)floor(exp_im * 32767); + symbol_rotation[0].r = (int16_t)floor(exp_re * 32767); + symbol_rotation[0].i = (int16_t)floor(exp_im * 32767); LOG_I(PHY, "Doing symbol rotation calculation for gNB TX/RX, f0 %f Hz, Nsymb %d\n", f0, nsymb); LOG_I(PHY, "Symbol rotation %d/%d => (%d,%d)\n", 0, nsymb, - symbol_rotation[0], - symbol_rotation[1]); + symbol_rotation[0].r, + symbol_rotation[0].i); for (int l = 1; l < nsymb; l++) { @@ -646,15 +646,15 @@ void init_symbol_rotation(NR_DL_FRAME_PARMS *fp) { poff = 2 * M_PI * (tl + (Ncp * Tc)) * f0; exp_re = cos(poff); exp_im = sin(-poff); - symbol_rotation[l<<1] = (int16_t)floor(exp_re * 32767); - symbol_rotation[1 + (l<<1)] = (int16_t)floor(exp_im * 32767); + symbol_rotation[l].r = (int16_t)floor(exp_re * 32767); + symbol_rotation[l].i = (int16_t)floor(exp_im * 32767); LOG_I(PHY, "Symbol rotation %d/%d => tl %f (%d,%d) (%f)\n", l, nsymb, tl, - symbol_rotation[l<<1], - symbol_rotation[1 + (l<<1)], + symbol_rotation[l].r, + symbol_rotation[l].i, (poff / 2 / M_PI) - floor(poff / 2 / M_PI)); Ncpm1 = Ncp; @@ -670,13 +670,13 @@ void init_timeshift_rotation(NR_DL_FRAME_PARMS *fp) double poff = -i * 2.0 * M_PI * sample_offset / fp->ofdm_symbol_size; double exp_re = cos(poff); double exp_im = sin(-poff); - fp->timeshift_symbol_rotation[i*2] = (int16_t)round(exp_re * 32767); - fp->timeshift_symbol_rotation[i*2+1] = (int16_t)round(exp_im * 32767); + fp->timeshift_symbol_rotation[i].r = (int16_t)round(exp_re * 32767); + fp->timeshift_symbol_rotation[i].i = (int16_t)round(exp_im * 32767); if (i < 10) LOG_I(PHY,"Timeshift symbol rotation %d => (%d,%d) %f\n",i, - fp->timeshift_symbol_rotation[i*2], - fp->timeshift_symbol_rotation[i*2+1], + fp->timeshift_symbol_rotation[i].r, + fp->timeshift_symbol_rotation[i].i, poff); } } diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index 609f0c75df..0b8f22a094 100644 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -348,7 +348,7 @@ void apply_nr_rotation(NR_DL_FRAME_PARMS *fp, int length) { int symb_offset = (slot%fp->slots_per_subframe)*fp->symbols_per_slot; - int16_t *symbol_rotation = fp->symbol_rotation[0]; + c16_t *symbol_rotation = fp->symbol_rotation[0]; for (int sidx=0;sidxrx_dft_stats); int symb_offset = (Ns%frame_parms->slots_per_subframe)*frame_parms->symbols_per_slot; - c16_t rot2 = ((c16_t*)frame_parms->symbol_rotation[0])[symbol+symb_offset]; + c16_t rot2 = frame_parms->symbol_rotation[0][symbol+symb_offset]; rot2.i=-rot2.i; #ifdef DEBUG_FEP @@ -113,10 +113,10 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, frame_parms->ofdm_symbol_size, 15); - int16_t *shift_rot = frame_parms->timeshift_symbol_rotation; + c16_t *shift_rot = frame_parms->timeshift_symbol_rotation; multadd_cpx_vector((int16_t *)&common_vars->common_vars_rx_data_per_thread[proc->thread_id].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol], - shift_rot, + (int16_t *)shift_rot, (int16_t *)&common_vars->common_vars_rx_data_per_thread[proc->thread_id].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol], 1, frame_parms->ofdm_symbol_size, @@ -214,7 +214,7 @@ int nr_slot_fep_init_sync(PHY_VARS_NR_UE *ue, stop_meas(&ue->rx_dft_stats); int symb_offset = (Ns%frame_parms->slots_per_subframe)*frame_parms->symbols_per_slot; - c16_t rot2 = ((c16_t*)frame_parms->symbol_rotation[0])[symbol + symb_offset]; + c16_t rot2 = frame_parms->symbol_rotation[0][symbol + symb_offset]; rot2.i=-rot2.i; #ifdef DEBUG_FEP @@ -310,7 +310,7 @@ void apply_nr_rotation_ul(NR_DL_FRAME_PARMS *frame_parms, for (int symbol=first_symbol;symbolsymbol_rotation[1])[symbol + symb_offset]; + c16_t rot2 = frame_parms->symbol_rotation[1][symbol + symb_offset]; rot2.i=-rot2.i; LOG_D(PHY,"slot %d, symb_offset %d rotating by %d.%d\n",slot,symb_offset,rot2.r,rot2.i); rotate_cpx_vector((c16_t *)&rxdataF[soffset+(frame_parms->ofdm_symbol_size*symbol)], @@ -319,10 +319,10 @@ void apply_nr_rotation_ul(NR_DL_FRAME_PARMS *frame_parms, length, 15); - int16_t *shift_rot = frame_parms->timeshift_symbol_rotation; + c16_t *shift_rot = frame_parms->timeshift_symbol_rotation; multadd_cpx_vector((int16_t *)&rxdataF[soffset+(frame_parms->ofdm_symbol_size*symbol)], - shift_rot, + (int16_t *)shift_rot, (int16_t *)&rxdataF[soffset+(frame_parms->ofdm_symbol_size*symbol)], 1, length, diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 9c8e90a9c7..67345b1a53 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -359,10 +359,10 @@ struct NR_DL_FRAME_PARMS { lte_prefix_type_t Ncp; /// sequence which is computed based on carrier frequency and numerology to rotate/derotate each OFDM symbol according to Section 5.3 in 38.211 /// First dimension is for the direction of the link (0 DL, 1 UL) - int16_t symbol_rotation[2][224*2]; + c16_t symbol_rotation[2][224]; /// sequence used to compensate the phase rotation due to timeshifted OFDM symbols /// First dimenstion is for different CP lengths - int16_t timeshift_symbol_rotation[4096*2] __attribute__ ((aligned (16))); + c16_t timeshift_symbol_rotation[4096*2] __attribute__ ((aligned (16))); /// shift of pilot position in one RB uint8_t nushift; /// SRS configuration from TS 38.331 RRC From c2fee0520c1bf91b33f6b8429ebef14a7d2a6add Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 30 Jun 2022 17:59:11 +0100 Subject: [PATCH 180/267] Fix variable redefinition --- openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c | 1 - 1 file changed, 1 deletion(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index f28f68acbd..f802c5b869 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -1163,7 +1163,6 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, *snr = dB_fixed((int32_t)((*signal_power<first_carrier_offset + srs_pdu->bwp_start*12; uint8_t R = srs_pdu->comb_size == 0 ? 2 : 4; for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) { for(int sc_idx = 0; sc_idx < nr_srs_info->sc_list_length; sc_idx++) { From d864cf945759a70319af8b1fd1845dc8176ffc8f Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Mon, 4 Jul 2022 11:31:33 +0100 Subject: [PATCH 181/267] Fix indentation --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 2 +- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 2ade30efc6..131cc059ac 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1018,7 +1018,7 @@ static int comparator(const void *p, const void *q) { void pf_ul(module_id_t module_id, frame_t frame, sub_frame_t slot, - NR_UE_info_t *UE_list[], + NR_UE_info_t *UE_list[], int max_num_ue, int n_rb_sched, uint16_t *rballoc_mask) { diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 119c6a3839..851890af19 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -217,7 +217,7 @@ void nr_csi_meas_reporting(int Mod_idP, sub_frame_t slotP); int nr_acknack_scheduling(int Mod_idP, - NR_UE_info_t * UE, + NR_UE_info_t *UE, frame_t frameP, sub_frame_t slotP, int r_pucch, From 2b36f2d8f282dbe555df47297145cfb1eaaf33e2 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Mon, 4 Jul 2022 14:18:04 +0100 Subject: [PATCH 182/267] Move nr_det_A_MF_2x2, nr_squared_matrix_element and nr_numer_2x2 to csi_rx.c --- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 83 +++++++++++++++++++ .../NR_UE_TRANSPORT/nr_dlsch_demodulation.c | 83 ------------------- .../NR_UE_TRANSPORT/nr_transport_proto_ue.h | 18 ---- 3 files changed, 83 insertions(+), 101 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 6be4d399bf..3a585d3eac 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -43,6 +43,89 @@ //#define NR_CSIRS_DEBUG //#define NR_CSIIM_DEBUG +void nr_det_A_MF_2x2(int32_t *a_mf_00, + int32_t *a_mf_01, + int32_t *a_mf_10, + int32_t *a_mf_11, + int32_t *det_fin, + unsigned short nb_rb) { + + int16_t nr_conjug2[8]__attribute__((aligned(16))) = {1,-1,1,-1,1,-1,1,-1} ; + + __m128i ad_re_128, bc_re_128, det_re_128; + + __m128i *a_mf_00_128 = (__m128i *)a_mf_00; + __m128i *a_mf_01_128 = (__m128i *)a_mf_01; + __m128i *a_mf_10_128 = (__m128i *)a_mf_10; + __m128i *a_mf_11_128 = (__m128i *)a_mf_11; + __m128i *det_fin_128 = (__m128i *)det_fin; + + for (int rb = 0; rb<3*nb_rb; rb++) { + + //complex multiplication (I_a+jQ_a)(I_d+jQ_d) = (I_aI_d - Q_aQ_d) + j(Q_aI_d + I_aQ_d) + //The imag part is often zero, we compute only the real part + ad_re_128 = _mm_sign_epi16(a_mf_00_128[0],*(__m128i*)&nr_conjug2[0]); + ad_re_128 = _mm_madd_epi16(ad_re_128,a_mf_11_128[0]); //Re: I_a0*I_d0 - Q_a1*Q_d1 + + //complex multiplication (I_b+jQ_b)(I_c+jQ_c) = (I_bI_c - Q_bQ_c) + j(Q_bI_c + I_bQ_c) + //The imag part is often zero, we compute only the real part + bc_re_128 = _mm_sign_epi16(a_mf_01_128[0],*(__m128i*)&nr_conjug2[0]); + bc_re_128 = _mm_madd_epi16(bc_re_128,a_mf_10_128[0]); //Re: I_b0*I_c0 - Q_b1*Q_c1 + + det_re_128 = _mm_sub_epi32(ad_re_128, bc_re_128); + + //det in Q30 format + det_fin_128[0] = _mm_abs_epi32(det_re_128); + + det_fin_128+=1; + a_mf_00_128+=1; + a_mf_01_128+=1; + a_mf_10_128+=1; + a_mf_11_128+=1; + } + _mm_empty(); + _m_empty(); +} + +void nr_squared_matrix_element(int32_t *a, + int32_t *a_sq, + unsigned short nb_rb) { + __m128i *a_128 = (__m128i *)a; + __m128i *a_sq_128 = (__m128i *)a_sq; + for (int rb=0; rb<3*nb_rb; rb++) { + a_sq_128[0] = _mm_madd_epi16(a_128[0], a_128[0]); + a_sq_128+=1; + a_128+=1; + } + _mm_empty(); + _m_empty(); +} + +void nr_numer_2x2(int32_t *a_00_sq, + int32_t *a_01_sq, + int32_t *a_10_sq, + int32_t *a_11_sq, + int32_t *num_fin, + unsigned short nb_rb) { + __m128i *a_00_sq_128 = (__m128i *)a_00_sq; + __m128i *a_01_sq_128 = (__m128i *)a_01_sq; + __m128i *a_10_sq_128 = (__m128i *)a_10_sq; + __m128i *a_11_sq_128 = (__m128i *)a_11_sq; + __m128i *num_fin_128 = (__m128i *)num_fin; + for (int rb=0; rb<3*nb_rb; rb++) { + __m128i sq_a_plus_sq_d_128 = _mm_add_epi32(a_00_sq_128[0], a_11_sq_128[0]); + __m128i sq_b_plus_sq_c_128 = _mm_add_epi32(a_01_sq_128[0], a_10_sq_128[0]); + num_fin_128[0] = _mm_add_epi32(sq_a_plus_sq_d_128, sq_b_plus_sq_c_128); + num_fin_128+=1; + a_00_sq_128+=1; + a_01_sq_128+=1; + a_10_sq_128+=1; + a_11_sq_128+=1; + } + _mm_empty(); + _m_empty(); +} + bool is_csi_rs_in_symbol(fapi_nr_dl_config_csirs_pdu_rel15_t csirs_config_pdu, int symbol) { bool ret = false; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index 19a680c6be..eb43d80525 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -1870,89 +1870,6 @@ void nr_dlsch_detection_mrc(int **rxdataF_comp, #endif } -void nr_det_A_MF_2x2(int32_t *a_mf_00, - int32_t *a_mf_01, - int32_t *a_mf_10, - int32_t *a_mf_11, - int32_t *det_fin, - unsigned short nb_rb) { - - int16_t nr_conjug2[8]__attribute__((aligned(16))) = {1,-1,1,-1,1,-1,1,-1} ; - - __m128i ad_re_128, bc_re_128, det_re_128; - - __m128i *a_mf_00_128 = (__m128i *)a_mf_00; - __m128i *a_mf_01_128 = (__m128i *)a_mf_01; - __m128i *a_mf_10_128 = (__m128i *)a_mf_10; - __m128i *a_mf_11_128 = (__m128i *)a_mf_11; - __m128i *det_fin_128 = (__m128i *)det_fin; - - for (int rb = 0; rb<3*nb_rb; rb++) { - - //complex multiplication (I_a+jQ_a)(I_d+jQ_d) = (I_aI_d - Q_aQ_d) + j(Q_aI_d + I_aQ_d) - //The imag part is often zero, we compute only the real part - ad_re_128 = _mm_sign_epi16(a_mf_00_128[0],*(__m128i*)&nr_conjug2[0]); - ad_re_128 = _mm_madd_epi16(ad_re_128,a_mf_11_128[0]); //Re: I_a0*I_d0 - Q_a1*Q_d1 - - //complex multiplication (I_b+jQ_b)(I_c+jQ_c) = (I_bI_c - Q_bQ_c) + j(Q_bI_c + I_bQ_c) - //The imag part is often zero, we compute only the real part - bc_re_128 = _mm_sign_epi16(a_mf_01_128[0],*(__m128i*)&nr_conjug2[0]); - bc_re_128 = _mm_madd_epi16(bc_re_128,a_mf_10_128[0]); //Re: I_b0*I_c0 - Q_b1*Q_c1 - - det_re_128 = _mm_sub_epi32(ad_re_128, bc_re_128); - - //det in Q30 format - det_fin_128[0] = _mm_abs_epi32(det_re_128); - - det_fin_128+=1; - a_mf_00_128+=1; - a_mf_01_128+=1; - a_mf_10_128+=1; - a_mf_11_128+=1; - } - _mm_empty(); - _m_empty(); -} - -void nr_squared_matrix_element(int32_t *a, - int32_t *a_sq, - unsigned short nb_rb) { - __m128i *a_128 = (__m128i *)a; - __m128i *a_sq_128 = (__m128i *)a_sq; - for (int rb=0; rb<3*nb_rb; rb++) { - a_sq_128[0] = _mm_madd_epi16(a_128[0], a_128[0]); - a_sq_128+=1; - a_128+=1; - } - _mm_empty(); - _m_empty(); -} - -void nr_numer_2x2(int32_t *a_00_sq, - int32_t *a_01_sq, - int32_t *a_10_sq, - int32_t *a_11_sq, - int32_t *num_fin, - unsigned short nb_rb) { - __m128i *a_00_sq_128 = (__m128i *)a_00_sq; - __m128i *a_01_sq_128 = (__m128i *)a_01_sq; - __m128i *a_10_sq_128 = (__m128i *)a_10_sq; - __m128i *a_11_sq_128 = (__m128i *)a_11_sq; - __m128i *num_fin_128 = (__m128i *)num_fin; - for (int rb=0; rb<3*nb_rb; rb++) { - __m128i sq_a_plus_sq_d_128 = _mm_add_epi32(a_00_sq_128[0], a_11_sq_128[0]); - __m128i sq_b_plus_sq_c_128 = _mm_add_epi32(a_01_sq_128[0], a_10_sq_128[0]); - num_fin_128[0] = _mm_add_epi32(sq_a_plus_sq_d_128, sq_b_plus_sq_c_128); - num_fin_128+=1; - a_00_sq_128+=1; - a_01_sq_128+=1; - a_10_sq_128+=1; - a_11_sq_128+=1; - } - _mm_empty(); - _m_empty(); -} - /* Zero Forcing Rx function: nr_a_sum_b() * Compute the complex addition x=x+y * diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index 30bc0ffe92..6d99ac9b8c 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -891,24 +891,6 @@ void nr_a_sum_b(__m128i *input_x, __m128i *input_y, unsigned short nb_rb); -void nr_det_A_MF_2x2(int32_t *a_mf_00, - int32_t *a_mf_01, - int32_t *a_mf_10, - int32_t *a_mf_11, - int32_t *det_fin, - unsigned short nb_rb); - -void nr_squared_matrix_element(int32_t *a, - int32_t *a_sq, - unsigned short nb_rb); - -void nr_numer_2x2(int32_t *a_00_sq, - int32_t *a_01_sq, - int32_t *a_10_sq, - int32_t *a_11_sq, - int32_t *num_fin, - unsigned short nb_rb); - uint8_t rank_estimation_tm3_tm4(int *dl_ch_estimates_00, int *dl_ch_estimates_01, int *dl_ch_estimates_10, From 253e037fb284239b56c05c4f7358478c86dbef03 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 5 Jul 2022 11:07:01 +0100 Subject: [PATCH 183/267] Remove some variables from nr_srs_info_t --- openair1/PHY/defs_nr_common.h | 5 ----- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 19 ++++++++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index fe895d1770..a5a0824166 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -249,11 +249,6 @@ typedef struct { int32_t **srs_estimated_channel_freq; int32_t **srs_estimated_channel_time; int32_t **srs_estimated_channel_time_shifted; - uint32_t signal_power; - uint32_t noise_power_per_rb[273]; - uint32_t noise_power; - int8_t snr_per_rb[273]; - int8_t snr; } nr_srs_info_t; typedef struct { diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 1635de7e81..f92190df56 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -848,6 +848,11 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { LOG_D(NR_PHY, "(%d.%d) gNB is waiting for SRS, id = %i\n", frame_rx, slot_rx, i); nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; + uint32_t noise_power_per_rb[srs_pdu->bwp_size]; + int8_t snr_per_rb[srs_pdu->bwp_size]; + uint32_t signal_power; + uint32_t noise_power; + int8_t snr; // At least currently, the configuration is constant, so it is enough to generate the sequence just once. if(gNB->nr_srs_info[i]->sc_list_length == 0) { @@ -867,11 +872,11 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->nr_srs_info[i]->srs_estimated_channel_freq, gNB->nr_srs_info[i]->srs_estimated_channel_time, gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted, - &gNB->nr_srs_info[i]->signal_power, - gNB->nr_srs_info[i]->noise_power_per_rb, - &gNB->nr_srs_info[i]->noise_power, - gNB->nr_srs_info[i]->snr_per_rb, - &gNB->nr_srs_info[i]->snr); + &signal_power, + noise_power_per_rb, + &noise_power, + snr_per_rb, + &snr); } T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), @@ -889,7 +894,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->srs_pdu_list[num_srs].timing_advance = srs_est >= 0 ? nr_est_timing_advance_srs(&gNB->frame_parms, (const int32_t **)gNB->nr_srs_info[i]->srs_estimated_channel_time) : 0xFFFF; gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; - gNB->srs_pdu_list[num_srs].wide_band_snr = srs_est >= 0 ? (gNB->nr_srs_info[i]->snr + 64)<<1 : 0xFF; // 0xFF will be set if this field is invalid + gNB->srs_pdu_list[num_srs].wide_band_snr = srs_est >= 0 ? (snr + 64)<<1 : 0xFF; // 0xFF will be set if this field is invalid gNB->srs_pdu_list[num_srs].num_reported_symbols = 1<num_symbols; if(!gNB->srs_pdu_list[num_srs].reported_symbol_list) { gNB->srs_pdu_list[num_srs].reported_symbol_list = (nfapi_nr_srs_indication_reported_symbol_t*) calloc(1, gNB->srs_pdu_list[num_srs].num_reported_symbols*sizeof(nfapi_nr_srs_indication_reported_symbol_t)); @@ -897,7 +902,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { fill_srs_reported_symbol_list(&gNB->srs_pdu_list[num_srs].reported_symbol_list[0], srs_pdu, gNB->frame_parms.N_RB_UL, - gNB->nr_srs_info[i]->snr_per_rb, + snr_per_rb, srs_est); gNB->UL_INFO.srs_ind.number_of_pdus += 1; From 52f6d38a3478fd6bb13bb2dd0527153003605145 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 5 Jul 2022 12:58:53 +0100 Subject: [PATCH 184/267] Remove more variables from nr_srs_info_t --- openair1/PHY/INIT/nr_init.c | 24 --------------- openair1/PHY/INIT/nr_init_ue.c | 25 ---------------- .../PHY/NR_ESTIMATION/nr_measurements_gNB.c | 2 +- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 10 +++---- openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 11 +++---- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 2 +- openair1/PHY/NR_TRANSPORT/srs_rx.c | 2 +- openair1/PHY/defs_nr_common.h | 5 ---- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 30 ++++++++++++------- 9 files changed, 33 insertions(+), 78 deletions(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index bd349d146a..4fe66a5cbf 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -613,18 +613,6 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, for (int id=0; idnr_srs_info[id] = (nr_srs_info_t *)malloc16_clear(sizeof(nr_srs_info_t)); - gNB->nr_srs_info[id]->srs_received_signal = (int32_t **)malloc16(Prx*sizeof(int32_t*)); - gNB->nr_srs_info[id]->srs_ls_estimated_channel = (int32_t **)malloc16(Prx*sizeof(int32_t*)); - gNB->nr_srs_info[id]->srs_estimated_channel_freq = (int32_t **)malloc16(Prx*sizeof(int32_t*)); - gNB->nr_srs_info[id]->srs_estimated_channel_time = (int32_t **)malloc16(Prx*sizeof(int32_t*)); - gNB->nr_srs_info[id]->srs_estimated_channel_time_shifted = (int32_t **)malloc16(Prx*sizeof(int32_t*)); - for (i=0;inr_srs_info[id]->srs_received_signal[i] = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - gNB->nr_srs_info[id]->srs_ls_estimated_channel[i] = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - gNB->nr_srs_info[id]->srs_estimated_channel_freq[i] = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - gNB->nr_srs_info[id]->srs_estimated_channel_time[i] = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - gNB->nr_srs_info[id]->srs_estimated_channel_time_shifted[i] = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - } } generate_ul_reference_signal_sequences(SHRT_MAX); @@ -782,18 +770,6 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) free_and_zero(gNB->nr_csi_rs_info); for (int id = 0; id < NUMBER_OF_NR_SRS_MAX; id++) { - for (int i = 0; i < Prx; i++) { - free_and_zero(gNB->nr_srs_info[id]->srs_received_signal[i]); - free_and_zero(gNB->nr_srs_info[id]->srs_ls_estimated_channel[i]); - free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_freq[i]); - free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_time[i]); - free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_time_shifted[i]); - } - free_and_zero(gNB->nr_srs_info[id]->srs_received_signal); - free_and_zero(gNB->nr_srs_info[id]->srs_ls_estimated_channel); - free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_freq); - free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_time); - free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_time_shifted); free_and_zero(gNB->nr_srs_info[id]); } diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 254a25097c..a332c2067c 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -377,19 +377,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) } ue->nr_srs_info = (nr_srs_info_t *)malloc16_clear(sizeof(nr_srs_info_t)); - ue->nr_srs_info->srs_received_signal = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) ); - ue->nr_srs_info->srs_ls_estimated_channel = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) ); - ue->nr_srs_info->srs_estimated_channel_freq = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) ); - ue->nr_srs_info->srs_estimated_channel_time = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) ); - ue->nr_srs_info->srs_estimated_channel_time_shifted = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) ); - for (i=0; inb_antennas_rx; i++) { - ue->nr_srs_info->srs_received_signal[i] = (int32_t *) malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - ue->nr_srs_info->srs_ls_estimated_channel[i] = (int32_t *) malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - ue->nr_srs_info->srs_estimated_channel_freq[i] = (int32_t *) malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - ue->nr_srs_info->srs_estimated_channel_time[i] = (int32_t *) malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - ue->nr_srs_info->srs_estimated_channel_time_shifted[i] = (int32_t *) malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - } - // RACH prach_vars[gNB_id]->prachF = (int16_t *)malloc16_clear( sizeof(int)*(7*2*sizeof(int)*(fp->ofdm_symbol_size*12)) ); @@ -517,18 +504,6 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) free_and_zero(ue->nr_csi_rs_info->csi_rs_estimated_channel_freq); free_and_zero(ue->nr_csi_rs_info); - for (int i = 0; i < fp->nb_antennas_rx; i++) { - free_and_zero(ue->nr_srs_info->srs_received_signal[i]); - free_and_zero(ue->nr_srs_info->srs_ls_estimated_channel[i]); - free_and_zero(ue->nr_srs_info->srs_estimated_channel_freq[i]); - free_and_zero(ue->nr_srs_info->srs_estimated_channel_time[i]); - free_and_zero(ue->nr_srs_info->srs_estimated_channel_time_shifted[i]); - } - free_and_zero(ue->nr_srs_info->srs_received_signal); - free_and_zero(ue->nr_srs_info->srs_ls_estimated_channel); - free_and_zero(ue->nr_srs_info->srs_estimated_channel_freq); - free_and_zero(ue->nr_srs_info->srs_estimated_channel_time); - free_and_zero(ue->nr_srs_info->srs_estimated_channel_time_shifted); free_and_zero(ue->nr_srs_info); free_and_zero(ue->csiim_vars[gNB_id]); diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index c1be11c468..1793a76fe1 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -68,7 +68,7 @@ int nr_est_timing_advance_pusch(PHY_VARS_gNB* gNB, int UE_id) } int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms, - const int32_t **srs_estimated_channel_time) { + const int32_t srs_estimated_channel_time[][frame_parms->ofdm_symbol_size]) { int timing_advance = 0; int max_val = 0; diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 84470be571..080b9b65d5 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -965,10 +965,11 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, const nfapi_nr_srs_pdu_t *srs_pdu, const nr_srs_info_t *nr_srs_info, const int32_t *srs_generated_signal, - const int32_t **srs_received_signal, - int32_t **srs_estimated_channel_freq, - int32_t **srs_estimated_channel_time, - int32_t **srs_estimated_channel_time_shifted, + int32_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)], + int32_t srs_ls_estimated_channel[][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)], + int32_t srs_estimated_channel_freq[][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)], + int32_t srs_estimated_channel_time[][gNB->frame_parms.ofdm_symbol_size], + int32_t srs_estimated_channel_time_shifted[][gNB->frame_parms.ofdm_symbol_size], uint32_t *signal_power, uint32_t *noise_power_per_rb, uint32_t *noise_power, @@ -981,7 +982,6 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, } const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; - int32_t **srs_ls_estimated_channel = nr_srs_info->srs_ls_estimated_channel; int16_t ch_real[frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length]; int16_t ch_imag[frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length]; diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index 01af743473..b0ed3662ea 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -56,7 +56,7 @@ void nr_gnb_measurements(PHY_VARS_gNB *gNB, uint8_t ulsch_id, unsigned char harq int nr_est_timing_advance_pusch(PHY_VARS_gNB* phy_vars_gNB, int UE_id); int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms, - const int32_t **srs_estimated_channel_time); + const int32_t srs_estimated_channel_time[][frame_parms->ofdm_symbol_size]); void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, NR_DL_FRAME_PARMS *frame_parms, @@ -72,10 +72,11 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, const nfapi_nr_srs_pdu_t *srs_pdu, const nr_srs_info_t *nr_srs_info, const int32_t *srs_generated_signal, - const int32_t **srs_received_signal, - int32_t **srs_estimated_channel_freq, - int32_t **srs_estimated_channel_time, - int32_t **srs_estimated_channel_time_shifted, + int32_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)], + int32_t srs_ls_estimated_channel[][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)], + int32_t srs_estimated_channel_freq[][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)], + int32_t srs_estimated_channel_time[][gNB->frame_parms.ofdm_symbol_size], + int32_t srs_estimated_channel_time_shifted[][gNB->frame_parms.ofdm_symbol_size], uint32_t *signal_power, uint32_t *noise_power_per_rb, uint32_t *noise_power, diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index e3b7efacfb..109fac7e2d 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -330,7 +330,7 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, int slot, nfapi_nr_srs_pdu_t *srs_pdu, nr_srs_info_t *nr_srs_info, - int32_t **srs_received_signal); + int32_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)]); void init_prach_list(PHY_VARS_gNB *gNB); void init_prach_ru_list(RU_t *ru); diff --git a/openair1/PHY/NR_TRANSPORT/srs_rx.c b/openair1/PHY/NR_TRANSPORT/srs_rx.c index ffcd7362f3..39c3846db5 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -98,7 +98,7 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, int slot, nfapi_nr_srs_pdu_t *srs_pdu, nr_srs_info_t *nr_srs_info, - int32_t **srs_received_signal) { + int32_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)]) { if(nr_srs_info->sc_list_length == 0) { LOG_E(NR_PHY, "(%d.%d) nr_srs_info was not generated yet!\n", frame, slot); diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 93c419da6f..ebcf8361f6 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -244,11 +244,6 @@ typedef struct { uint16_t sc_list[6*273]; uint8_t srs_generated_signal_bits; int32_t srs_generated_signal[OFDM_SYMBOL_SIZE_SAMPLES_MAX * MAX_NUM_NR_SRS_SYMBOLS]; - int32_t **srs_received_signal; - int32_t **srs_ls_estimated_channel; - int32_t **srs_estimated_channel_freq; - int32_t **srs_estimated_channel_time; - int32_t **srs_estimated_channel_time_shifted; } nr_srs_info_t; typedef struct { diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 635a0d0f37..d2cf0f141f 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -850,7 +850,14 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { LOG_D(NR_PHY, "(%d.%d) gNB is waiting for SRS, id = %i\n", frame_rx, slot_rx, i); + NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; + uint8_t N_symb_SRS = 1<num_symbols; + int32_t srs_received_signal[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size*N_symb_SRS]; + int32_t srs_ls_estimated_channel[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size*N_symb_SRS]; + int32_t srs_estimated_channel_freq[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size*N_symb_SRS]; + int32_t srs_estimated_channel_time[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size]; + int32_t srs_estimated_channel_time_shifted[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size]; uint32_t noise_power_per_rb[srs_pdu->bwp_size]; int8_t snr_per_rb[srs_pdu->bwp_size]; uint32_t signal_power; @@ -859,10 +866,10 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { // At least currently, the configuration is constant, so it is enough to generate the sequence just once. if(gNB->nr_srs_info[i]->sc_list_length == 0) { - generate_srs_nr(srs_pdu, &gNB->frame_parms, gNB->nr_srs_info[i]->srs_generated_signal, gNB->nr_srs_info[i], AMP, frame_rx, slot_rx); + generate_srs_nr(srs_pdu, frame_parms, gNB->nr_srs_info[i]->srs_generated_signal, gNB->nr_srs_info[i], AMP, frame_rx, slot_rx); } - const int srs_est = nr_get_srs_signal(gNB,frame_rx,slot_rx,srs_pdu, gNB->nr_srs_info[i], gNB->nr_srs_info[i]->srs_received_signal); + const int srs_est = nr_get_srs_signal(gNB,frame_rx,slot_rx, srs_pdu, gNB->nr_srs_info[i], srs_received_signal); if (srs_est >= 0) { nr_srs_channel_estimation(gNB, @@ -871,10 +878,11 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { srs_pdu, gNB->nr_srs_info[i], gNB->nr_srs_info[i]->srs_generated_signal, - (const int32_t **)gNB->nr_srs_info[i]->srs_received_signal, - gNB->nr_srs_info[i]->srs_estimated_channel_freq, - gNB->nr_srs_info[i]->srs_estimated_channel_time, - gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted, + srs_received_signal, + srs_ls_estimated_channel, + srs_estimated_channel_freq, + srs_estimated_channel_time, + srs_estimated_channel_time_shifted, &signal_power, noise_power_per_rb, &noise_power, @@ -883,10 +891,10 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { } T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), - T_BUFFER(gNB->nr_srs_info[i]->srs_estimated_channel_freq[0], gNB->frame_parms.ofdm_symbol_size*sizeof(int32_t))); + T_BUFFER(srs_estimated_channel_freq[0], frame_parms->ofdm_symbol_size*sizeof(int32_t))); T(T_GNB_PHY_UL_TIME_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), - T_BUFFER(gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted[0], gNB->frame_parms.ofdm_symbol_size*sizeof(int32_t))); + T_BUFFER(srs_estimated_channel_time_shifted[0], frame_parms->ofdm_symbol_size*sizeof(int32_t))); const uint16_t num_srs = gNB->UL_INFO.srs_ind.number_of_pdus; gNB->UL_INFO.srs_ind.pdu_list = &gNB->srs_pdu_list[0]; @@ -894,8 +902,8 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->UL_INFO.srs_ind.slot = slot_rx; gNB->srs_pdu_list[num_srs].handle = srs_pdu->handle; gNB->srs_pdu_list[num_srs].rnti = srs_pdu->rnti; - gNB->srs_pdu_list[num_srs].timing_advance = srs_est >= 0 ? nr_est_timing_advance_srs(&gNB->frame_parms, - (const int32_t **)gNB->nr_srs_info[i]->srs_estimated_channel_time) : 0xFFFF; + gNB->srs_pdu_list[num_srs].timing_advance = srs_est >= 0 ? nr_est_timing_advance_srs(frame_parms, + srs_estimated_channel_time) : 0xFFFF; gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; gNB->srs_pdu_list[num_srs].wide_band_snr = srs_est >= 0 ? (snr + 64)<<1 : 0xFF; // 0xFF will be set if this field is invalid gNB->srs_pdu_list[num_srs].num_reported_symbols = 1<num_symbols; @@ -904,7 +912,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { } fill_srs_reported_symbol_list(&gNB->srs_pdu_list[num_srs].reported_symbol_list[0], srs_pdu, - gNB->frame_parms.N_RB_UL, + frame_parms->N_RB_UL, snr_per_rb, srs_est); From 805b35643f047857fe3604c5fd1c265753418855 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 24 Jun 2022 10:37:22 +0200 Subject: [PATCH 185/267] Updates in TESTBench documentation - Correct carabe name - NR freq bands with "nXX" - add amariue in figure - minor changes --- doc/TESTBenches.md | 12 ++++++------ .../4g-faraday-bench.pdf | Bin 53134 -> 53079 bytes .../4g-faraday-bench.png | Bin 92391 -> 92377 bytes .../5g-nsa-faraday-bench.pdf | Bin 337513 -> 337509 bytes .../5g-nsa-faraday-bench.png | Bin 89436 -> 89413 bytes .../5g-nsa-faraday-bench.tex | 2 +- .../5g-ota-bench.pdf | Bin 232494 -> 232400 bytes .../5g-ota-bench.png | Bin 90027 -> 96734 bytes .../5g-ota-bench.tex | 13 +++++++++---- 9 files changed, 16 insertions(+), 11 deletions(-) diff --git a/doc/TESTBenches.md b/doc/TESTBenches.md index 547fd5a23b..7951bb6a88 100644 --- a/doc/TESTBenches.md +++ b/doc/TESTBenches.md @@ -9,19 +9,19 @@ | Machine | IP address | Lockable Resource | Function | Connected devices | | ------------- | --------------- | --------------------- | ------------------ | ----------------------------------------------------- | -| asterix | 172.21.16.127 | CI-Asterix-Usage | gNB | 173.21.19.14 | -| obelix | 172.21.16.128 | CI-Obelix-Usage | eNB, UE (5G) | 172.21.19.13, X300 (192.168.60.2), B200mini (30C51EB) | +| asterix | 172.21.16.127 | CI-Asterix-Usage | gNB (n78) | 173.21.19.14 | +| obelix | 172.21.16.128 | CI-Obelix-Usage | eNB (n40, n78), nrUE | 172.21.19.13, X300 (192.168.60.2), B200mini (30C51EB) | | porcepix | 172.21.16.136 | CI-NSA-MiniBench | Executor, EPC, 5GC | -- | | nrmodule2 | 172.21.16.139 | CI-NSA-MiniBench | Quectel | Quectel module | -| nepes | 172.21.16.137 | CI-NSA-MiniBench | gNB | B200mini (30C51D4) | +| nepes | 172.21.16.137 | CI-NSA-MiniBench | gNB (n78) | B200mini (30C51D4) | | caracal | 172.21.16.132 | CI-Caracal | gNB/phytest | N300 (192.168.10.2) | | idefix | 172.21.16.135 | CI-NSA-MiniBench | Quectel | Quectel module | -| amariue | 172.21.16.144 | CI-Amarisoft-UE-Usage | TBD | Amarisoft UE simulator | +| amariue | 172.21.16.144 | CI-Amarisoft-UE-Usage | nrUE | Amarisoft UE simulator | | bellatrix | 192.168.117.115 | CI-RAN-VM-Deployment | Executor | -- | | nano | 192.168.12.62 | CI-Bench-1-Phones | EPC, adb | 2x COTS (adb) | | hutch | 192.168.12.19 | CI-Bench-1-Phones | eNB (B7) | B200mini (30C5239) | | starsky | 192.168.12.18 | CI-Bench-1-Phones | eNB (B40) | b200mini (30A3E3C) | -| carabe | 192.168.12.211 | CI-Bench-2-OAI-Phone | UE 4G (B) | B200mini (30AE8C9) | +| carabe | 192.168.12.211 | CI-Bench-2-OAI-Phone | UE (B7UE) | B200mini (30AE8C9) | Note: The available resources, and their current usage, is indicated here: - [Lockable resources of jenkins-oai](https://jenkins-oai.eurecom.fr/lockable-resources/): @@ -40,7 +40,7 @@ Note: The available resources, and their current usage, is indicated here: ### OTA Testbench -[Proper image to be followed up. TBD: add antennas/circulators] +**Purpose**: Over-the-air 4G/5G (NSA/SA) tests Note: obelix and porcepix are both used in the OTA testbench and the 5G NSA/Faraday Cage testbench! diff --git a/doc/testbenches_doc_resources/4g-faraday-bench.pdf b/doc/testbenches_doc_resources/4g-faraday-bench.pdf index 7e31789e9acb9a3cc05719d98304966708925ff9..f6f7b078e67c61044004c70a92c729b14079cafc 100644 GIT binary patch delta 8561 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 delta 8689 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

U^jvkQkX}oYqF9J@~lgByn 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 literal 92391 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

vh4ehB$&?ymC@{5J~(+oo1-;TWB{07$j*UR>Bk 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 Date: Tue, 5 Jul 2022 17:17:40 +0100 Subject: [PATCH 186/267] To use some casts to c16_t --- openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c | 4 ++-- .../PHY/NR_ESTIMATION/nr_ul_channel_estimation.c | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index 1793a76fe1..935798334f 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -75,8 +75,8 @@ int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms, for (int i = 0; i < frame_parms->ofdm_symbol_size; i++) { int temp = 0; for (int aa = 0; aa < frame_parms->nb_antennas_rx; aa++) { - int Re = ((int16_t*)srs_estimated_channel_time[aa])[(i<<1)]; - int Im = ((int16_t*)srs_estimated_channel_time[aa])[1+(i<<1)]; + int Re = ((c16_t*)srs_estimated_channel_time[aa])[i].r; + int Im = ((c16_t*)srs_estimated_channel_time[aa])[i].i; temp += (Re*Re/2) + (Im*Im/2); } if (temp > max_val) { diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 080b9b65d5..00b053e3ff 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -999,11 +999,11 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, for(int sc_idx = 0; sc_idx < nr_srs_info->sc_list_length; sc_idx++) { - int16_t generated_real = srs_generated_signal[nr_srs_info->sc_list[sc_idx]] & 0xFFFF; - int16_t generated_imag = (srs_generated_signal[nr_srs_info->sc_list[sc_idx]] >> 16) & 0xFFFF; + int16_t generated_real = ((c16_t*)srs_generated_signal)[nr_srs_info->sc_list[sc_idx]].r; + int16_t generated_imag = ((c16_t*)srs_generated_signal)[nr_srs_info->sc_list[sc_idx]].i; - int16_t received_real = srs_received_signal[ant][nr_srs_info->sc_list[sc_idx]] & 0xFFFF; - int16_t received_imag = (srs_received_signal[ant][nr_srs_info->sc_list[sc_idx]] >> 16) & 0xFFFF; + int16_t received_real = ((c16_t*)srs_received_signal[ant])[nr_srs_info->sc_list[sc_idx]].r; + int16_t received_imag = ((c16_t*)srs_received_signal[ant])[nr_srs_info->sc_list[sc_idx]].i; // We know that nr_srs_info->srs_generated_signal_bits bits are enough to represent the generated_real and generated_imag. // So we only need a nr_srs_info->srs_generated_signal_bits shift to ensure that the result fits into 16 bits. @@ -1074,10 +1074,10 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, // Compute noise for(int sc_idx = 0; sc_idx < nr_srs_info->sc_list_length; sc_idx++) { - ch_real[ant*nr_srs_info->sc_list_length + sc_idx] = (int16_t)(srs_estimated_channel_freq[ant][nr_srs_info->sc_list[sc_idx]] & 0xFFFF); - ch_imag[ant*nr_srs_info->sc_list_length + sc_idx] = (int16_t)((srs_estimated_channel_freq[ant][nr_srs_info->sc_list[sc_idx]] >> 16) & 0xFFFF); - noise_real[ant*nr_srs_info->sc_list_length + sc_idx] = abs((int16_t)(srs_ls_estimated_channel[ant][nr_srs_info->sc_list[sc_idx]] & 0xFFFF) - ch_real[ant*nr_srs_info->sc_list_length + sc_idx]); - noise_imag[ant*nr_srs_info->sc_list_length + sc_idx] = abs((int16_t)((srs_ls_estimated_channel[ant][nr_srs_info->sc_list[sc_idx]] >> 16) & 0xFFFF) - ch_imag[ant*nr_srs_info->sc_list_length + sc_idx]); + ch_real[ant*nr_srs_info->sc_list_length + sc_idx] = ((c16_t*)srs_estimated_channel_freq[ant])[nr_srs_info->sc_list[sc_idx]].r; + ch_imag[ant*nr_srs_info->sc_list_length + sc_idx] = ((c16_t*)srs_estimated_channel_freq[ant])[nr_srs_info->sc_list[sc_idx]].i; + noise_real[ant*nr_srs_info->sc_list_length + sc_idx] = abs(((c16_t*)srs_ls_estimated_channel[ant])[nr_srs_info->sc_list[sc_idx]].r - ch_real[ant*nr_srs_info->sc_list_length + sc_idx]); + noise_imag[ant*nr_srs_info->sc_list_length + sc_idx] = abs(((c16_t*)srs_ls_estimated_channel[ant])[nr_srs_info->sc_list[sc_idx]].i - ch_imag[ant*nr_srs_info->sc_list_length + sc_idx]); } // Convert to time domain From d68f7d6270df9806cc833fc98d45b5db693433ce Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 5 Jul 2022 17:50:58 +0100 Subject: [PATCH 187/267] Add help string --- openair2/GNB_APP/MACRLC_nr_paramdef.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index 22b83f4064..4359cb0c86 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -97,7 +97,7 @@ {CONFIG_STRING_MACRLC_ULSCH_MAX_FRAME_INACTIVITY, NULL, 0, uptr:NULL, defintval:10, TYPE_UINT, 0}, \ {CONFIG_STRING_MACRLC_PUSCHTARGETSNRX10, NULL, 0, iptr:NULL, defintval:200, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUCCHTARGETSNRX10, NULL, 0, iptr:NULL, defintval:150, TYPE_INT, 0}, \ -{CONFIG_STRING_MACRLC_UL_PRBBLACK_SNR_THRESHOLD, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ +{CONFIG_STRING_MACRLC_UL_PRBBLACK_SNR_THRESHOLD, "SNR threshold to decide whether a PRB will be blacklisted or not", 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUCCHFAILURETHRES, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUSCHFAILURETHRES, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_DL_BLER_TARGET_UPPER, "Upper threshold of BLER to decrease DL MCS", 0, dblptr:NULL, defdblval:0.15, TYPE_DOUBLE, 0}, \ From 24745eafca450f4f7fde10b2bf8986ab883a4a89 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Wed, 6 Jul 2022 08:45:48 +0100 Subject: [PATCH 188/267] Rename variable from phy_procedures_errors to pusch_DTX --- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 1428987d40..8e1f2bbd4c 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -625,7 +625,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { /* those variables to log T_GNB_PHY_PUCCH_PUSCH_IQ only when we try to decode */ int pucch_decode_done = 0; int pusch_decode_done = 0; - int phy_procedures_errors = 0; + int pusch_DTX = 0; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_UESPEC_RX,1); LOG_D(PHY,"phy_procedures_gNB_uespec_RX frame %d, slot %d\n",frame_rx,slot_rx); @@ -765,7 +765,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { if (no_sig) { LOG_D(PHY, "PUSCH not detected in frame %d, slot %d\n", frame_rx, slot_rx); nr_fill_indication(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid, 1,1); - phy_procedures_errors++; + pusch_DTX++; continue; } gNB->pusch_vars[ULSCH_id]->ulsch_power_tot=0; @@ -790,7 +790,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { /* in case of phy_test mode, we still want to decode to measure execution time. Therefore, we don't yet call nr_fill_indication, it will be called later */ nr_fill_indication(gNB,frame_rx, slot_rx, ULSCH_id, harq_pid, 1,1); - phy_procedures_errors++; + pusch_DTX++; continue; } } else { @@ -858,5 +858,5 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_UESPEC_RX,0); - return phy_procedures_errors; + return pusch_DTX; } From 0c2b3a1eebe028f24b88a09e931007b51656fb37 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 6 Jul 2022 20:18:44 +0100 Subject: [PATCH 189/267] Remove some variables from nr_csi_rs_info_t --- .../nfapi/public_inc/fapi_nr_ue_interface.h | 8 +- openair1/PHY/INIT/nr_init_ue.c | 17 -- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 224 ++++++++++-------- openair1/PHY/defs_nr_common.h | 13 - openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 14 +- 5 files changed, 130 insertions(+), 146 deletions(-) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index f8ba448727..6e1a4adb65 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -48,10 +48,10 @@ typedef struct { } fapi_nr_uci_pdu_rel15_t; typedef struct { - uint8_t *rank_indicator; - uint8_t *i1; - uint8_t *i2; - uint8_t *cqi; + uint8_t rank_indicator; + uint8_t i1; + uint8_t i2; + uint8_t cqi; } fapi_nr_csirs_measurements_t; typedef struct { diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index ac2b7e21f6..cb174dc81f 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -358,12 +358,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) AssertFatal(ue->nr_csi_rs_info->nr_gold_csi_rs[slot][symb]!=NULL, "NR init: csi reference signal for slot %d symbol %d - malloc failed\n", slot, symb); } } - ue->nr_csi_rs_info->noise_power = (uint32_t*)malloc16_clear(sizeof(uint32_t)); - ue->nr_csi_rs_info->rank_indicator = (uint8_t*)malloc16_clear(sizeof(uint8_t)); - ue->nr_csi_rs_info->i1 = (uint8_t*)malloc16_clear(3*sizeof(uint8_t)); - ue->nr_csi_rs_info->i2 = (uint8_t*)malloc16_clear(sizeof(uint8_t)); - ue->nr_csi_rs_info->precoded_sinr_dB = (uint32_t*)malloc16_clear(sizeof(uint32_t)); - ue->nr_csi_rs_info->cqi = (uint8_t*)malloc16_clear(sizeof(uint8_t)); ue->nr_csi_rs_info->csi_rs_generated_signal = (int32_t **)malloc16(NR_MAX_NB_PORTS * sizeof(int32_t *) ); for (i=0; inr_csi_rs_info->csi_rs_generated_signal[i] = (int32_t *) malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t)); @@ -497,7 +491,6 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) for (int gNB_id = 0; gNB_id < ue->n_connected_gNB; gNB_id++) { for (int th_id = 0; th_id < RX_NB_TH_MAX; th_id++) { - free_and_zero(ue->pdcch_vars[th_id][gNB_id]); } @@ -519,17 +512,7 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) } free_and_zero(ue->nr_csi_rs_info->nr_gold_csi_rs[slot]); } - free_and_zero(ue->nr_csi_rs_info->noise_power); - free_and_zero(ue->nr_csi_rs_info->rank_indicator); - free_and_zero(ue->nr_csi_rs_info->i1); - free_and_zero(ue->nr_csi_rs_info->i2); - free_and_zero(ue->nr_csi_rs_info->precoded_sinr_dB); - free_and_zero(ue->nr_csi_rs_info->cqi); free_and_zero(ue->nr_csi_rs_info->nr_gold_csi_rs); - free_and_zero(ue->nr_csi_rs_info->csi_rs_generated_signal); - free_and_zero(ue->nr_csi_rs_info->csi_rs_received_signal); - free_and_zero(ue->nr_csi_rs_info->csi_rs_ls_estimated_channel); - free_and_zero(ue->nr_csi_rs_info->csi_rs_estimated_channel_freq); free_and_zero(ue->nr_csi_rs_info); free_and_zero(ue->nr_csi_im_info); diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 3a585d3eac..482f2ea2a5 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -48,7 +48,7 @@ void nr_det_A_MF_2x2(int32_t *a_mf_00, int32_t *a_mf_10, int32_t *a_mf_11, int32_t *det_fin, - unsigned short nb_rb) { + const unsigned short nb_rb) { int16_t nr_conjug2[8]__attribute__((aligned(16))) = {1,-1,1,-1,1,-1,1,-1} ; @@ -89,7 +89,7 @@ void nr_det_A_MF_2x2(int32_t *a_mf_00, void nr_squared_matrix_element(int32_t *a, int32_t *a_sq, - unsigned short nb_rb) { + const unsigned short nb_rb) { __m128i *a_128 = (__m128i *)a; __m128i *a_sq_128 = (__m128i *)a_sq; for (int rb=0; rb<3*nb_rb; rb++) { @@ -106,7 +106,7 @@ void nr_numer_2x2(int32_t *a_00_sq, int32_t *a_10_sq, int32_t *a_11_sq, int32_t *num_fin, - unsigned short nb_rb) { + const unsigned short nb_rb) { __m128i *a_00_sq_128 = (__m128i *)a_00_sq; __m128i *a_01_sq_128 = (__m128i *)a_01_sq; __m128i *a_10_sq_128 = (__m128i *)a_10_sq; @@ -126,7 +126,7 @@ void nr_numer_2x2(int32_t *a_00_sq, _m_empty(); } -bool is_csi_rs_in_symbol(fapi_nr_dl_config_csirs_pdu_rel15_t csirs_config_pdu, int symbol) { +bool is_csi_rs_in_symbol(const fapi_nr_dl_config_csirs_pdu_rel15_t csirs_config_pdu, const int symbol) { bool ret = false; @@ -174,14 +174,14 @@ bool is_csi_rs_in_symbol(fapi_nr_dl_config_csirs_pdu_rel15_t csirs_config_pdu, i return ret; } -int nr_get_csi_rs_signal(PHY_VARS_NR_UE *ue, - UE_nr_rxtx_proc_t *proc, - fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, - nr_csi_rs_info_t *nr_csi_rs_info, +int nr_get_csi_rs_signal(const PHY_VARS_NR_UE *ue, + const UE_nr_rxtx_proc_t *proc, + const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, + const nr_csi_rs_info_t *nr_csi_rs_info, int32_t **csi_rs_received_signal) { int32_t **rxdataF = ue->common_vars.common_vars_rx_data_per_thread[proc->thread_id].rxdataF; - NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + const NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) { memset(csi_rs_received_signal[ant_rx], 0, frame_parms->samples_per_frame_wCP*sizeof(int32_t)); @@ -234,7 +234,7 @@ int nr_get_csi_rs_signal(PHY_VARS_NR_UE *ue, return 0; } -uint32_t calc_power_csirs(uint16_t *x, fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu) { +uint32_t calc_power_csirs(const uint16_t *x, const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu) { uint64_t sum_x = 0; uint64_t sum_x2 = 0; uint16_t size = 0; @@ -249,17 +249,20 @@ uint32_t calc_power_csirs(uint16_t *x, fapi_nr_dl_config_csirs_pdu_rel15_t *csir return sum_x2/size - (sum_x/size)*(sum_x/size); } -int nr_csi_rs_channel_estimation(PHY_VARS_NR_UE *ue, - UE_nr_rxtx_proc_t *proc, - fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, - nr_csi_rs_info_t *nr_csi_rs_info, - int32_t **csi_rs_generated_signal, - int32_t **csi_rs_received_signal, +int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, + const UE_nr_rxtx_proc_t *proc, + const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, + const nr_csi_rs_info_t *nr_csi_rs_info, + const int32_t **csi_rs_generated_signal, + const int32_t **csi_rs_received_signal, + int32_t ***csi_rs_ls_estimated_channel, int32_t ***csi_rs_estimated_channel_freq, + int16_t *log2_re, + int16_t *log2_maxh, uint32_t *noise_power) { - NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; - int dataF_offset = proc->nr_slot_rx*ue->frame_parms.samples_per_slot_wCP; + const NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + const int dataF_offset = proc->nr_slot_rx*ue->frame_parms.samples_per_slot_wCP; *noise_power = 0; int maxh = 0; int count = 0; @@ -407,8 +410,8 @@ int nr_csi_rs_channel_estimation(PHY_VARS_NR_UE *ue, } *noise_power /= (frame_parms->nb_antennas_rx*nr_csi_rs_info->N_ports); - nr_csi_rs_info->log2_maxh = log2_approx(maxh-1); - nr_csi_rs_info->log2_re = log2_approx(count-1); + *log2_maxh = log2_approx(maxh-1); + *log2_re = log2_approx(count-1); #ifdef NR_CSIRS_DEBUG LOG_I(NR_PHY, "Noise power estimation based on CSI-RS: %i\n", *noise_power); @@ -417,14 +420,15 @@ int nr_csi_rs_channel_estimation(PHY_VARS_NR_UE *ue, return 0; } -int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, - fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, - nr_csi_rs_info_t *nr_csi_rs_info, +int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue, + const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, + const nr_csi_rs_info_t *nr_csi_rs_info, int32_t ***csi_rs_estimated_channel_freq, + const int16_t log2_maxh, uint8_t *rank_indicator) { - NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; - int16_t cond_dB_threshold = 5; + const NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + const int16_t cond_dB_threshold = 5; int count = 0; *rank_indicator = 0; @@ -441,14 +445,14 @@ int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, * | conjch01 conjch11 | | ch10 ch11 | | conjch01*ch00+conjch11*ch10 conjch01*ch01+conjch11*ch11 | */ - uint8_t sum_shift = 1; // log2(2x2) = 2, which is a shift of 1 bit - - for(uint16_t port_tx_conjch = 0; port_tx_conjch < nr_csi_rs_info->N_ports; port_tx_conjch++) { - for(uint16_t port_tx_ch = 0; port_tx_ch < nr_csi_rs_info->N_ports; port_tx_ch++) { - memset(nr_csi_rs_info->csi_rs_estimated_A_MF[port_tx_conjch][port_tx_ch],0,NR_MAX_OFDM_SYMBOL_SIZE*sizeof(int32_t)); - } - } + int32_t csi_rs_estimated_conjch_ch[frame_parms->nb_antennas_rx][nr_csi_rs_info->N_ports][frame_parms->nb_antennas_rx][nr_csi_rs_info->N_ports][frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); + int32_t csi_rs_estimated_A_MF[nr_csi_rs_info->N_ports][nr_csi_rs_info->N_ports][frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); + int32_t csi_rs_estimated_A_MF_sq[nr_csi_rs_info->N_ports][nr_csi_rs_info->N_ports][frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); + int32_t csi_rs_estimated_determ_fin[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); + int32_t csi_rs_estimated_numer_fin[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); + const uint8_t sum_shift = 1; // log2(2x2) = 2, which is a shift of 1 bit + for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) { if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) { @@ -464,14 +468,14 @@ int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, // conjch x ch computation nr_conjch0_mult_ch1(&csi_rs_estimated_channel_freq[ant_rx_conjch][port_tx_conjch][k], &csi_rs_estimated_channel_freq[ant_rx_ch][port_tx_ch][k], - &nr_csi_rs_info->csi_rs_estimated_conjch_ch[ant_rx_conjch][port_tx_conjch][ant_rx_ch][port_tx_ch][k], + &csi_rs_estimated_conjch_ch[ant_rx_conjch][port_tx_conjch][ant_rx_ch][port_tx_ch][k], 1, - nr_csi_rs_info->log2_maxh); + log2_maxh); // construct Hh x H elements if(ant_rx_conjch == ant_rx_ch) { - nr_a_sum_b((__m128i *)&nr_csi_rs_info->csi_rs_estimated_A_MF[port_tx_conjch][port_tx_ch][k], - (__m128i *)&nr_csi_rs_info->csi_rs_estimated_conjch_ch[ant_rx_conjch][port_tx_conjch][ant_rx_ch][port_tx_ch][k], + nr_a_sum_b((__m128i *)&csi_rs_estimated_A_MF[port_tx_conjch][port_tx_ch][k], + (__m128i *)&csi_rs_estimated_conjch_ch[ant_rx_conjch][port_tx_conjch][ant_rx_ch][port_tx_ch][k], 1); } } @@ -480,44 +484,44 @@ int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, } // compute the determinant of A_MF (denominator) - nr_det_A_MF_2x2(&nr_csi_rs_info->csi_rs_estimated_A_MF[0][0][k], - &nr_csi_rs_info->csi_rs_estimated_A_MF[0][1][k], - &nr_csi_rs_info->csi_rs_estimated_A_MF[1][0][k], - &nr_csi_rs_info->csi_rs_estimated_A_MF[1][1][k], - &nr_csi_rs_info->csi_rs_estimated_determ_fin[k], + nr_det_A_MF_2x2(&csi_rs_estimated_A_MF[0][0][k], + &csi_rs_estimated_A_MF[0][1][k], + &csi_rs_estimated_A_MF[1][0][k], + &csi_rs_estimated_A_MF[1][1][k], + &csi_rs_estimated_determ_fin[k], 1); // compute the square of A_MF (numerator) - nr_squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[0][0][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][0][k], 1); - nr_squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[0][1][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][1][k], 1); - nr_squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[1][0][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][0][k], 1); - nr_squared_matrix_element(&nr_csi_rs_info->csi_rs_estimated_A_MF[1][1][k], &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][1][k], 1); - nr_numer_2x2(&nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][0][k], - &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[0][1][k], - &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][0][k], - &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[1][1][k], - &nr_csi_rs_info->csi_rs_estimated_numer_fin[k], + nr_squared_matrix_element(&csi_rs_estimated_A_MF[0][0][k], &csi_rs_estimated_A_MF_sq[0][0][k], 1); + nr_squared_matrix_element(&csi_rs_estimated_A_MF[0][1][k], &csi_rs_estimated_A_MF_sq[0][1][k], 1); + nr_squared_matrix_element(&csi_rs_estimated_A_MF[1][0][k], &csi_rs_estimated_A_MF_sq[1][0][k], 1); + nr_squared_matrix_element(&csi_rs_estimated_A_MF[1][1][k], &csi_rs_estimated_A_MF_sq[1][1][k], 1); + nr_numer_2x2(&csi_rs_estimated_A_MF_sq[0][0][k], + &csi_rs_estimated_A_MF_sq[0][1][k], + &csi_rs_estimated_A_MF_sq[1][0][k], + &csi_rs_estimated_A_MF_sq[1][1][k], + &csi_rs_estimated_numer_fin[k], 1); #ifdef NR_CSIRS_DEBUG for(uint16_t port_tx_conjch = 0; port_tx_conjch < nr_csi_rs_info->N_ports; port_tx_conjch++) { for(uint16_t port_tx_ch = 0; port_tx_ch < nr_csi_rs_info->N_ports; port_tx_ch++) { - int16_t *csi_rs_estimated_A_MF = (int16_t *) &nr_csi_rs_info->csi_rs_estimated_A_MF[port_tx_conjch][port_tx_ch][k]; + int16_t *csi_rs_estimated_A_MF_k = (int16_t *) &csi_rs_estimated_A_MF[port_tx_conjch][port_tx_ch][k]; LOG_I(NR_PHY, "(%i) csi_rs_estimated_A_MF[%i][%i] = (%i, %i)\n", - k, port_tx_conjch, port_tx_ch, csi_rs_estimated_A_MF[0], csi_rs_estimated_A_MF[1]); - int16_t *csi_rs_estimated_A_MF_sq = (int16_t *) &nr_csi_rs_info->csi_rs_estimated_A_MF_sq[port_tx_conjch][port_tx_ch][k]; + k, port_tx_conjch, port_tx_ch, csi_rs_estimated_A_MF_k[0], csi_rs_estimated_A_MF_k[1]); + int16_t *csi_rs_estimated_A_MF_sq_k = (int16_t *) &csi_rs_estimated_A_MF_sq[port_tx_conjch][port_tx_ch][k]; LOG_I(NR_PHY, "(%i) csi_rs_estimated_A_MF_sq[%i][%i] = (%i, %i)\n", - k, port_tx_conjch, port_tx_ch, csi_rs_estimated_A_MF_sq[0], csi_rs_estimated_A_MF_sq[1]); + k, port_tx_conjch, port_tx_ch, csi_rs_estimated_A_MF_sq_k[0], csi_rs_estimated_A_MF_sq_k[1]); } } - LOG_I(NR_PHY, "(%i) csi_rs_estimated_determ_fin = %i\n", k, nr_csi_rs_info->csi_rs_estimated_determ_fin[k]); - LOG_I(NR_PHY, "(%i) csi_rs_estimated_numer_fin = %i\n", k, nr_csi_rs_info->csi_rs_estimated_numer_fin[k]>>sum_shift); + LOG_I(NR_PHY, "(%i) csi_rs_estimated_determ_fin = %i\n", k, csi_rs_estimated_determ_fin[k]); + LOG_I(NR_PHY, "(%i) csi_rs_estimated_numer_fin = %i\n", k, csi_rs_estimated_numer_fin[k]>>sum_shift); #endif // compute the conditional number for (int sc_idx=0; sc_idx < NR_NB_SC_PER_RB; sc_idx++) { - int8_t csi_rs_estimated_denum_db = dB_fixed(nr_csi_rs_info->csi_rs_estimated_determ_fin[k + sc_idx]); - int8_t csi_rs_estimated_numer_db = dB_fixed(nr_csi_rs_info->csi_rs_estimated_numer_fin[k + sc_idx]>>sum_shift); + int8_t csi_rs_estimated_denum_db = dB_fixed(csi_rs_estimated_determ_fin[k + sc_idx]); + int8_t csi_rs_estimated_numer_db = dB_fixed(csi_rs_estimated_numer_fin[k + sc_idx]>>sum_shift); int8_t cond_db = csi_rs_estimated_numer_db - csi_rs_estimated_denum_db; #ifdef NR_CSIRS_DEBUG @@ -547,17 +551,18 @@ int nr_csi_rs_ri_estimation(PHY_VARS_NR_UE *ue, return 0; } -int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, - fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, - nr_csi_rs_info_t *nr_csi_rs_info, - int32_t ***csi_rs_estimated_channel_freq, - uint32_t interference_plus_noise_power, - uint8_t rank_indicator, +int nr_csi_rs_pmi_estimation(const PHY_VARS_NR_UE *ue, + const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, + const nr_csi_rs_info_t *nr_csi_rs_info, + const int32_t ***csi_rs_estimated_channel_freq, + const uint32_t interference_plus_noise_power, + const uint8_t rank_indicator, + const int16_t log2_re, uint8_t *i1, uint8_t *i2, uint32_t *precoded_sinr_dB) { - NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + const NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; memset(i1,0,3*sizeof(uint8_t)); i2[0] = 0; @@ -597,34 +602,34 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, // H_p0 + 1*H_p1 = (H_p0_re + H_p1_re) + 1j*(H_p0_im + H_p1_im) sum_re[0] += (csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[0]); sum_im[0] += (csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[1]); - sum2_re[0] += ((csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[0]))>>nr_csi_rs_info->log2_re; - sum2_im[0] += ((csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[1]))>>nr_csi_rs_info->log2_re; + sum2_re[0] += ((csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[0]))>>log2_re; + sum2_im[0] += ((csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[1]))>>log2_re; // H_p0 + 1j*H_p1 = (H_p0_re - H_p1_im) + 1j*(H_p0_im + H_p1_re) sum_re[1] += (csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[1]); sum_im[1] += (csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[0]); - sum2_re[1] += ((csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[1]))>>nr_csi_rs_info->log2_re; - sum2_im[1] += ((csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[0]))>>nr_csi_rs_info->log2_re; + sum2_re[1] += ((csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[1]))>>log2_re; + sum2_im[1] += ((csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[0]))>>log2_re; // H_p0 - 1*H_p1 = (H_p0_re - H_p1_re) + 1j*(H_p0_im - H_p1_im) sum_re[2] += (csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[0]); sum_im[2] += (csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[1]); - sum2_re[2] += ((csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[0]))>>nr_csi_rs_info->log2_re; - sum2_im[2] += ((csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[1]))>>nr_csi_rs_info->log2_re; + sum2_re[2] += ((csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[0]))>>log2_re; + sum2_im[2] += ((csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[1]))>>log2_re; // H_p0 - 1j*H_p1 = (H_p0_re + H_p1_im) + 1j*(H_p0_im - H_p1_re) sum_re[3] += (csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[1]); sum_im[3] += (csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[0]); - sum2_re[3] += ((csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[1]))>>nr_csi_rs_info->log2_re; - sum2_im[3] += ((csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[0]))>>nr_csi_rs_info->log2_re; + sum2_re[3] += ((csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[1]))>>log2_re; + sum2_im[3] += ((csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[0]))>>log2_re; } } // We should perform >>nr_csi_rs_info->log2_re here for all terms, but since sum2_re and sum2_im can be high values, // we performed this above. for(int p = 0; p<4; p++) { - int32_t power_re = sum2_re[p] - (sum_re[p]>>nr_csi_rs_info->log2_re)*(sum_re[p]>>nr_csi_rs_info->log2_re); - int32_t power_im = sum2_im[p] - (sum_im[p]>>nr_csi_rs_info->log2_re)*(sum_im[p]>>nr_csi_rs_info->log2_re); + int32_t power_re = sum2_re[p] - (sum_re[p]>>log2_re)*(sum_re[p]>>log2_re); + int32_t power_im = sum2_im[p] - (sum_im[p]>>log2_re)*(sum_im[p]>>log2_re); tested_precoded_sinr[p] = (power_re+power_im)/(int32_t)interference_plus_noise_power; } @@ -648,7 +653,7 @@ int nr_csi_rs_pmi_estimation(PHY_VARS_NR_UE *ue, return 0; } -int nr_csi_rs_cqi_estimation(uint32_t precoded_sinr, +int nr_csi_rs_cqi_estimation(const uint32_t precoded_sinr, uint8_t *cqi) { *cqi = 0; @@ -683,16 +688,16 @@ int nr_csi_rs_cqi_estimation(uint32_t precoded_sinr, return 0; } -int nr_csi_im_power_estimation(PHY_VARS_NR_UE *ue, - UE_nr_rxtx_proc_t *proc, - fapi_nr_dl_config_csiim_pdu_rel15_t *csiim_config_pdu, +int nr_csi_im_power_estimation(const PHY_VARS_NR_UE *ue, + const UE_nr_rxtx_proc_t *proc, + const fapi_nr_dl_config_csiim_pdu_rel15_t *csiim_config_pdu, uint32_t *interference_plus_noise_power) { int32_t **rxdataF = ue->common_vars.common_vars_rx_data_per_thread[proc->thread_id].rxdataF; - NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + const NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; - uint16_t end_rb = csiim_config_pdu->start_rb + csiim_config_pdu->nr_of_rbs > csiim_config_pdu->bwp_size ? - csiim_config_pdu->bwp_size : csiim_config_pdu->start_rb + csiim_config_pdu->nr_of_rbs; + const uint16_t end_rb = csiim_config_pdu->start_rb + csiim_config_pdu->nr_of_rbs > csiim_config_pdu->bwp_size ? + csiim_config_pdu->bwp_size : csiim_config_pdu->start_rb + csiim_config_pdu->nr_of_rbs; int32_t count = 0; int32_t sum_re = 0; @@ -763,7 +768,7 @@ int nr_ue_csi_im_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t return -1; } - fapi_nr_dl_config_csiim_pdu_rel15_t *csiim_config_pdu = (fapi_nr_dl_config_csiim_pdu_rel15_t*)&ue->csiim_vars[gNB_id]->csiim_config_pdu; + const fapi_nr_dl_config_csiim_pdu_rel15_t *csiim_config_pdu = (fapi_nr_dl_config_csiim_pdu_rel15_t*)&ue->csiim_vars[gNB_id]->csiim_config_pdu; #ifdef NR_CSIIM_DEBUG LOG_I(NR_PHY, "csiim_config_pdu->bwp_size = %i\n", csiim_config_pdu->bwp_size); @@ -787,7 +792,7 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t return -1; } - fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu = (fapi_nr_dl_config_csirs_pdu_rel15_t*)&ue->csirs_vars[gNB_id]->csirs_config_pdu; + const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu = (fapi_nr_dl_config_csirs_pdu_rel15_t*)&ue->csirs_vars[gNB_id]->csirs_config_pdu; #ifdef NR_CSIRS_DEBUG LOG_I(NR_PHY, "csirs_config_pdu->subcarrier_spacing = %i\n", csirs_config_pdu->subcarrier_spacing); @@ -806,6 +811,15 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t LOG_I(NR_PHY, "csirs_config_pdu->power_control_offset_ss = %i\n", csirs_config_pdu->power_control_offset_ss); #endif + int16_t log2_re = 0; + int16_t log2_maxh = 0; + uint32_t noise_power = 0; + uint8_t rank_indicator = 0; + uint32_t precoded_sinr_dB = 0; + uint8_t cqi = 0; + uint8_t i1[3]; + uint8_t i2[1]; + nr_generate_csi_rs(ue->frame_parms, ue->nr_csi_rs_info->csi_rs_generated_signal, AMP, @@ -823,43 +837,43 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t proc, csirs_config_pdu, ue->nr_csi_rs_info, - ue->nr_csi_rs_info->csi_rs_generated_signal, - ue->nr_csi_rs_info->csi_rs_received_signal, + (const int32_t **) ue->nr_csi_rs_info->csi_rs_generated_signal, + (const int32_t **) ue->nr_csi_rs_info->csi_rs_received_signal, + ue->nr_csi_rs_info->csi_rs_ls_estimated_channel, ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, - ue->nr_csi_rs_info->noise_power); + &log2_re, + &log2_maxh, + &noise_power); nr_csi_rs_ri_estimation(ue, csirs_config_pdu, ue->nr_csi_rs_info, ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, - ue->nr_csi_rs_info->rank_indicator); + log2_maxh, + &rank_indicator); nr_csi_rs_pmi_estimation(ue, csirs_config_pdu, ue->nr_csi_rs_info, - ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, - ue->nr_csi_im_info->meas_computed ? ue->nr_csi_im_info->interference_plus_noise_power : *ue->nr_csi_rs_info->noise_power, - *ue->nr_csi_rs_info->rank_indicator, - ue->nr_csi_rs_info->i1, - ue->nr_csi_rs_info->i2, - ue->nr_csi_rs_info->precoded_sinr_dB); + (const int32_t ***) ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, + ue->nr_csi_im_info->meas_computed ? ue->nr_csi_im_info->interference_plus_noise_power : noise_power, + rank_indicator, + log2_re, + i1, + i2, + &precoded_sinr_dB); - nr_csi_rs_cqi_estimation(*ue->nr_csi_rs_info->precoded_sinr_dB, - ue->nr_csi_rs_info->cqi); + nr_csi_rs_cqi_estimation(precoded_sinr_dB, &cqi); LOG_I(NR_PHY, "RI = %i, i1 = %i.%i.%i, i2 = %i, SINR = %i dB, CQI = %i\n", - *ue->nr_csi_rs_info->rank_indicator + 1, - ue->nr_csi_rs_info->i1[0], ue->nr_csi_rs_info->i1[1], ue->nr_csi_rs_info->i1[2], - ue->nr_csi_rs_info->i2[0], - *ue->nr_csi_rs_info->precoded_sinr_dB, - *ue->nr_csi_rs_info->cqi); + rank_indicator+1, i1[0], i1[1], i1[2], i2[0], precoded_sinr_dB, cqi); // Send CSI measurements to MAC fapi_nr_csirs_measurements_t csirs_measurements; - csirs_measurements.rank_indicator = ue->nr_csi_rs_info->rank_indicator; - csirs_measurements.i1 = ue->nr_csi_rs_info->i1; - csirs_measurements.i2 = ue->nr_csi_rs_info->i2; - csirs_measurements.cqi = ue->nr_csi_rs_info->cqi; + csirs_measurements.rank_indicator = rank_indicator; + csirs_measurements.i1 = *i1; + csirs_measurements.i2 = *i2; + csirs_measurements.cqi = cqi; nr_downlink_indication_t *dl_indication = calloc(sizeof(*dl_indication),1); fapi_nr_rx_indication_t *rx_ind = calloc(sizeof(*rx_ind),1); nr_fill_dl_indication(dl_indication, NULL, rx_ind, proc, ue, gNB_id, NULL); diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 1b7dffb04e..34f089d9f9 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -269,19 +269,6 @@ typedef struct { int32_t **csi_rs_received_signal; int32_t ***csi_rs_ls_estimated_channel; int32_t ***csi_rs_estimated_channel_freq; - int16_t log2_re; - int16_t log2_maxh; - int32_t csi_rs_estimated_conjch_ch[4][4][4][4][NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32))); - int32_t csi_rs_estimated_A_MF[2][2][NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32))); - int32_t csi_rs_estimated_A_MF_sq[2][2][NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32))); - int32_t csi_rs_estimated_determ_fin[NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32))); - int32_t csi_rs_estimated_numer_fin[NR_MAX_OFDM_SYMBOL_SIZE] __attribute__((aligned(32))); - uint32_t *noise_power; - uint8_t *rank_indicator; - uint8_t *i1; - uint8_t *i2; - uint32_t *precoded_sinr_dB; - uint8_t *cqi; } nr_csi_rs_info_t; typedef struct { diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index a41b9db0cb..67331c1865 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2688,16 +2688,16 @@ uint8_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, int cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; int ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; - int pmi_x1_bitlen = csi_report->csi_meas_bitlen.pmi_x1_bitlen[*mac->csirs_measurements.rank_indicator]; - int pmi_x2_bitlen = csi_report->csi_meas_bitlen.pmi_x2_bitlen[*mac->csirs_measurements.rank_indicator]; - int cqi_bitlen = csi_report->csi_meas_bitlen.cqi_bitlen[*mac->csirs_measurements.rank_indicator]; + int pmi_x1_bitlen = csi_report->csi_meas_bitlen.pmi_x1_bitlen[mac->csirs_measurements.rank_indicator]; + int pmi_x2_bitlen = csi_report->csi_meas_bitlen.pmi_x2_bitlen[mac->csirs_measurements.rank_indicator]; + int cqi_bitlen = csi_report->csi_meas_bitlen.cqi_bitlen[mac->csirs_measurements.rank_indicator]; int padding_bitlen = n_bits - (cri_bitlen + ri_bitlen + pmi_x1_bitlen + pmi_x2_bitlen + cqi_bitlen); // TODO: Improvements will be needed to cri_bitlen>0 and pmi_x1_bitlen>0 - temp_payload = (*mac->csirs_measurements.rank_indicator<<(cri_bitlen+cqi_bitlen+pmi_x2_bitlen+padding_bitlen+pmi_x1_bitlen)) | - (*mac->csirs_measurements.i1<<(cri_bitlen+cqi_bitlen+pmi_x2_bitlen)) | - (*mac->csirs_measurements.i2<<(cri_bitlen+cqi_bitlen)) | - (*mac->csirs_measurements.cqi<csirs_measurements.rank_indicator<<(cri_bitlen+cqi_bitlen+pmi_x2_bitlen+padding_bitlen+pmi_x1_bitlen)) | + (mac->csirs_measurements.i1<<(cri_bitlen+cqi_bitlen+pmi_x2_bitlen)) | + (mac->csirs_measurements.i2<<(cri_bitlen+cqi_bitlen)) | + (mac->csirs_measurements.cqi< Date: Wed, 6 Jul 2022 21:08:08 +0100 Subject: [PATCH 190/267] To use cast for c16_t --- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 116 +++++++++++++------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 482f2ea2a5..cc1ead7dc9 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -205,24 +205,24 @@ int nr_get_csi_rs_signal(const PHY_VARS_NR_UE *ue, for (int lp = 0; lp <= nr_csi_rs_info->lprime; lp++) { uint16_t symb = lp + nr_csi_rs_info->loverline[cdm_id]; uint64_t symbol_offset = symb*frame_parms->ofdm_symbol_size; - int16_t *rx_signal = (int16_t*)&rxdataF[ant_rx][symbol_offset]; - int16_t *rx_csi_rs_signal = (int16_t*)&csi_rs_received_signal[ant_rx][symbol_offset]; - rx_csi_rs_signal[k<<1] = rx_signal[k<<1]; - rx_csi_rs_signal[(k<<1)+1] = rx_signal[(k<<1)+1]; + c16_t *rx_signal = (c16_t*)&rxdataF[ant_rx][symbol_offset]; + c16_t *rx_csi_rs_signal = (c16_t*)&csi_rs_received_signal[ant_rx][symbol_offset]; + rx_csi_rs_signal[k].r = rx_signal[k].r; + rx_csi_rs_signal[k].i = rx_signal[k].i; #ifdef NR_CSIRS_DEBUG int dataF_offset = proc->nr_slot_rx*ue->frame_parms.samples_per_slot_wCP; uint16_t port_tx = s+nr_csi_rs_info->j[cdm_id]*nr_csi_rs_info->CDM_group_size; - int16_t *tx_csi_rs_signal = (int16_t*)&nr_csi_rs_info->csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset]; + c16_t *tx_csi_rs_signal = (c16_t*)&nr_csi_rs_info->csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset]; LOG_I(NR_PHY, "l,k (%2d,%4d) |\tport_tx %d (%4d,%4d)\tant_rx %d (%4d,%4d)\n", symb, k, port_tx+3000, - tx_csi_rs_signal[k<<1], - tx_csi_rs_signal[(k<<1)+1], + tx_csi_rs_signal[k].r, + tx_csi_rs_signal[k].i, ant_rx, - rx_csi_rs_signal[k<<1], - rx_csi_rs_signal[(k<<1)+1]); + rx_csi_rs_signal[k].r, + rx_csi_rs_signal[k].i); #endif } } @@ -272,7 +272,7 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, /// LS channel estimation for(uint16_t port_tx = 0; port_txN_ports; port_tx++) { - memset(nr_csi_rs_info->csi_rs_ls_estimated_channel[ant_rx][port_tx], 0, frame_parms->ofdm_symbol_size*sizeof(int32_t)); + memset(csi_rs_ls_estimated_channel[ant_rx][port_tx], 0, frame_parms->ofdm_symbol_size*sizeof(int32_t)); } for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) { @@ -297,17 +297,17 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, for (int lp = 0; lp <= nr_csi_rs_info->lprime; lp++) { uint16_t symb = lp + nr_csi_rs_info->loverline[cdm_id]; uint64_t symbol_offset = symb*frame_parms->ofdm_symbol_size; - int16_t *tx_csi_rs_signal = (int16_t*)&csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset]; - int16_t *rx_csi_rs_signal = (int16_t*)&csi_rs_received_signal[ant_rx][symbol_offset]; - int16_t *csi_rs_ls_estimated_channel = (int16_t*)&nr_csi_rs_info->csi_rs_ls_estimated_channel[ant_rx][port_tx][0]; + c16_t *tx_csi_rs_signal = (c16_t*)&csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset]; + c16_t *rx_csi_rs_signal = (c16_t*)&csi_rs_received_signal[ant_rx][symbol_offset]; + c16_t *csi_rs_ls_estimated_channel16 = (c16_t*)&csi_rs_ls_estimated_channel[ant_rx][port_tx][0]; - int16_t csi_rs_ls_estimated_channel_re = (int16_t)(((int32_t)tx_csi_rs_signal[k<<1]*rx_csi_rs_signal[k<<1] + (int32_t)tx_csi_rs_signal[(k<<1)+1]*rx_csi_rs_signal[(k<<1)+1])>>nr_csi_rs_info->csi_rs_generated_signal_bits); - int16_t csi_rs_ls_estimated_channel_im = (int16_t)(((int32_t)tx_csi_rs_signal[k<<1]*rx_csi_rs_signal[(k<<1)+1] - (int32_t)tx_csi_rs_signal[(k<<1)+1]*rx_csi_rs_signal[k<<1])>>nr_csi_rs_info->csi_rs_generated_signal_bits); + int16_t csi_rs_ls_estimated_channel_re = (int16_t)(((int32_t)tx_csi_rs_signal[k].r*rx_csi_rs_signal[k].r + (int32_t)tx_csi_rs_signal[k].i*rx_csi_rs_signal[k].i)>>nr_csi_rs_info->csi_rs_generated_signal_bits); + int16_t csi_rs_ls_estimated_channel_im = (int16_t)(((int32_t)tx_csi_rs_signal[k].r*rx_csi_rs_signal[k].i - (int32_t)tx_csi_rs_signal[k].i*rx_csi_rs_signal[k].r)>>nr_csi_rs_info->csi_rs_generated_signal_bits); // This is not just the LS estimation for each (k,l), but also the sum of the different contributions // for the sake of optimizing the memory used. - csi_rs_ls_estimated_channel[kinit<<1] += csi_rs_ls_estimated_channel_re; - csi_rs_ls_estimated_channel[(kinit<<1)+1] += csi_rs_ls_estimated_channel_im; + csi_rs_ls_estimated_channel16[kinit].r += csi_rs_ls_estimated_channel_re; + csi_rs_ls_estimated_channel16[kinit].i += csi_rs_ls_estimated_channel_im; } } } @@ -323,14 +323,14 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, LOG_I(NR_PHY, "l,k (%2d,%4d) | ", symb, k); for(uint16_t port_tx = 0; port_txN_ports; port_tx++) { uint64_t symbol_offset = symb*frame_parms->ofdm_symbol_size; - int16_t *tx_csi_rs_signal = (int16_t*)&csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset]; - int16_t *rx_csi_rs_signal = (int16_t*)&csi_rs_received_signal[ant_rx][symbol_offset]; - int16_t *csi_rs_ls_estimated_channel = (int16_t*)&nr_csi_rs_info->csi_rs_ls_estimated_channel[ant_rx][port_tx][0]; + c16_t *tx_csi_rs_signal = (c16_t*)&csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset]; + c16_t *rx_csi_rs_signal = (c16_t*)&csi_rs_received_signal[ant_rx][symbol_offset]; + c16_t *csi_rs_ls_estimated_channel16 = (c16_t*)&csi_rs_ls_estimated_channel[ant_rx][port_tx][0]; printf("port_tx %d --> ant_rx %d, tx (%4d,%4d), rx (%4d,%4d), ls (%4d,%4d) | ", port_tx+3000, ant_rx, - tx_csi_rs_signal[k<<1], tx_csi_rs_signal[(k<<1)+1], - rx_csi_rs_signal[k<<1], rx_csi_rs_signal[(k<<1)+1], - csi_rs_ls_estimated_channel[k<<1], csi_rs_ls_estimated_channel[(k<<1)+1]); + tx_csi_rs_signal[k].r, tx_csi_rs_signal[k].i, + rx_csi_rs_signal[k].r, rx_csi_rs_signal[k].i, + csi_rs_ls_estimated_channel16[k].r, csi_rs_ls_estimated_channel16[k].i); } printf("\n"); } @@ -354,15 +354,15 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, uint16_t k = (frame_parms->first_carrier_offset + rb*NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size; for(uint16_t port_tx = 0; port_txN_ports; port_tx++) { - int16_t *csi_rs_ls_estimated_channel = (int16_t*)&nr_csi_rs_info->csi_rs_ls_estimated_channel[ant_rx][port_tx][k]; + int16_t *csi_rs_ls_estimated_channel16 = (int16_t*)&csi_rs_ls_estimated_channel[ant_rx][port_tx][k]; int16_t *csi_rs_estimated_channel16 = (int16_t *)&csi_rs_estimated_channel_freq[ant_rx][port_tx][k]; if( (k == 0) || (k == frame_parms->first_carrier_offset) ) { // Start of OFDM symbol case or first occupied subcarrier case - multadd_real_vector_complex_scalar(filt24_start, csi_rs_ls_estimated_channel, csi_rs_estimated_channel16, 24); + multadd_real_vector_complex_scalar(filt24_start, csi_rs_ls_estimated_channel16, csi_rs_estimated_channel16, 24); } else if( ( (k + NR_NB_SC_PER_RB) >= frame_parms->ofdm_symbol_size) || (rb == (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs-1)) ) { // End of OFDM symbol case or Last occupied subcarrier case - multadd_real_vector_complex_scalar(filt24_end, csi_rs_ls_estimated_channel, csi_rs_estimated_channel16 - 3*sizeof(uint64_t), 24); + multadd_real_vector_complex_scalar(filt24_end, csi_rs_ls_estimated_channel16, csi_rs_estimated_channel16 - 3*sizeof(uint64_t), 24); } else { // Middle case - multadd_real_vector_complex_scalar(filt24_middle, csi_rs_ls_estimated_channel, csi_rs_estimated_channel16 - 3*sizeof(uint64_t), 24); + multadd_real_vector_complex_scalar(filt24_middle, csi_rs_ls_estimated_channel16, csi_rs_estimated_channel16 - 3*sizeof(uint64_t), 24); } } } @@ -376,11 +376,11 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, } uint16_t k = (frame_parms->first_carrier_offset + rb*NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size; for(uint16_t port_tx = 0; port_txN_ports; port_tx++) { - int16_t *csi_rs_ls_estimated_channel = (int16_t*)&nr_csi_rs_info->csi_rs_ls_estimated_channel[ant_rx][port_tx][k]; - int16_t *csi_rs_estimated_channel16 = (int16_t *)&csi_rs_estimated_channel_freq[ant_rx][port_tx][k]; - noise_real[ant_rx][port_tx][rb-csirs_config_pdu->start_rb] = abs(csi_rs_ls_estimated_channel[0]-csi_rs_estimated_channel16[0]); - noise_imag[ant_rx][port_tx][rb-csirs_config_pdu->start_rb] = abs(csi_rs_ls_estimated_channel[1]-csi_rs_estimated_channel16[1]); - maxh = cmax3(maxh, abs(csi_rs_estimated_channel16[0]), abs(csi_rs_estimated_channel16[1])); + c16_t *csi_rs_ls_estimated_channel16 = (c16_t*)&csi_rs_ls_estimated_channel[ant_rx][port_tx][k]; + c16_t *csi_rs_estimated_channel16 = (c16_t *)&csi_rs_estimated_channel_freq[ant_rx][port_tx][k]; + noise_real[ant_rx][port_tx][rb-csirs_config_pdu->start_rb] = abs(csi_rs_ls_estimated_channel16->r-csi_rs_estimated_channel16->r); + noise_imag[ant_rx][port_tx][rb-csirs_config_pdu->start_rb] = abs(csi_rs_ls_estimated_channel16->i-csi_rs_estimated_channel16->i); + maxh = cmax3(maxh, abs(csi_rs_estimated_channel16->r), abs(csi_rs_estimated_channel16->i)); } } for(uint16_t port_tx = 0; port_txN_ports; port_tx++) { @@ -394,12 +394,12 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, (k + frame_parms->ofdm_symbol_size - frame_parms->first_carrier_offset)/NR_NB_SC_PER_RB; LOG_I(NR_PHY, "(k = %4d) |\t", k); for(uint16_t port_tx = 0; port_txN_ports; port_tx++) { - int16_t *csi_rs_ls_estimated_channel = (int16_t*)&nr_csi_rs_info->csi_rs_ls_estimated_channel[ant_rx][port_tx][0]; - int16_t *csi_rs_estimated_channel16 = (int16_t *)&csi_rs_estimated_channel_freq[ant_rx][port_tx][0]; + c16_t *csi_rs_ls_estimated_channel16 = (c16_t*)&csi_rs_ls_estimated_channel[ant_rx][port_tx][0]; + c16_t *csi_rs_estimated_channel16 = (c16_t *)&csi_rs_estimated_channel_freq[ant_rx][port_tx][0]; printf("Channel port_tx %d --> ant_rx %d : ls (%4d,%4d), int (%4d,%4d), noise (%4d,%4d) | ", port_tx+3000, ant_rx, - csi_rs_ls_estimated_channel[k<<1], csi_rs_ls_estimated_channel[(k<<1)+1], - csi_rs_estimated_channel16[k<<1], csi_rs_estimated_channel16[(k<<1)+1], + csi_rs_ls_estimated_channel16[k].r, csi_rs_ls_estimated_channel16[k].i, + csi_rs_estimated_channel16[k].r, csi_rs_estimated_channel16[k].i, rb >= csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs ? 0 : noise_real[ant_rx][port_tx][rb-csirs_config_pdu->start_rb], rb >= csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs ? 0 : noise_imag[ant_rx][port_tx][rb-csirs_config_pdu->start_rb]); } @@ -506,12 +506,12 @@ int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue, #ifdef NR_CSIRS_DEBUG for(uint16_t port_tx_conjch = 0; port_tx_conjch < nr_csi_rs_info->N_ports; port_tx_conjch++) { for(uint16_t port_tx_ch = 0; port_tx_ch < nr_csi_rs_info->N_ports; port_tx_ch++) { - int16_t *csi_rs_estimated_A_MF_k = (int16_t *) &csi_rs_estimated_A_MF[port_tx_conjch][port_tx_ch][k]; + c16_t *csi_rs_estimated_A_MF_k = (c16_t *) &csi_rs_estimated_A_MF[port_tx_conjch][port_tx_ch][k]; LOG_I(NR_PHY, "(%i) csi_rs_estimated_A_MF[%i][%i] = (%i, %i)\n", - k, port_tx_conjch, port_tx_ch, csi_rs_estimated_A_MF_k[0], csi_rs_estimated_A_MF_k[1]); - int16_t *csi_rs_estimated_A_MF_sq_k = (int16_t *) &csi_rs_estimated_A_MF_sq[port_tx_conjch][port_tx_ch][k]; + k, port_tx_conjch, port_tx_ch, csi_rs_estimated_A_MF_k->r, csi_rs_estimated_A_MF_k->i); + c16_t *csi_rs_estimated_A_MF_sq_k = (c16_t *) &csi_rs_estimated_A_MF_sq[port_tx_conjch][port_tx_ch][k]; LOG_I(NR_PHY, "(%i) csi_rs_estimated_A_MF_sq[%i][%i] = (%i, %i)\n", - k, port_tx_conjch, port_tx_ch, csi_rs_estimated_A_MF_sq_k[0], csi_rs_estimated_A_MF_sq_k[1]); + k, port_tx_conjch, port_tx_ch, csi_rs_estimated_A_MF_sq_k->r, csi_rs_estimated_A_MF_sq_k->i); } } LOG_I(NR_PHY, "(%i) csi_rs_estimated_determ_fin = %i\n", k, csi_rs_estimated_determ_fin[k]); @@ -596,32 +596,32 @@ int nr_csi_rs_pmi_estimation(const PHY_VARS_NR_UE *ue, for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) { - int16_t *csi_rs_estimated_channel_p0 = (int16_t *) &csi_rs_estimated_channel_freq[ant_rx][0][k]; - int16_t *csi_rs_estimated_channel_p1 = (int16_t *) &csi_rs_estimated_channel_freq[ant_rx][1][k]; + c16_t *csi_rs_estimated_channel_p0 = (c16_t *) &csi_rs_estimated_channel_freq[ant_rx][0][k]; + c16_t *csi_rs_estimated_channel_p1 = (c16_t *) &csi_rs_estimated_channel_freq[ant_rx][1][k]; // H_p0 + 1*H_p1 = (H_p0_re + H_p1_re) + 1j*(H_p0_im + H_p1_im) - sum_re[0] += (csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[0]); - sum_im[0] += (csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[1]); - sum2_re[0] += ((csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[0]))>>log2_re; - sum2_im[0] += ((csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[1]))>>log2_re; + sum_re[0] += (csi_rs_estimated_channel_p0->r+csi_rs_estimated_channel_p1->r); + sum_im[0] += (csi_rs_estimated_channel_p0->i+csi_rs_estimated_channel_p1->i); + sum2_re[0] += ((csi_rs_estimated_channel_p0->r+csi_rs_estimated_channel_p1->r)*(csi_rs_estimated_channel_p0->r+csi_rs_estimated_channel_p1->r))>>log2_re; + sum2_im[0] += ((csi_rs_estimated_channel_p0->i+csi_rs_estimated_channel_p1->i)*(csi_rs_estimated_channel_p0->i+csi_rs_estimated_channel_p1->i))>>log2_re; // H_p0 + 1j*H_p1 = (H_p0_re - H_p1_im) + 1j*(H_p0_im + H_p1_re) - sum_re[1] += (csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[1]); - sum_im[1] += (csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[0]); - sum2_re[1] += ((csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[1]))>>log2_re; - sum2_im[1] += ((csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[1]+csi_rs_estimated_channel_p1[0]))>>log2_re; + sum_re[1] += (csi_rs_estimated_channel_p0->r-csi_rs_estimated_channel_p1->i); + sum_im[1] += (csi_rs_estimated_channel_p0->i+csi_rs_estimated_channel_p1->r); + sum2_re[1] += ((csi_rs_estimated_channel_p0->r-csi_rs_estimated_channel_p1->i)*(csi_rs_estimated_channel_p0->r-csi_rs_estimated_channel_p1->i))>>log2_re; + sum2_im[1] += ((csi_rs_estimated_channel_p0->i+csi_rs_estimated_channel_p1->r)*(csi_rs_estimated_channel_p0->i+csi_rs_estimated_channel_p1->r))>>log2_re; // H_p0 - 1*H_p1 = (H_p0_re - H_p1_re) + 1j*(H_p0_im - H_p1_im) - sum_re[2] += (csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[0]); - sum_im[2] += (csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[1]); - sum2_re[2] += ((csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[0]-csi_rs_estimated_channel_p1[0]))>>log2_re; - sum2_im[2] += ((csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[1]))>>log2_re; + sum_re[2] += (csi_rs_estimated_channel_p0->r-csi_rs_estimated_channel_p1->r); + sum_im[2] += (csi_rs_estimated_channel_p0->i-csi_rs_estimated_channel_p1->i); + sum2_re[2] += ((csi_rs_estimated_channel_p0->r-csi_rs_estimated_channel_p1->r)*(csi_rs_estimated_channel_p0->r-csi_rs_estimated_channel_p1->r))>>log2_re; + sum2_im[2] += ((csi_rs_estimated_channel_p0->i-csi_rs_estimated_channel_p1->i)*(csi_rs_estimated_channel_p0->i-csi_rs_estimated_channel_p1->i))>>log2_re; // H_p0 - 1j*H_p1 = (H_p0_re + H_p1_im) + 1j*(H_p0_im - H_p1_re) - sum_re[3] += (csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[1]); - sum_im[3] += (csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[0]); - sum2_re[3] += ((csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[1])*(csi_rs_estimated_channel_p0[0]+csi_rs_estimated_channel_p1[1]))>>log2_re; - sum2_im[3] += ((csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[0])*(csi_rs_estimated_channel_p0[1]-csi_rs_estimated_channel_p1[0]))>>log2_re; + sum_re[3] += (csi_rs_estimated_channel_p0->r+csi_rs_estimated_channel_p1->i); + sum_im[3] += (csi_rs_estimated_channel_p0->i-csi_rs_estimated_channel_p1->r); + sum2_re[3] += ((csi_rs_estimated_channel_p0->r+csi_rs_estimated_channel_p1->i)*(csi_rs_estimated_channel_p0->r+csi_rs_estimated_channel_p1->i))>>log2_re; + sum2_im[3] += ((csi_rs_estimated_channel_p0->i-csi_rs_estimated_channel_p1->r)*(csi_rs_estimated_channel_p0->i-csi_rs_estimated_channel_p1->r))>>log2_re; } } From 79586c03f401d9d874678856e16f9dfb640eacfc Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 5 Jul 2022 14:16:06 +0200 Subject: [PATCH 191/267] fix for pointa and ssboffset --- openair1/PHY/NR_TRANSPORT/nr_pbch.c | 6 +- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 7 +- openair1/SIMULATION/NR_PHY/pbchsim.c | 6 +- openair2/LAYER2/NR_MAC_gNB/config.c | 24 +++---- .../LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 68 ++++--------------- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 2 +- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 1 + openair2/RRC/NR/MESSAGES/asn1_msg.c | 14 ++-- 8 files changed, 44 insertions(+), 84 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_pbch.c b/openair1/PHY/NR_TRANSPORT/nr_pbch.c index fc7df46496..278c2dfd58 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_pbch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_pbch.c @@ -35,6 +35,7 @@ #include "PHY/NR_TRANSPORT/nr_transport_proto.h" #include "PHY/LTE_REFSIG/lte_refsig.h" #include "PHY/sse_intrin.h" +#include "executables/softmodem-common.h" //#define DEBUG_PBCH //#define DEBUG_PBCH_ENCODING @@ -248,6 +249,9 @@ int nr_generate_pbch(nfapi_nr_dl_tti_ssb_pdu *ssb_pdu, for (int i=0; ipbch_a |= ((pbch_pdu[i>>3]>>(7-(i&7)))&1)<sa ? config->ssb_table.ssb_subcarrier_offset.value : 31; + #ifdef DEBUG_PBCH_ENCODING for (int i=0; i<3; i++) printf("pbch_pdu[%d]: 0x%02x\n", i, pbch_pdu[i]); @@ -265,7 +269,7 @@ int nr_generate_pbch(nfapi_nr_dl_tti_ssb_pdu *ssb_pdu, for (int i=0; i<3; i++) pbch->pbch_a |= ((ssb_index>>(5-i))&1)<<(29+i); // resp. 6th, 5th and 4th bits of ssb_index else - pbch->pbch_a |= ((config->ssb_table.ssb_subcarrier_offset.value>>4)&1)<<29; //MSB of k_SSB (bit index 4) + pbch->pbch_a |= ((ssb_sc_offset>>4)&1)<<29; //MSB of k_SSB (bit index 4) LOG_D(PHY,"After extra byte: pbch_a = 0x%08x\n",pbch->pbch_a); diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 1428987d40..4d511a2e95 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -72,8 +72,11 @@ void nr_common_signal_procedures (PHY_VARS_gNB *gNB,int frame,int slot,nfapi_nr_ ssb_start_symbol = ssb_start_symbol_abs % fp->symbols_per_slot; // start symbol wrt slot // setting the first subcarrier - fp->ssb_start_subcarrier = (12 * cfg->ssb_table.ssb_offset_point_a.value + ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset); - LOG_D(PHY, "SSB first subcarrier %d (%d,%d)\n", fp->ssb_start_subcarrier,cfg->ssb_table.ssb_offset_point_a.value,ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset); + const int scs = cfg->ssb_config.scs_common.value; + const int prb_offset = (fp->freq_range == nr_FR1) ? ssb_pdu.ssb_pdu_rel15.ssbOffsetPointA>>scs : ssb_pdu.ssb_pdu_rel15.ssbOffsetPointA>>(scs-2); + const int sc_offset = (fp->freq_range == nr_FR1) ? ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset>>scs : ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset; + fp->ssb_start_subcarrier = (12 * prb_offset + sc_offset); + LOG_D(PHY, "SSB first subcarrier %d (%d,%d)\n", fp->ssb_start_subcarrier, prb_offset, sc_offset); LOG_D(PHY,"SS TX: frame %d, slot %d, start_symbol %d\n",frame,slot, ssb_start_symbol); nr_generate_pss(&txdataF[0][txdataF_offset], AMP, ssb_start_symbol, cfg, fp); diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index 07c5f118dc..b43cb6b00d 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -67,7 +67,10 @@ openair0_config_t openair0_cfg[MAX_CARDS]; uint8_t const nr_rv_round_map[4] = {0, 2, 3, 1}; uint64_t get_softmodem_optmask(void) {return 0;} -softmodem_params_t *get_softmodem_params(void) {return 0;} +static softmodem_params_t softmodem_params; +softmodem_params_t *get_softmodem_params(void) { + return &softmodem_params; +} void init_downlink_harq_status(NR_DL_UE_HARQ_t *dl_harq) {} @@ -174,6 +177,7 @@ int main(int argc, char **argv) int ssb_subcarrier_offset = 0; channel_desc_t *gNB2UE; + get_softmodem_params()->sa = 0; //uint8_t extended_prefix_flag=0; //int8_t interf1=-21,interf2=-21; diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 218b75b2e8..4daddbf03a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -335,22 +335,13 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, int pusch_AntennaPorts, cfg->num_tlv++; // SSB Table Configuration - int scs_scaling = 1<<(cfg->ssb_config.scs_common.value); - if (scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA < 600000) - scs_scaling = scs_scaling*3; - if (scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA > 2016666) - scs_scaling = scs_scaling>>2; uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); - - RC.nrmac[Mod_idP]->ssb_SubcarrierOffset = absolute_diff%(12*scs_scaling); - int sco = 31; // no SIB1 - if(get_softmodem_params()->sa) { - sco = RC.nrmac[Mod_idP]->ssb_SubcarrierOffset; - if(frequency_range == FR1) - sco <<= cfg->ssb_config.scs_common.value; // 38.211 section 7.4.3.1 in FR1 it is expresses in terms of 15kHz SCS - } - - cfg->ssb_table.ssb_offset_point_a.value = absolute_diff/(12*scs_scaling) - 10; //absoluteFrequencySSB is the central frequency of SSB which is made by 20RBs in total + const int scaling_5khz = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA < 600000 ? 3 : 1; + int sco = (absolute_diff*scaling_5khz) % 24; + if(frequency_range == FR2) + sco >>= 1; // this assumes 120kHz SCS for SSB and subCarrierSpacingCommon (only option supported by OAI for + const int scs_scaling = frequency_range == FR2 ? 1 << (*scc->ssbSubcarrierSpacing - 2) : 1 << *scc->ssbSubcarrierSpacing; + cfg->ssb_table.ssb_offset_point_a.value = absolute_diff/(12*scaling_5khz) - 10*scs_scaling; //absoluteFrequencySSB is the central frequency of SSB which is made by 20RBs in total cfg->ssb_table.ssb_offset_point_a.tl.tag = NFAPI_NR_CONFIG_SSB_OFFSET_POINT_A_TAG; cfg->num_tlv++; cfg->ssb_table.ssb_period.value = *scc->ssb_periodicityServingCell; @@ -360,6 +351,9 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, int pusch_AntennaPorts, cfg->ssb_table.ssb_subcarrier_offset.tl.tag = NFAPI_NR_CONFIG_SSB_SUBCARRIER_OFFSET_TAG; cfg->num_tlv++; + RC.nrmac[Mod_idP]->ssb_SubcarrierOffset = cfg->ssb_table.ssb_subcarrier_offset.value; + RC.nrmac[Mod_idP]->ssb_OffsetPointA = cfg->ssb_table.ssb_offset_point_a.value; + switch (scc->ssb_PositionsInBurst->present) { case 1 : cfg->ssb_table.ssb_mask_list[0].ssb_mask.value = scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0]<<24; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index e2ceadb889..828cb2b880 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -54,52 +54,6 @@ extern RAN_CONTEXT_t RC; - -uint16_t get_ssboffset_pointa(NR_ServingCellConfigCommon_t *scc,const long band) { - - int ratio; - switch (*scc->ssbSubcarrierSpacing) { - case NR_SubcarrierSpacing_kHz15: - AssertFatal(band <= 95, - "Band %ld is not possible for SSB with 15 kHz SCS\n", - band); - // no band available above 3GHz using 15kHz - ratio = 3; // NRARFCN step is 5 kHz - break; - case NR_SubcarrierSpacing_kHz30: - AssertFatal(band <= 96, - "Band %ld is not possible for SSB with 30 kHz SCS\n", - band); - if (band == 46 || band == 48 || band == 77 || - band == 78 || band == 79 || band == 96) // above 3GHz - ratio = 2; // NRARFCN step is 15 kHz - else - ratio = 6; // NRARFCN step is 5 kHz - break; - case NR_SubcarrierSpacing_kHz120: - AssertFatal(band >= 257, - "Band %ld is not possible for SSB with 120 kHz SCS\n", - band); - ratio = 2; // NRARFCN step is 15 kHz - break; - case NR_SubcarrierSpacing_kHz240: - AssertFatal(band >= 257, - "Band %ld is not possible for SSB with 240 kHz SCS\n", - band); - ratio = 4; // NRARFCN step is 15 kHz - break; - default: - AssertFatal(1 == 0, "SCS %ld not allowed for SSB \n", - *scc->ssbSubcarrierSpacing); - } - - const uint32_t ssb_offset0 = *scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA; - - return (ssb_offset0/(ratio*12) - 10); // absoluteFrequencySSB is the center of SSB - -} - - void schedule_ssb(frame_t frame, sub_frame_t slot, NR_ServingCellConfigCommon_t *scc, nfapi_nr_dl_tti_request_body_t *dl_req, @@ -190,7 +144,7 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) NR_SubcarrierSpacing_t scs = *scc->ssbSubcarrierSpacing; const long band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; - uint16_t offset_pointa = get_ssboffset_pointa(scc,band); + const uint16_t offset_pointa = gNB->ssb_OffsetPointA; uint8_t ssbSubcarrierOffset = gNB->ssb_SubcarrierOffset; const BIT_STRING_t *shortBitmap = &scc->ssb_PositionsInBurst->choice.shortBitmap; @@ -207,8 +161,9 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) ssb_start_symbol = get_ssb_start_symbol(band,scs,i_ssb); // if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters if ((ssb_start_symbol/14) == rel_slot){ + const int prb_offset = offset_pointa >> scs; schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, ssbSubcarrierOffset, offset_pointa, (*(uint32_t*)cc->MIB_pdu.payload) & ((1<<24)-1)); - fill_ssb_vrb_map(cc, offset_pointa, ssb_start_symbol, CC_id); + fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset, ssb_start_symbol, CC_id); if (get_softmodem_params()->sa == 1) { get_type0_PDCCH_CSS_config_parameters(&gNB->type0_PDCCH_CSS_config[i_ssb], frameP, @@ -221,7 +176,7 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) band, i_ssb, ssb_frame_periodicity, - offset_pointa); + prb_offset); gNB->type0_PDCCH_CSS_config[i_ssb].active = true; } } @@ -235,8 +190,9 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) ssb_start_symbol = get_ssb_start_symbol(band,scs,i_ssb); // if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters if ((ssb_start_symbol/14) == rel_slot){ + const int prb_offset = offset_pointa >> scs; schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, ssbSubcarrierOffset, offset_pointa, (*(uint32_t*)cc->MIB_pdu.payload) & ((1<<24)-1)); - fill_ssb_vrb_map(cc, offset_pointa, ssb_start_symbol, CC_id); + fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset, ssb_start_symbol, CC_id); if (get_softmodem_params()->sa == 1) { get_type0_PDCCH_CSS_config_parameters(&gNB->type0_PDCCH_CSS_config[i_ssb], frameP, @@ -249,7 +205,7 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) band, i_ssb, ssb_frame_periodicity, - offset_pointa); + prb_offset); gNB->type0_PDCCH_CSS_config[i_ssb].active = true; } } @@ -264,8 +220,9 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) ssb_start_symbol = get_ssb_start_symbol(band,scs,i_ssb); // if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters if ((ssb_start_symbol/14) == rel_slot){ + const int prb_offset = offset_pointa >> (scs-2); // reference 60kHz schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, ssbSubcarrierOffset, offset_pointa, (*(uint32_t*)cc->MIB_pdu.payload) & ((1<<24)-1)); - fill_ssb_vrb_map(cc, offset_pointa, ssb_start_symbol, CC_id); + fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset, ssb_start_symbol, CC_id); const NR_TDD_UL_DL_Pattern_t *tdd = &scc->tdd_UL_DL_ConfigurationCommon->pattern1; const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; // FR2 is only TDD, to be fixed for flexible TDD @@ -286,7 +243,7 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) band, i_ssb, ssb_frame_periodicity, - offset_pointa); + prb_offset); gNB->type0_PDCCH_CSS_config[i_ssb].active = true; } } @@ -306,7 +263,7 @@ void schedule_nr_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframe //---------------------------------------- } -void fill_ssb_vrb_map (NR_COMMON_channels_t *cc, int rbStart, uint16_t symStart, int CC_id) { +void fill_ssb_vrb_map (NR_COMMON_channels_t *cc, int rbStart, int ssb_subcarrier_offset, uint16_t symStart, int CC_id) { AssertFatal(*cc->ServingCellConfigCommon->ssbSubcarrierSpacing != NR_SubcarrierSpacing_kHz240, @@ -314,7 +271,8 @@ void fill_ssb_vrb_map (NR_COMMON_channels_t *cc, int rbStart, uint16_t symStart uint16_t *vrb_map = cc[CC_id].vrb_map; - for (int rb = 0; rb < 20; rb++) + const int extra_prb = ssb_subcarrier_offset > 0; + for (int rb = 0; rb < 20+extra_prb; rb++) vrb_map[rbStart + rb] = SL_to_bitmap(symStart, 4); } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 3fd394abdb..364f0255d2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -434,7 +434,7 @@ int binomial(int n, int k); bool is_xlsch_in_slot(uint64_t bitmap, sub_frame_t slot); -void fill_ssb_vrb_map (NR_COMMON_channels_t *cc, int rbStart, uint16_t symStart, int CC_id); +void fill_ssb_vrb_map (NR_COMMON_channels_t *cc, int rbStart, int ssb_subcarrier_offset, uint16_t symStart, int CC_id); /* \brief Function to indicate a received SDU on ULSCH. diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 40d16f8e8d..49c1f5caf2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -765,6 +765,7 @@ typedef struct gNB_MAC_INST_s { int pusch_failure_thres; /// Subcarrier Offset int ssb_SubcarrierOffset; + int ssb_OffsetPointA; /// SIB1 Time domain allocation int sib1_tda; int minRXTXTIMEpdsch; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index ea4e038ca0..d08f816cdb 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -226,17 +226,13 @@ uint8_t do_MIB_NR(gNB_RRC_INST *rrc,uint32_t frame) { AssertFatal(scc->ssbSubcarrierSpacing != NULL, "scc->ssbSubcarrierSpacing is null\n"); int band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; frequency_range_t frequency_range = band<100?FR1:FR2; - int scs_scaling = 1<<*scc->ssbSubcarrierSpacing; - if (scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA < 600000) - scs_scaling = scs_scaling*3; - if (scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA > 2016666) - scs_scaling = scs_scaling>>2; - uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); int ssb_subcarrier_offset = 31; // default value for NSA if (get_softmodem_params()->sa) { - ssb_subcarrier_offset = absolute_diff%(12*scs_scaling); - if(frequency_range == FR1) - ssb_subcarrier_offset <<= *scc->ssbSubcarrierSpacing; + uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); + int scs_scaling = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA < 600000 ? 3 : 1; + ssb_subcarrier_offset = (absolute_diff*scs_scaling)%24; + if(frequency_range == FR2) + ssb_subcarrier_offset >>= 1; // this assumes 120kHz SCS for SSB and subCarrierSpacingCommon (only option supported by OAI for now) } mib->message.choice.mib->ssb_SubcarrierOffset = ssb_subcarrier_offset&15; From edcb1b2bf578ed980935d5774c4ef80d4ff8cd10 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 5 Jul 2022 18:30:02 +0200 Subject: [PATCH 192/267] workaround for pbchsim --- openair1/SIMULATION/NR_PHY/pbchsim.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index b43cb6b00d..0e648c945f 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -177,7 +177,7 @@ int main(int argc, char **argv) int ssb_subcarrier_offset = 0; channel_desc_t *gNB2UE; - get_softmodem_params()->sa = 0; + get_softmodem_params()->sa = 1; //uint8_t extended_prefix_flag=0; //int8_t interf1=-21,interf2=-21; @@ -464,6 +464,7 @@ int main(int argc, char **argv) frame_parms->Nid_cell = Nid_cell; frame_parms->nushift = Nid_cell%4; frame_parms->ssb_type = nr_ssb_type_C; + frame_parms->freq_range = mu<2 ? nr_FR1 : nr_FR2; nr_phy_config_request_sim_pbchsim(gNB,N_RB_DL,N_RB_DL,mu,Nid_cell,SSB_positions); phy_init_nr_gNB(gNB,0,1); @@ -588,9 +589,12 @@ int main(int argc, char **argv) for (i=0; iLmax; i++) { if((SSB_positions >> i) & 0x01) { + const int sc_offset = frame_parms->freq_range == nr_FR1 ? ssb_subcarrier_offset<freq_range == nr_FR1 ? gNB->gNB_config.ssb_table.ssb_offset_point_a.value<gNB_config.ssb_table.ssb_offset_point_a.value << (mu - 2); msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.bchPayload = 0x55dd33; msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.SsbBlockIndex = i; - msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset = ssb_subcarrier_offset; + msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset = sc_offset; + msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.ssbOffsetPointA = prb_offset; start_symbol = nr_get_ssb_start_symbol(frame_parms,i); int slot = start_symbol/14; From 43c980d36bf277e49e3f22ea545e309af7099239 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 7 Jul 2022 09:24:31 +0200 Subject: [PATCH 193/267] CI: NSA-B200-Container: no Qlog --- ci-scripts/xml_files/container_nsa_b200_quectel.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/ci-scripts/xml_files/container_nsa_b200_quectel.xml b/ci-scripts/xml_files/container_nsa_b200_quectel.xml index 8d04be3efd..51e6668cf0 100644 --- a/ci-scripts/xml_files/container_nsa_b200_quectel.xml +++ b/ci-scripts/xml_files/container_nsa_b200_quectel.xml @@ -53,7 +53,6 @@ Initialize_UE Initialize Quectel idefix - yes From acd4e39566de51fb1e3daa9d3f253ab31fa03d17 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 7 Jul 2022 11:48:37 +0100 Subject: [PATCH 194/267] Remove csi_rs_received_signal from nr_csi_rs_info_t --- openair1/PHY/INIT/nr_init_ue.c | 3 -- openair1/PHY/NR_REFSIG/nr_refsig.h | 2 +- openair1/PHY/NR_REFSIG/refsig_defs_ue.h | 2 +- openair1/PHY/NR_TRANSPORT/nr_csi_rs.c | 28 +++++++++---------- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 2 +- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 14 ++++++---- openair1/PHY/defs_nr_common.h | 1 - openair1/SCHED_NR/phy_procedures_nr_gNB.c | 2 +- 8 files changed, 26 insertions(+), 28 deletions(-) diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index cb174dc81f..09bc80c4ed 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -362,11 +362,9 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) for (i=0; inr_csi_rs_info->csi_rs_generated_signal[i] = (int32_t *) malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t)); } - ue->nr_csi_rs_info->csi_rs_received_signal = (int32_t **)malloc16(fp->nb_antennas_rx * sizeof(int32_t *) ); ue->nr_csi_rs_info->csi_rs_ls_estimated_channel = (int32_t ***)malloc16(fp->nb_antennas_rx * sizeof(int32_t **) ); ue->nr_csi_rs_info->csi_rs_estimated_channel_freq = (int32_t ***)malloc16(fp->nb_antennas_rx * sizeof(int32_t **) ); for (i=0; inb_antennas_rx; i++) { - ue->nr_csi_rs_info->csi_rs_received_signal[i] = (int32_t *) malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t)); ue->nr_csi_rs_info->csi_rs_ls_estimated_channel[i] = (int32_t **) malloc16_clear(NR_MAX_NB_PORTS * sizeof(int32_t *)); ue->nr_csi_rs_info->csi_rs_estimated_channel_freq[i] = (int32_t **) malloc16_clear(NR_MAX_NB_PORTS * sizeof(int32_t *)); for (j=0; jnr_csi_rs_info->csi_rs_generated_signal[i]); } for (int i = 0; i < fp->nb_antennas_rx; i++) { - free_and_zero(ue->nr_csi_rs_info->csi_rs_received_signal[i]); for (int j=0; jnr_csi_rs_info->csi_rs_ls_estimated_channel[i][j]); free_and_zero(ue->nr_csi_rs_info->csi_rs_estimated_channel_freq[i][j]); diff --git a/openair1/PHY/NR_REFSIG/nr_refsig.h b/openair1/PHY/NR_REFSIG/nr_refsig.h index d4d91d7060..110ff321bd 100644 --- a/openair1/PHY/NR_REFSIG/nr_refsig.h +++ b/openair1/PHY/NR_REFSIG/nr_refsig.h @@ -38,7 +38,7 @@ void nr_init_pbch_dmrs(PHY_VARS_gNB* gNB); */ void nr_init_pdcch_dmrs(PHY_VARS_gNB* gNB, uint32_t Nid); void nr_init_pdsch_dmrs(PHY_VARS_gNB* gNB, uint8_t nscid, uint32_t Nid); -void nr_init_csi_rs(NR_DL_FRAME_PARMS *fp, uint32_t ***csi_rs, uint32_t Nid); +void nr_init_csi_rs(const NR_DL_FRAME_PARMS *fp, uint32_t ***csi_rs, uint32_t Nid); void nr_gold_pusch(PHY_VARS_gNB* gNB, int nscid, uint32_t nid); diff --git a/openair1/PHY/NR_REFSIG/refsig_defs_ue.h b/openair1/PHY/NR_REFSIG/refsig_defs_ue.h index eb5c573368..a6e57fb298 100644 --- a/openair1/PHY/NR_REFSIG/refsig_defs_ue.h +++ b/openair1/PHY/NR_REFSIG/refsig_defs_ue.h @@ -68,6 +68,6 @@ void nr_init_pusch_dmrs(PHY_VARS_NR_UE* ue, uint16_t N_n_scid, uint8_t n_scid); -void nr_init_csi_rs(NR_DL_FRAME_PARMS *fp, uint32_t ***csi_rs, uint32_t Nid); +void nr_init_csi_rs(const NR_DL_FRAME_PARMS *fp, uint32_t ***csi_rs, uint32_t Nid); #endif diff --git a/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c b/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c index ab8d915d6e..86917473b7 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c +++ b/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c @@ -27,7 +27,7 @@ //#define NR_CSIRS_DEBUG -void nr_init_csi_rs(NR_DL_FRAME_PARMS *fp, uint32_t ***csi_rs, uint32_t Nid) { +void nr_init_csi_rs(const NR_DL_FRAME_PARMS *fp, uint32_t ***csi_rs, uint32_t Nid) { uint32_t x1, x2; uint8_t reset; int csi_dmrs_init_length = ((fp->N_RB_DL<<4)>>5)+1; @@ -43,7 +43,7 @@ void nr_init_csi_rs(NR_DL_FRAME_PARMS *fp, uint32_t ***csi_rs, uint32_t Nid) { } } -void nr_generate_csi_rs(NR_DL_FRAME_PARMS frame_parms, +void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms, int32_t **dataF, int16_t amp, nr_csi_rs_info_t *nr_csi_rs_info, @@ -67,11 +67,11 @@ void nr_generate_csi_rs(NR_DL_FRAME_PARMS frame_parms, LOG_I(NR_PHY, "csi_params->power_control_offset_ss = %i\n", csi_params->power_control_offset_ss); #endif - int dataF_offset = slot*frame_parms.samples_per_slot_wCP; + int dataF_offset = slot*frame_parms->samples_per_slot_wCP; uint32_t **nr_gold_csi_rs = nr_csi_rs_info->nr_gold_csi_rs[slot]; //*8(max allocation per RB)*2(QPSK)) - int csi_rs_length = frame_parms.N_RB_DL<<4; - int16_t mod_csi[frame_parms.symbols_per_slot][csi_rs_length>>1] __attribute__((aligned(16))); + int csi_rs_length = frame_parms->N_RB_DL<<4; + int16_t mod_csi[frame_parms->symbols_per_slot][csi_rs_length>>1] __attribute__((aligned(16))); uint16_t b = csi_params->freq_domain; uint16_t n, p, k, l, mprime, na, kpn; uint8_t size, ports, kprime, lprime, i, gs; @@ -88,7 +88,7 @@ void nr_generate_csi_rs(NR_DL_FRAME_PARMS frame_parms, // if the scrambling id is not the one previously used to initialize we need to re-initialize the rs if (csi_params->scramb_id != nr_csi_rs_info->csi_gold_init) { nr_csi_rs_info->csi_gold_init = csi_params->scramb_id; - nr_init_csi_rs(&frame_parms, nr_csi_rs_info->nr_gold_csi_rs, csi_params->scramb_id); + nr_init_csi_rs(frame_parms, nr_csi_rs_info->nr_gold_csi_rs, csi_params->scramb_id); } switch (csi_params->row) { @@ -584,7 +584,7 @@ void nr_generate_csi_rs(NR_DL_FRAME_PARMS frame_parms, } } - uint16_t start_sc = frame_parms.first_carrier_offset; + uint16_t start_sc = frame_parms->first_carrier_offset; // resource mapping according to 38.211 7.4.1.5.3 for (n=csi_params->start_rb; n<(csi_params->start_rb+csi_params->nr_of_rbs); n++) { @@ -593,7 +593,7 @@ void nr_generate_csi_rs(NR_DL_FRAME_PARMS frame_parms, for (int s=0 ; sofdm_symbol_size); // frequency index of current resource element // wf according to tables 7.4.5.3-2 to 7.4.5.3-5 if (kp == 0) wf = 1; @@ -620,17 +620,17 @@ void nr_generate_csi_rs(NR_DL_FRAME_PARMS frame_parms, // ZP CSI RS if (csi_params->csi_type == 2) { - ((int16_t*)dataF[p])[((l*frame_parms.ofdm_symbol_size + k)<<1)+(2*dataF_offset)] = 0; - ((int16_t*)dataF[p])[((l*frame_parms.ofdm_symbol_size + k)<<1)+1+(2*dataF_offset)] = 0; + ((int16_t*)dataF[p])[((l*frame_parms->ofdm_symbol_size + k)<<1)+(2*dataF_offset)] = 0; + ((int16_t*)dataF[p])[((l*frame_parms->ofdm_symbol_size + k)<<1)+1+(2*dataF_offset)] = 0; } else { - ((int16_t*)dataF[p])[((l*frame_parms.ofdm_symbol_size + k)<<1)+(2*dataF_offset)] = (beta*wt*wf*mod_csi[l][mprime<<1]) >> 15; - ((int16_t*)dataF[p])[((l*frame_parms.ofdm_symbol_size + k)<<1)+1+(2*dataF_offset)] = (beta*wt*wf*mod_csi[l][(mprime<<1) + 1]) >> 15; + ((int16_t*)dataF[p])[((l*frame_parms->ofdm_symbol_size + k)<<1)+(2*dataF_offset)] = (beta*wt*wf*mod_csi[l][mprime<<1]) >> 15; + ((int16_t*)dataF[p])[((l*frame_parms->ofdm_symbol_size + k)<<1)+1+(2*dataF_offset)] = (beta*wt*wf*mod_csi[l][(mprime<<1) + 1]) >> 15; } #ifdef NR_CSIRS_DEBUG printf("l,k (%d,%d) seq. index %d \t port %d \t (%d,%d)\n",l,k,mprime,p+3000, - ((int16_t*)dataF[p])[((l*frame_parms.ofdm_symbol_size + k)<<1)+(2*dataF_offset)], - ((int16_t*)dataF[p])[((l*frame_parms.ofdm_symbol_size + k)<<1)+1+(2*dataF_offset)]); + ((int16_t*)dataF[p])[((l*frame_parms->ofdm_symbol_size + k)<<1)+(2*dataF_offset)], + ((int16_t*)dataF[p])[((l*frame_parms->ofdm_symbol_size + k)<<1)+1+(2*dataF_offset)]); #endif } } diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index e3b7efacfb..ce201b3302 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -337,7 +337,7 @@ void init_prach_ru_list(RU_t *ru); void free_nr_ru_prach_entry(RU_t *ru, int prach_id); uint8_t get_nr_prach_duration(uint8_t prach_format); -void nr_generate_csi_rs(NR_DL_FRAME_PARMS frame_parms, +void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms, int32_t **dataF, int16_t amp, nr_csi_rs_info_t *nr_csi_rs_info, diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index cc1ead7dc9..29958d7e77 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -178,13 +178,12 @@ int nr_get_csi_rs_signal(const PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, const nr_csi_rs_info_t *nr_csi_rs_info, - int32_t **csi_rs_received_signal) { + int32_t csi_rs_received_signal[][ue->frame_parms.samples_per_slot_wCP]) { int32_t **rxdataF = ue->common_vars.common_vars_rx_data_per_thread[proc->thread_id].rxdataF; const NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) { - memset(csi_rs_received_signal[ant_rx], 0, frame_parms->samples_per_frame_wCP*sizeof(int32_t)); for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) { @@ -254,7 +253,7 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, const nr_csi_rs_info_t *nr_csi_rs_info, const int32_t **csi_rs_generated_signal, - const int32_t **csi_rs_received_signal, + const int32_t csi_rs_received_signal[][ue->frame_parms.samples_per_slot_wCP], int32_t ***csi_rs_ls_estimated_channel, int32_t ***csi_rs_estimated_channel_freq, int16_t *log2_re, @@ -811,6 +810,9 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t LOG_I(NR_PHY, "csirs_config_pdu->power_control_offset_ss = %i\n", csirs_config_pdu->power_control_offset_ss); #endif + const NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + int32_t csi_rs_received_signal[frame_parms->nb_antennas_rx][frame_parms->samples_per_slot_wCP]; + int16_t log2_re = 0; int16_t log2_maxh = 0; uint32_t noise_power = 0; @@ -820,7 +822,7 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t uint8_t i1[3]; uint8_t i2[1]; - nr_generate_csi_rs(ue->frame_parms, + nr_generate_csi_rs(frame_parms, ue->nr_csi_rs_info->csi_rs_generated_signal, AMP, ue->nr_csi_rs_info, @@ -831,14 +833,14 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t proc, csirs_config_pdu, ue->nr_csi_rs_info, - ue->nr_csi_rs_info->csi_rs_received_signal); + csi_rs_received_signal); nr_csi_rs_channel_estimation(ue, proc, csirs_config_pdu, ue->nr_csi_rs_info, (const int32_t **) ue->nr_csi_rs_info->csi_rs_generated_signal, - (const int32_t **) ue->nr_csi_rs_info->csi_rs_received_signal, + csi_rs_received_signal, ue->nr_csi_rs_info->csi_rs_ls_estimated_channel, ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, &log2_re, diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 34f089d9f9..9556c9cba2 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -266,7 +266,6 @@ typedef struct { uint32_t ***nr_gold_csi_rs; uint8_t csi_rs_generated_signal_bits; int32_t **csi_rs_generated_signal; - int32_t **csi_rs_received_signal; int32_t ***csi_rs_ls_estimated_channel; int32_t ***csi_rs_estimated_channel_freq; } nr_csi_rs_info_t; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 1428987d40..9bd82fd4f9 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -168,7 +168,7 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, if (csirs->active == 1) { LOG_D(PHY, "CSI-RS generation started in frame %d.%d\n",frame,slot); nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *csi_params = &csirs->csirs_pdu.csi_rs_pdu_rel15; - nr_generate_csi_rs(gNB->frame_parms, gNB->common_vars.txdataF, AMP, gNB->nr_csi_rs_info, csi_params, slot); + nr_generate_csi_rs(&gNB->frame_parms, gNB->common_vars.txdataF, AMP, gNB->nr_csi_rs_info, csi_params, slot); csirs->active = 0; } } From e39be3917bfa62be6aa12b66a434c64cb12ce104 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 7 Jul 2022 14:33:40 +0100 Subject: [PATCH 195/267] Remove csi_rs_ls_estimated_channel and csi_rs_estimated_channel_freq from nr_csi_rs_info_t --- openair1/PHY/INIT/nr_init_ue.c | 20 +------------------- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 20 +++++++++++--------- openair1/PHY/defs_nr_common.h | 2 -- 3 files changed, 12 insertions(+), 30 deletions(-) diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 09bc80c4ed..acd945497f 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -159,7 +159,7 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) NR_UE_CSI_RS **const csirs_vars = ue->csirs_vars; NR_UE_SRS **const srs_vars = ue->srs_vars; - int i, j, slot, symb, gNB_id, th_id; + int i, slot, symb, gNB_id, th_id; LOG_I(PHY, "Initializing UE vars for gNB TXant %u, UE RXant %u\n", fp->nb_antennas_tx, fp->nb_antennas_rx); @@ -362,16 +362,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) for (i=0; inr_csi_rs_info->csi_rs_generated_signal[i] = (int32_t *) malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t)); } - ue->nr_csi_rs_info->csi_rs_ls_estimated_channel = (int32_t ***)malloc16(fp->nb_antennas_rx * sizeof(int32_t **) ); - ue->nr_csi_rs_info->csi_rs_estimated_channel_freq = (int32_t ***)malloc16(fp->nb_antennas_rx * sizeof(int32_t **) ); - for (i=0; inb_antennas_rx; i++) { - ue->nr_csi_rs_info->csi_rs_ls_estimated_channel[i] = (int32_t **) malloc16_clear(NR_MAX_NB_PORTS * sizeof(int32_t *)); - ue->nr_csi_rs_info->csi_rs_estimated_channel_freq[i] = (int32_t **) malloc16_clear(NR_MAX_NB_PORTS * sizeof(int32_t *)); - for (j=0; jnr_csi_rs_info->csi_rs_ls_estimated_channel[i][j] = (int32_t *) malloc16_clear(fp->ofdm_symbol_size * sizeof(int32_t)); - ue->nr_csi_rs_info->csi_rs_estimated_channel_freq[i][j] = (int32_t *) malloc16_clear(fp->ofdm_symbol_size * sizeof(int32_t)); - } - } ue->nr_csi_im_info = (nr_csi_im_info_t *)malloc16_clear(sizeof(nr_csi_im_info_t)); @@ -495,14 +485,6 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) for (int i=0; inr_csi_rs_info->csi_rs_generated_signal[i]); } - for (int i = 0; i < fp->nb_antennas_rx; i++) { - for (int j=0; jnr_csi_rs_info->csi_rs_ls_estimated_channel[i][j]); - free_and_zero(ue->nr_csi_rs_info->csi_rs_estimated_channel_freq[i][j]); - } - free_and_zero(ue->nr_csi_rs_info->csi_rs_ls_estimated_channel[i]); - free_and_zero(ue->nr_csi_rs_info->csi_rs_estimated_channel_freq[i]); - } for (int slot=0; slotslots_per_frame; slot++) { for (int symb=0; symbsymbols_per_slot; symb++) { free_and_zero(ue->nr_csi_rs_info->nr_gold_csi_rs[slot][symb]); diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 29958d7e77..09f21a96b9 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -254,8 +254,8 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, const nr_csi_rs_info_t *nr_csi_rs_info, const int32_t **csi_rs_generated_signal, const int32_t csi_rs_received_signal[][ue->frame_parms.samples_per_slot_wCP], - int32_t ***csi_rs_ls_estimated_channel, - int32_t ***csi_rs_estimated_channel_freq, + int32_t csi_rs_ls_estimated_channel[][ue->nr_csi_rs_info->N_ports][ue->frame_parms.ofdm_symbol_size], + int32_t csi_rs_estimated_channel_freq[][ue->nr_csi_rs_info->N_ports][ue->frame_parms.ofdm_symbol_size], int16_t *log2_re, int16_t *log2_maxh, uint32_t *noise_power) { @@ -422,7 +422,7 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue, const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, const nr_csi_rs_info_t *nr_csi_rs_info, - int32_t ***csi_rs_estimated_channel_freq, + int32_t csi_rs_estimated_channel_freq[][ue->nr_csi_rs_info->N_ports][ue->frame_parms.ofdm_symbol_size], const int16_t log2_maxh, uint8_t *rank_indicator) { @@ -553,7 +553,7 @@ int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue, int nr_csi_rs_pmi_estimation(const PHY_VARS_NR_UE *ue, const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, const nr_csi_rs_info_t *nr_csi_rs_info, - const int32_t ***csi_rs_estimated_channel_freq, + const int32_t csi_rs_estimated_channel_freq[][ue->nr_csi_rs_info->N_ports][ue->frame_parms.ofdm_symbol_size], const uint32_t interference_plus_noise_power, const uint8_t rank_indicator, const int16_t log2_re, @@ -812,7 +812,6 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t const NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; int32_t csi_rs_received_signal[frame_parms->nb_antennas_rx][frame_parms->samples_per_slot_wCP]; - int16_t log2_re = 0; int16_t log2_maxh = 0; uint32_t noise_power = 0; @@ -829,6 +828,9 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t (nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *) csirs_config_pdu, proc->nr_slot_rx); + int32_t csi_rs_ls_estimated_channel[frame_parms->nb_antennas_rx][ue->nr_csi_rs_info->N_ports][frame_parms->ofdm_symbol_size]; + int32_t csi_rs_estimated_channel_freq[frame_parms->nb_antennas_rx][ue->nr_csi_rs_info->N_ports][frame_parms->ofdm_symbol_size]; + nr_get_csi_rs_signal(ue, proc, csirs_config_pdu, @@ -841,8 +843,8 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t ue->nr_csi_rs_info, (const int32_t **) ue->nr_csi_rs_info->csi_rs_generated_signal, csi_rs_received_signal, - ue->nr_csi_rs_info->csi_rs_ls_estimated_channel, - ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, + csi_rs_ls_estimated_channel, + csi_rs_estimated_channel_freq, &log2_re, &log2_maxh, &noise_power); @@ -850,14 +852,14 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t nr_csi_rs_ri_estimation(ue, csirs_config_pdu, ue->nr_csi_rs_info, - ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, + csi_rs_estimated_channel_freq, log2_maxh, &rank_indicator); nr_csi_rs_pmi_estimation(ue, csirs_config_pdu, ue->nr_csi_rs_info, - (const int32_t ***) ue->nr_csi_rs_info->csi_rs_estimated_channel_freq, + csi_rs_estimated_channel_freq, ue->nr_csi_im_info->meas_computed ? ue->nr_csi_im_info->interference_plus_noise_power : noise_power, rank_indicator, log2_re, diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 9556c9cba2..3cc2a1245a 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -266,8 +266,6 @@ typedef struct { uint32_t ***nr_gold_csi_rs; uint8_t csi_rs_generated_signal_bits; int32_t **csi_rs_generated_signal; - int32_t ***csi_rs_ls_estimated_channel; - int32_t ***csi_rs_estimated_channel_freq; } nr_csi_rs_info_t; typedef struct { From 36a9139a660401a8e2f30548d241c88e099b1867 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 7 Jul 2022 15:51:02 +0100 Subject: [PATCH 196/267] Remove N_cdm_groups, CDM_group_size, kprime and lprime from nr_csi_rs_info_t --- openair1/PHY/NR_TRANSPORT/nr_csi_rs.c | 37 +++--- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 11 +- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 108 ++++++++++++------ openair1/PHY/defs_nr_common.h | 5 - openair1/SCHED_NR/phy_procedures_nr_gNB.c | 2 +- 5 files changed, 101 insertions(+), 62 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c b/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c index 86917473b7..74630ece74 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c +++ b/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c @@ -45,10 +45,15 @@ void nr_init_csi_rs(const NR_DL_FRAME_PARMS *fp, uint32_t ***csi_rs, uint32_t Ni void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms, int32_t **dataF, - int16_t amp, + const int16_t amp, nr_csi_rs_info_t *nr_csi_rs_info, - nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *csi_params, - int slot){ + const nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *csi_params, + const int slot, + uint8_t *N_cdm_groups, + uint8_t *CDM_group_size, + uint8_t *k_prime, + uint8_t *l_prime, + uint8_t *N_ports) { #ifdef NR_CSIRS_DEBUG LOG_I(NR_PHY, "csi_params->subcarrier_spacing = %i\n", csi_params->subcarrier_spacing); @@ -638,23 +643,25 @@ void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms, } } } - nr_csi_rs_info->N_cdm_groups = size; - nr_csi_rs_info->CDM_group_size = gs; - nr_csi_rs_info->kprime = kprime; - nr_csi_rs_info->lprime = lprime; - nr_csi_rs_info->N_ports = ports; + if (N_cdm_groups) *N_cdm_groups = size; + if (CDM_group_size) *CDM_group_size = gs; + if (k_prime) *k_prime = kprime; + if (l_prime) *l_prime = lprime; + if (N_ports) *N_ports = ports; memcpy(nr_csi_rs_info->j,j,16*sizeof(uint8_t)); memcpy(nr_csi_rs_info->koverline,koverline,16*sizeof(uint8_t)); memcpy(nr_csi_rs_info->loverline,loverline,16*sizeof(uint8_t)); #ifdef NR_CSIRS_DEBUG - LOG_I(NR_PHY, "nr_csi_rs_info->N_ports = %d\n", nr_csi_rs_info->N_ports); - LOG_I(NR_PHY, "nr_csi_rs_info->N_cdm_groups = %d\n", nr_csi_rs_info->N_cdm_groups); - LOG_I(NR_PHY, "nr_csi_rs_info->CDM_group_size = %d\n", nr_csi_rs_info->CDM_group_size); - LOG_I(NR_PHY, "nr_csi_rs_info->kprime = %d\n", nr_csi_rs_info->kprime); - LOG_I(NR_PHY, "nr_csi_rs_info->lprime = %d\n", nr_csi_rs_info->lprime); - for(int ji=0; jiN_cdm_groups; ji++) { - LOG_I(NR_PHY, "(CDM group %d) j = %d, koverline = %d, loverline = %d\n", ji, nr_csi_rs_info->j[ji], nr_csi_rs_info->koverline[ji], nr_csi_rs_info->loverline[ji]); + if (N_ports) LOG_I(NR_PHY, "nr_csi_rs_info->N_ports = %d\n", *N_ports); + if (N_cdm_groups) LOG_I(NR_PHY, "nr_csi_rs_info->N_cdm_groups = %d\n", *N_cdm_groups); + if (CDM_group_size) LOG_I(NR_PHY, "nr_csi_rs_info->CDM_group_size = %d\n", *CDM_group_size); + if (k_prime) LOG_I(NR_PHY, "nr_csi_rs_info->kprime = %d\n", *k_prime); + if (l_prime) LOG_I(NR_PHY, "nr_csi_rs_info->lprime = %d\n", *l_prime); + if (N_cdm_groups) { + for(int ji=0; ji<*N_cdm_groups; ji++) { + LOG_I(NR_PHY, "(CDM group %d) j = %d, koverline = %d, loverline = %d\n", ji, nr_csi_rs_info->j[ji], nr_csi_rs_info->koverline[ji], nr_csi_rs_info->loverline[ji]); + } } #endif } diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index ce201b3302..76a4931c96 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -339,10 +339,15 @@ uint8_t get_nr_prach_duration(uint8_t prach_format); void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms, int32_t **dataF, - int16_t amp, + const int16_t amp, nr_csi_rs_info_t *nr_csi_rs_info, - nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *csi_params, - int slot); + const nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *csi_params, + const int slot, + uint8_t *N_cdm_groups, + uint8_t *CDM_group_size, + uint8_t *k_prime, + uint8_t *l_prime, + uint8_t *N_ports); void free_nr_prach_entry(PHY_VARS_gNB *gNB, int prach_id); diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 09f21a96b9..aacdfb7f22 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -178,6 +178,10 @@ int nr_get_csi_rs_signal(const PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, const nr_csi_rs_info_t *nr_csi_rs_info, + const uint8_t N_cdm_groups, + const uint8_t CDM_group_size, + const uint8_t k_prime, + const uint8_t l_prime, int32_t csi_rs_received_signal[][ue->frame_parms.samples_per_slot_wCP]) { int32_t **rxdataF = ue->common_vars.common_vars_rx_data_per_thread[proc->thread_id].rxdataF; @@ -192,16 +196,16 @@ int nr_get_csi_rs_signal(const PHY_VARS_NR_UE *ue, continue; } - for (int cdm_id = 0; cdm_id < nr_csi_rs_info->N_cdm_groups; cdm_id++) { - for (int s = 0; s < nr_csi_rs_info->CDM_group_size; s++) { + for (int cdm_id = 0; cdm_id < N_cdm_groups; cdm_id++) { + for (int s = 0; s < CDM_group_size; s++) { // loop over frequency resource elements within a group - for (int kp = 0; kp <= nr_csi_rs_info->kprime; kp++) { + for (int kp = 0; kp <= k_prime; kp++) { uint16_t k = (frame_parms->first_carrier_offset + (rb*NR_NB_SC_PER_RB)+nr_csi_rs_info->koverline[cdm_id] + kp) % frame_parms->ofdm_symbol_size; // loop over time resource elements within a group - for (int lp = 0; lp <= nr_csi_rs_info->lprime; lp++) { + for (int lp = 0; lp <= l_prime; lp++) { uint16_t symb = lp + nr_csi_rs_info->loverline[cdm_id]; uint64_t symbol_offset = symb*frame_parms->ofdm_symbol_size; c16_t *rx_signal = (c16_t*)&rxdataF[ant_rx][symbol_offset]; @@ -211,7 +215,7 @@ int nr_get_csi_rs_signal(const PHY_VARS_NR_UE *ue, #ifdef NR_CSIRS_DEBUG int dataF_offset = proc->nr_slot_rx*ue->frame_parms.samples_per_slot_wCP; - uint16_t port_tx = s+nr_csi_rs_info->j[cdm_id]*nr_csi_rs_info->CDM_group_size; + uint16_t port_tx = s+nr_csi_rs_info->j[cdm_id]*CDM_group_size; c16_t *tx_csi_rs_signal = (c16_t*)&nr_csi_rs_info->csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset]; LOG_I(NR_PHY, "l,k (%2d,%4d) |\tport_tx %d (%4d,%4d)\tant_rx %d (%4d,%4d)\n", symb, @@ -254,8 +258,13 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, const nr_csi_rs_info_t *nr_csi_rs_info, const int32_t **csi_rs_generated_signal, const int32_t csi_rs_received_signal[][ue->frame_parms.samples_per_slot_wCP], - int32_t csi_rs_ls_estimated_channel[][ue->nr_csi_rs_info->N_ports][ue->frame_parms.ofdm_symbol_size], - int32_t csi_rs_estimated_channel_freq[][ue->nr_csi_rs_info->N_ports][ue->frame_parms.ofdm_symbol_size], + const uint8_t N_cdm_groups, + const uint8_t CDM_group_size, + const uint8_t k_prime, + const uint8_t l_prime, + const uint8_t N_ports, + int32_t csi_rs_ls_estimated_channel[][N_ports][ue->frame_parms.ofdm_symbol_size], + int32_t csi_rs_estimated_channel_freq[][N_ports][ue->frame_parms.ofdm_symbol_size], int16_t *log2_re, int16_t *log2_maxh, uint32_t *noise_power) { @@ -270,7 +279,7 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, /// LS channel estimation - for(uint16_t port_tx = 0; port_txN_ports; port_tx++) { + for(uint16_t port_tx = 0; port_txofdm_symbol_size*sizeof(int32_t)); } @@ -281,19 +290,19 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, continue; } - for (int cdm_id = 0; cdm_id < nr_csi_rs_info->N_cdm_groups; cdm_id++) { - for (int s = 0; s < nr_csi_rs_info->CDM_group_size; s++) { + for (int cdm_id = 0; cdm_id < N_cdm_groups; cdm_id++) { + for (int s = 0; s < CDM_group_size; s++) { - uint16_t port_tx = s+nr_csi_rs_info->j[cdm_id]*nr_csi_rs_info->CDM_group_size; + uint16_t port_tx = s+nr_csi_rs_info->j[cdm_id]*CDM_group_size; // loop over frequency resource elements within a group - for (int kp = 0; kp <= nr_csi_rs_info->kprime; kp++) { + for (int kp = 0; kp <= k_prime; kp++) { uint16_t kinit = (frame_parms->first_carrier_offset + rb*NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size; uint16_t k = kinit + nr_csi_rs_info->koverline[cdm_id] + kp; // loop over time resource elements within a group - for (int lp = 0; lp <= nr_csi_rs_info->lprime; lp++) { + for (int lp = 0; lp <= l_prime; lp++) { uint16_t symb = lp + nr_csi_rs_info->loverline[cdm_id]; uint64_t symbol_offset = symb*frame_parms->ofdm_symbol_size; c16_t *tx_csi_rs_signal = (c16_t*)&csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset]; @@ -320,7 +329,7 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, } for(int k = 0; kofdm_symbol_size; k++) { LOG_I(NR_PHY, "l,k (%2d,%4d) | ", symb, k); - for(uint16_t port_tx = 0; port_txN_ports; port_tx++) { + for(uint16_t port_tx = 0; port_txofdm_symbol_size; c16_t *tx_csi_rs_signal = (c16_t*)&csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset]; c16_t *rx_csi_rs_signal = (c16_t*)&csi_rs_received_signal[ant_rx][symbol_offset]; @@ -338,7 +347,7 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, /// Channel interpolation - for(uint16_t port_tx = 0; port_txN_ports; port_tx++) { + for(uint16_t port_tx = 0; port_txofdm_symbol_size*sizeof(int32_t)); } @@ -352,7 +361,7 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, count++; uint16_t k = (frame_parms->first_carrier_offset + rb*NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size; - for(uint16_t port_tx = 0; port_txN_ports; port_tx++) { + for(uint16_t port_tx = 0; port_txfirst_carrier_offset) ) { // Start of OFDM symbol case or first occupied subcarrier case @@ -367,14 +376,14 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, } /// Power noise estimation - uint16_t noise_real[frame_parms->nb_antennas_rx][nr_csi_rs_info->N_ports][csirs_config_pdu->nr_of_rbs]; - uint16_t noise_imag[frame_parms->nb_antennas_rx][nr_csi_rs_info->N_ports][csirs_config_pdu->nr_of_rbs]; + uint16_t noise_real[frame_parms->nb_antennas_rx][N_ports][csirs_config_pdu->nr_of_rbs]; + uint16_t noise_imag[frame_parms->nb_antennas_rx][N_ports][csirs_config_pdu->nr_of_rbs]; for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) { if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) { continue; } uint16_t k = (frame_parms->first_carrier_offset + rb*NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size; - for(uint16_t port_tx = 0; port_txN_ports; port_tx++) { + for(uint16_t port_tx = 0; port_txstart_rb] = abs(csi_rs_ls_estimated_channel16->r-csi_rs_estimated_channel16->r); @@ -382,7 +391,7 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, maxh = cmax3(maxh, abs(csi_rs_estimated_channel16->r), abs(csi_rs_estimated_channel16->i)); } } - for(uint16_t port_tx = 0; port_txN_ports; port_tx++) { + for(uint16_t port_tx = 0; port_txfirst_carrier_offset)/NR_NB_SC_PER_RB : (k + frame_parms->ofdm_symbol_size - frame_parms->first_carrier_offset)/NR_NB_SC_PER_RB; LOG_I(NR_PHY, "(k = %4d) |\t", k); - for(uint16_t port_tx = 0; port_txN_ports; port_tx++) { + for(uint16_t port_tx = 0; port_tx ant_rx %d : ls (%4d,%4d), int (%4d,%4d), noise (%4d,%4d) | ", @@ -408,7 +417,7 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, } - *noise_power /= (frame_parms->nb_antennas_rx*nr_csi_rs_info->N_ports); + *noise_power /= (frame_parms->nb_antennas_rx*N_ports); *log2_maxh = log2_approx(maxh-1); *log2_re = log2_approx(count-1); @@ -422,7 +431,8 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue, const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, const nr_csi_rs_info_t *nr_csi_rs_info, - int32_t csi_rs_estimated_channel_freq[][ue->nr_csi_rs_info->N_ports][ue->frame_parms.ofdm_symbol_size], + const uint8_t N_ports, + int32_t csi_rs_estimated_channel_freq[][N_ports][ue->frame_parms.ofdm_symbol_size], const int16_t log2_maxh, uint8_t *rank_indicator) { @@ -431,11 +441,11 @@ int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue, int count = 0; *rank_indicator = 0; - if (ue->frame_parms.nb_antennas_rx == 1 || ue->nr_csi_rs_info->N_ports == 1) { + if (ue->frame_parms.nb_antennas_rx == 1 || N_ports == 1) { return 0; - } else if( !(ue->frame_parms.nb_antennas_rx == 2 && ue->nr_csi_rs_info->N_ports == 2) ) { + } else if( !(ue->frame_parms.nb_antennas_rx == 2 && N_ports == 2) ) { LOG_W(NR_PHY, "Rank indicator computation is not implemented for %i x %i system\n", - ue->frame_parms.nb_antennas_rx, ue->nr_csi_rs_info->N_ports); + ue->frame_parms.nb_antennas_rx, N_ports); return -1; } @@ -444,9 +454,9 @@ int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue, * | conjch01 conjch11 | | ch10 ch11 | | conjch01*ch00+conjch11*ch10 conjch01*ch01+conjch11*ch11 | */ - int32_t csi_rs_estimated_conjch_ch[frame_parms->nb_antennas_rx][nr_csi_rs_info->N_ports][frame_parms->nb_antennas_rx][nr_csi_rs_info->N_ports][frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); - int32_t csi_rs_estimated_A_MF[nr_csi_rs_info->N_ports][nr_csi_rs_info->N_ports][frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); - int32_t csi_rs_estimated_A_MF_sq[nr_csi_rs_info->N_ports][nr_csi_rs_info->N_ports][frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); + int32_t csi_rs_estimated_conjch_ch[frame_parms->nb_antennas_rx][N_ports][frame_parms->nb_antennas_rx][N_ports][frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); + int32_t csi_rs_estimated_A_MF[N_ports][N_ports][frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); + int32_t csi_rs_estimated_A_MF_sq[N_ports][N_ports][frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); int32_t csi_rs_estimated_determ_fin[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); int32_t csi_rs_estimated_numer_fin[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); @@ -460,9 +470,9 @@ int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue, uint16_t k = (frame_parms->first_carrier_offset + rb*NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size; for (int ant_rx_conjch = 0; ant_rx_conjch < frame_parms->nb_antennas_rx; ant_rx_conjch++) { - for(uint16_t port_tx_conjch = 0; port_tx_conjch < nr_csi_rs_info->N_ports; port_tx_conjch++) { + for(uint16_t port_tx_conjch = 0; port_tx_conjch < N_ports; port_tx_conjch++) { for (int ant_rx_ch = 0; ant_rx_ch < frame_parms->nb_antennas_rx; ant_rx_ch++) { - for(uint16_t port_tx_ch = 0; port_tx_ch < nr_csi_rs_info->N_ports; port_tx_ch++) { + for(uint16_t port_tx_ch = 0; port_tx_ch < N_ports; port_tx_ch++) { // conjch x ch computation nr_conjch0_mult_ch1(&csi_rs_estimated_channel_freq[ant_rx_conjch][port_tx_conjch][k], @@ -503,8 +513,8 @@ int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue, 1); #ifdef NR_CSIRS_DEBUG - for(uint16_t port_tx_conjch = 0; port_tx_conjch < nr_csi_rs_info->N_ports; port_tx_conjch++) { - for(uint16_t port_tx_ch = 0; port_tx_ch < nr_csi_rs_info->N_ports; port_tx_ch++) { + for(uint16_t port_tx_conjch = 0; port_tx_conjch < N_ports; port_tx_conjch++) { + for(uint16_t port_tx_ch = 0; port_tx_ch < N_ports; port_tx_ch++) { c16_t *csi_rs_estimated_A_MF_k = (c16_t *) &csi_rs_estimated_A_MF[port_tx_conjch][port_tx_ch][k]; LOG_I(NR_PHY, "(%i) csi_rs_estimated_A_MF[%i][%i] = (%i, %i)\n", k, port_tx_conjch, port_tx_ch, csi_rs_estimated_A_MF_k->r, csi_rs_estimated_A_MF_k->i); @@ -553,7 +563,8 @@ int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue, int nr_csi_rs_pmi_estimation(const PHY_VARS_NR_UE *ue, const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, const nr_csi_rs_info_t *nr_csi_rs_info, - const int32_t csi_rs_estimated_channel_freq[][ue->nr_csi_rs_info->N_ports][ue->frame_parms.ofdm_symbol_size], + const uint8_t N_ports, + const int32_t csi_rs_estimated_channel_freq[][N_ports][ue->frame_parms.ofdm_symbol_size], const uint32_t interference_plus_noise_power, const uint8_t rank_indicator, const int16_t log2_re, @@ -574,7 +585,7 @@ int nr_csi_rs_pmi_estimation(const PHY_VARS_NR_UE *ue, // The first column is applicable if the UE is reporting a Rank = 1, whereas the second column is applicable if the // UE is reporting a Rank = 2. - if(nr_csi_rs_info->N_ports == 1 || interference_plus_noise_power == 0) { + if(N_ports == 1 || interference_plus_noise_power == 0) { return 0; } @@ -812,6 +823,11 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t const NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; int32_t csi_rs_received_signal[frame_parms->nb_antennas_rx][frame_parms->samples_per_slot_wCP]; + uint8_t N_cdm_groups = 0; + uint8_t CDM_group_size = 0; + uint8_t k_prime = 0; + uint8_t l_prime = 0; + uint8_t N_ports = 0; int16_t log2_re = 0; int16_t log2_maxh = 0; uint32_t noise_power = 0; @@ -826,15 +842,24 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t AMP, ue->nr_csi_rs_info, (nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *) csirs_config_pdu, - proc->nr_slot_rx); + proc->nr_slot_rx, + &N_cdm_groups, + &CDM_group_size, + &k_prime, + &l_prime, + &N_ports); - int32_t csi_rs_ls_estimated_channel[frame_parms->nb_antennas_rx][ue->nr_csi_rs_info->N_ports][frame_parms->ofdm_symbol_size]; - int32_t csi_rs_estimated_channel_freq[frame_parms->nb_antennas_rx][ue->nr_csi_rs_info->N_ports][frame_parms->ofdm_symbol_size]; + int32_t csi_rs_ls_estimated_channel[frame_parms->nb_antennas_rx][N_ports][frame_parms->ofdm_symbol_size]; + int32_t csi_rs_estimated_channel_freq[frame_parms->nb_antennas_rx][N_ports][frame_parms->ofdm_symbol_size]; nr_get_csi_rs_signal(ue, proc, csirs_config_pdu, ue->nr_csi_rs_info, + N_cdm_groups, + CDM_group_size, + k_prime, + l_prime, csi_rs_received_signal); nr_csi_rs_channel_estimation(ue, @@ -843,6 +868,11 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t ue->nr_csi_rs_info, (const int32_t **) ue->nr_csi_rs_info->csi_rs_generated_signal, csi_rs_received_signal, + N_cdm_groups, + CDM_group_size, + k_prime, + l_prime, + N_ports, csi_rs_ls_estimated_channel, csi_rs_estimated_channel_freq, &log2_re, @@ -852,6 +882,7 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t nr_csi_rs_ri_estimation(ue, csirs_config_pdu, ue->nr_csi_rs_info, + N_ports, csi_rs_estimated_channel_freq, log2_maxh, &rank_indicator); @@ -859,6 +890,7 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t nr_csi_rs_pmi_estimation(ue, csirs_config_pdu, ue->nr_csi_rs_info, + N_ports, csi_rs_estimated_channel_freq, ue->nr_csi_im_info->meas_computed ? ue->nr_csi_im_info->interference_plus_noise_power : noise_power, rank_indicator, diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 3cc2a1245a..3180207b3a 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -254,11 +254,6 @@ typedef struct { } nr_srs_info_t; typedef struct { - uint8_t N_cdm_groups; - uint8_t CDM_group_size; - uint8_t kprime; - uint8_t lprime; - uint8_t N_ports; uint8_t j[16]; uint8_t koverline[16]; uint8_t loverline[16]; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 9bd82fd4f9..7aa12cd812 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -168,7 +168,7 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, if (csirs->active == 1) { LOG_D(PHY, "CSI-RS generation started in frame %d.%d\n",frame,slot); nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *csi_params = &csirs->csirs_pdu.csi_rs_pdu_rel15; - nr_generate_csi_rs(&gNB->frame_parms, gNB->common_vars.txdataF, AMP, gNB->nr_csi_rs_info, csi_params, slot); + nr_generate_csi_rs(&gNB->frame_parms, gNB->common_vars.txdataF, AMP, gNB->nr_csi_rs_info, csi_params, slot, NULL, NULL, NULL, NULL, NULL); csirs->active = 0; } } From 3025627c0634d65ae6a64df1a8a52ebeb179f082 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 7 Jul 2022 17:23:18 +0100 Subject: [PATCH 197/267] Remove j, koverline and loverline from nr_csi_rs_info_t --- openair1/PHY/NR_TRANSPORT/nr_csi_rs.c | 13 +++++--- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 5 ++- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 32 +++++++++++++++---- openair1/PHY/defs_nr_common.h | 3 -- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 2 +- 5 files changed, 38 insertions(+), 17 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c b/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c index 74630ece74..e0b0432462 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c +++ b/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c @@ -53,7 +53,10 @@ void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms, uint8_t *CDM_group_size, uint8_t *k_prime, uint8_t *l_prime, - uint8_t *N_ports) { + uint8_t *N_ports, + uint8_t *j_cdm, + uint8_t *k_overline, + uint8_t *l_overline) { #ifdef NR_CSIRS_DEBUG LOG_I(NR_PHY, "csi_params->subcarrier_spacing = %i\n", csi_params->subcarrier_spacing); @@ -648,9 +651,9 @@ void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms, if (k_prime) *k_prime = kprime; if (l_prime) *l_prime = lprime; if (N_ports) *N_ports = ports; - memcpy(nr_csi_rs_info->j,j,16*sizeof(uint8_t)); - memcpy(nr_csi_rs_info->koverline,koverline,16*sizeof(uint8_t)); - memcpy(nr_csi_rs_info->loverline,loverline,16*sizeof(uint8_t)); + if (j_cdm) memcpy(j_cdm,j,16*sizeof(uint8_t)); + if (k_overline) memcpy(k_overline,koverline,16*sizeof(uint8_t)); + if (l_overline) memcpy(l_overline,loverline,16*sizeof(uint8_t)); #ifdef NR_CSIRS_DEBUG if (N_ports) LOG_I(NR_PHY, "nr_csi_rs_info->N_ports = %d\n", *N_ports); @@ -660,7 +663,7 @@ void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms, if (l_prime) LOG_I(NR_PHY, "nr_csi_rs_info->lprime = %d\n", *l_prime); if (N_cdm_groups) { for(int ji=0; ji<*N_cdm_groups; ji++) { - LOG_I(NR_PHY, "(CDM group %d) j = %d, koverline = %d, loverline = %d\n", ji, nr_csi_rs_info->j[ji], nr_csi_rs_info->koverline[ji], nr_csi_rs_info->loverline[ji]); + LOG_I(NR_PHY, "(CDM group %d) j = %d, koverline = %d, loverline = %d\n", ji, j[ji], koverline[ji], loverline[ji]); } } #endif diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 76a4931c96..4b0c056642 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -347,7 +347,10 @@ void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms, uint8_t *CDM_group_size, uint8_t *k_prime, uint8_t *l_prime, - uint8_t *N_ports); + uint8_t *N_ports, + uint8_t *j_cdm, + uint8_t *k_overline, + uint8_t *l_overline); void free_nr_prach_entry(PHY_VARS_gNB *gNB, int prach_id); diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index aacdfb7f22..43b1ae8506 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -182,6 +182,9 @@ int nr_get_csi_rs_signal(const PHY_VARS_NR_UE *ue, const uint8_t CDM_group_size, const uint8_t k_prime, const uint8_t l_prime, + const uint8_t *j_cdm, + const uint8_t *k_overline, + const uint8_t *l_overline, int32_t csi_rs_received_signal[][ue->frame_parms.samples_per_slot_wCP]) { int32_t **rxdataF = ue->common_vars.common_vars_rx_data_per_thread[proc->thread_id].rxdataF; @@ -202,11 +205,11 @@ int nr_get_csi_rs_signal(const PHY_VARS_NR_UE *ue, // loop over frequency resource elements within a group for (int kp = 0; kp <= k_prime; kp++) { - uint16_t k = (frame_parms->first_carrier_offset + (rb*NR_NB_SC_PER_RB)+nr_csi_rs_info->koverline[cdm_id] + kp) % frame_parms->ofdm_symbol_size; + uint16_t k = (frame_parms->first_carrier_offset + (rb*NR_NB_SC_PER_RB)+k_overline[cdm_id] + kp) % frame_parms->ofdm_symbol_size; // loop over time resource elements within a group for (int lp = 0; lp <= l_prime; lp++) { - uint16_t symb = lp + nr_csi_rs_info->loverline[cdm_id]; + uint16_t symb = lp + l_overline[cdm_id]; uint64_t symbol_offset = symb*frame_parms->ofdm_symbol_size; c16_t *rx_signal = (c16_t*)&rxdataF[ant_rx][symbol_offset]; c16_t *rx_csi_rs_signal = (c16_t*)&csi_rs_received_signal[ant_rx][symbol_offset]; @@ -215,7 +218,7 @@ int nr_get_csi_rs_signal(const PHY_VARS_NR_UE *ue, #ifdef NR_CSIRS_DEBUG int dataF_offset = proc->nr_slot_rx*ue->frame_parms.samples_per_slot_wCP; - uint16_t port_tx = s+nr_csi_rs_info->j[cdm_id]*CDM_group_size; + uint16_t port_tx = s+j_cdm[cdm_id]*CDM_group_size; c16_t *tx_csi_rs_signal = (c16_t*)&nr_csi_rs_info->csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset]; LOG_I(NR_PHY, "l,k (%2d,%4d) |\tport_tx %d (%4d,%4d)\tant_rx %d (%4d,%4d)\n", symb, @@ -263,6 +266,9 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, const uint8_t k_prime, const uint8_t l_prime, const uint8_t N_ports, + const uint8_t *j_cdm, + const uint8_t *k_overline, + const uint8_t *l_overline, int32_t csi_rs_ls_estimated_channel[][N_ports][ue->frame_parms.ofdm_symbol_size], int32_t csi_rs_estimated_channel_freq[][N_ports][ue->frame_parms.ofdm_symbol_size], int16_t *log2_re, @@ -293,17 +299,17 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, for (int cdm_id = 0; cdm_id < N_cdm_groups; cdm_id++) { for (int s = 0; s < CDM_group_size; s++) { - uint16_t port_tx = s+nr_csi_rs_info->j[cdm_id]*CDM_group_size; + uint16_t port_tx = s+j_cdm[cdm_id]*CDM_group_size; // loop over frequency resource elements within a group for (int kp = 0; kp <= k_prime; kp++) { uint16_t kinit = (frame_parms->first_carrier_offset + rb*NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size; - uint16_t k = kinit + nr_csi_rs_info->koverline[cdm_id] + kp; + uint16_t k = kinit + k_overline[cdm_id] + kp; // loop over time resource elements within a group for (int lp = 0; lp <= l_prime; lp++) { - uint16_t symb = lp + nr_csi_rs_info->loverline[cdm_id]; + uint16_t symb = lp + l_overline[cdm_id]; uint64_t symbol_offset = symb*frame_parms->ofdm_symbol_size; c16_t *tx_csi_rs_signal = (c16_t*)&csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset]; c16_t *rx_csi_rs_signal = (c16_t*)&csi_rs_received_signal[ant_rx][symbol_offset]; @@ -828,6 +834,9 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t uint8_t k_prime = 0; uint8_t l_prime = 0; uint8_t N_ports = 0; + uint8_t j_cdm[16]; + uint8_t k_overline[16]; + uint8_t l_overline[16]; int16_t log2_re = 0; int16_t log2_maxh = 0; uint32_t noise_power = 0; @@ -847,7 +856,10 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t &CDM_group_size, &k_prime, &l_prime, - &N_ports); + &N_ports, + j_cdm, + k_overline, + l_overline); int32_t csi_rs_ls_estimated_channel[frame_parms->nb_antennas_rx][N_ports][frame_parms->ofdm_symbol_size]; int32_t csi_rs_estimated_channel_freq[frame_parms->nb_antennas_rx][N_ports][frame_parms->ofdm_symbol_size]; @@ -860,6 +872,9 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t CDM_group_size, k_prime, l_prime, + j_cdm, + k_overline, + l_overline, csi_rs_received_signal); nr_csi_rs_channel_estimation(ue, @@ -873,6 +888,9 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t k_prime, l_prime, N_ports, + j_cdm, + k_overline, + l_overline, csi_rs_ls_estimated_channel, csi_rs_estimated_channel_freq, &log2_re, diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 3180207b3a..6b40847ea8 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -254,9 +254,6 @@ typedef struct { } nr_srs_info_t; typedef struct { - uint8_t j[16]; - uint8_t koverline[16]; - uint8_t loverline[16]; uint16_t csi_gold_init; uint32_t ***nr_gold_csi_rs; uint8_t csi_rs_generated_signal_bits; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 7aa12cd812..3a5d04500c 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -168,7 +168,7 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, if (csirs->active == 1) { LOG_D(PHY, "CSI-RS generation started in frame %d.%d\n",frame,slot); nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *csi_params = &csirs->csirs_pdu.csi_rs_pdu_rel15; - nr_generate_csi_rs(&gNB->frame_parms, gNB->common_vars.txdataF, AMP, gNB->nr_csi_rs_info, csi_params, slot, NULL, NULL, NULL, NULL, NULL); + nr_generate_csi_rs(&gNB->frame_parms, gNB->common_vars.txdataF, AMP, gNB->nr_csi_rs_info, csi_params, slot, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); csirs->active = 0; } } From 70d7a6687b6df1f6a7fc44e6f4ba0a58815ef2f5 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 7 Jul 2022 18:28:05 +0100 Subject: [PATCH 198/267] Merge nr_csi_rs_info_t plus nr_csi_im_info_t into nr_csi_info_t --- openair1/PHY/INIT/nr_init.c | 22 ++++++------ openair1/PHY/INIT/nr_init_ue.c | 32 ++++++++--------- openair1/PHY/NR_TRANSPORT/nr_csi_rs.c | 22 ++++++------ .../PHY/NR_TRANSPORT/nr_transport_proto.h | 2 +- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 36 +++++++++---------- .../PHY/NR_UE_TRANSPORT/nr_initial_sync.c | 2 +- openair1/PHY/defs_gNB.h | 4 +-- openair1/PHY/defs_nr_UE.h | 7 ++-- openair1/PHY/defs_nr_common.h | 7 ++-- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 2 +- 10 files changed, 63 insertions(+), 73 deletions(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index e2139a9903..b2167453e3 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -596,20 +596,20 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, // CSI RS init // ceil((NB_RB*8(max allocation per RB)*2(QPSK))/32) int csi_dmrs_init_length = ((fp->N_RB_DL<<4)>>5)+1; - gNB->nr_csi_rs_info = (nr_csi_rs_info_t *)malloc16_clear(sizeof(nr_csi_rs_info_t)); - gNB->nr_csi_rs_info->nr_gold_csi_rs = (uint32_t ***)malloc16(fp->slots_per_frame*sizeof(uint32_t **)); - AssertFatal(gNB->nr_csi_rs_info->nr_gold_csi_rs!=NULL, "NR init: csi reference signal malloc failed\n"); + gNB->nr_csi_info = (nr_csi_info_t *)malloc16_clear(sizeof(nr_csi_info_t)); + gNB->nr_csi_info->nr_gold_csi_rs = (uint32_t ***)malloc16(fp->slots_per_frame * sizeof(uint32_t **)); + AssertFatal(gNB->nr_csi_info->nr_gold_csi_rs != NULL, "NR init: csi reference signal malloc failed\n"); for (int slot=0; slotslots_per_frame; slot++) { - gNB->nr_csi_rs_info->nr_gold_csi_rs[slot] = (uint32_t **)malloc16(fp->symbols_per_slot*sizeof(uint32_t *)); - AssertFatal(gNB->nr_csi_rs_info->nr_gold_csi_rs[slot]!=NULL, "NR init: csi reference signal for slot %d - malloc failed\n", slot); + gNB->nr_csi_info->nr_gold_csi_rs[slot] = (uint32_t **)malloc16(fp->symbols_per_slot * sizeof(uint32_t *)); + AssertFatal(gNB->nr_csi_info->nr_gold_csi_rs[slot] != NULL, "NR init: csi reference signal for slot %d - malloc failed\n", slot); for (int symb=0; symbsymbols_per_slot; symb++) { - gNB->nr_csi_rs_info->nr_gold_csi_rs[slot][symb] = (uint32_t *)malloc16(csi_dmrs_init_length*sizeof(uint32_t)); - AssertFatal(gNB->nr_csi_rs_info->nr_gold_csi_rs[slot][symb]!=NULL, "NR init: csi reference signal for slot %d symbol %d - malloc failed\n", slot, symb); + gNB->nr_csi_info->nr_gold_csi_rs[slot][symb] = (uint32_t *)malloc16(csi_dmrs_init_length * sizeof(uint32_t)); + AssertFatal(gNB->nr_csi_info->nr_gold_csi_rs[slot][symb] != NULL, "NR init: csi reference signal for slot %d symbol %d - malloc failed\n", slot, symb); } } - gNB->nr_csi_rs_info->csi_gold_init = cfg->cell_config.phy_cell_id.value; - nr_init_csi_rs(&gNB->frame_parms, gNB->nr_csi_rs_info->nr_gold_csi_rs, cfg->cell_config.phy_cell_id.value); + gNB->nr_csi_info->csi_gold_init = cfg->cell_config.phy_cell_id.value; + nr_init_csi_rs(&gNB->frame_parms, gNB->nr_csi_info->nr_gold_csi_rs, cfg->cell_config.phy_cell_id.value); for (int id=0; idnr_srs_info[id] = (nr_srs_info_t *)malloc16_clear(sizeof(nr_srs_info_t)); @@ -775,14 +775,14 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) } free_and_zero(pusch_dmrs); - uint32_t ***nr_gold_csi_rs = gNB->nr_csi_rs_info->nr_gold_csi_rs; + uint32_t ***nr_gold_csi_rs = gNB->nr_csi_info->nr_gold_csi_rs; for (int slot = 0; slot < fp->slots_per_frame; slot++) { for (int symb = 0; symb < fp->symbols_per_slot; symb++) free_and_zero(nr_gold_csi_rs[slot][symb]); free_and_zero(nr_gold_csi_rs[slot]); } free_and_zero(nr_gold_csi_rs); - free_and_zero(gNB->nr_csi_rs_info); + free_and_zero(gNB->nr_csi_info); for (int id = 0; id < NUMBER_OF_NR_SRS_MAX; id++) { for (int i = 0; i < Prx; i++) { diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index acd945497f..0efdb1e8e1 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -347,24 +347,22 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) // ceil((NB_RB*8(max allocation per RB)*2(QPSK))/32) int csi_dmrs_init_length = ((fp->N_RB_DL<<4)>>5)+1; - ue->nr_csi_rs_info = (nr_csi_rs_info_t *)malloc16_clear(sizeof(nr_csi_rs_info_t)); - ue->nr_csi_rs_info->nr_gold_csi_rs = (uint32_t ***)malloc16(fp->slots_per_frame*sizeof(uint32_t **)); - AssertFatal(ue->nr_csi_rs_info->nr_gold_csi_rs!=NULL, "NR init: csi reference signal malloc failed\n"); + ue->nr_csi_info = (nr_csi_info_t *)malloc16_clear(sizeof(nr_csi_info_t)); + ue->nr_csi_info->nr_gold_csi_rs = (uint32_t ***)malloc16(fp->slots_per_frame * sizeof(uint32_t **)); + AssertFatal(ue->nr_csi_info->nr_gold_csi_rs != NULL, "NR init: csi reference signal malloc failed\n"); for (int slot=0; slotslots_per_frame; slot++) { - ue->nr_csi_rs_info->nr_gold_csi_rs[slot] = (uint32_t **)malloc16(fp->symbols_per_slot*sizeof(uint32_t *)); - AssertFatal(ue->nr_csi_rs_info->nr_gold_csi_rs[slot]!=NULL, "NR init: csi reference signal for slot %d - malloc failed\n", slot); + ue->nr_csi_info->nr_gold_csi_rs[slot] = (uint32_t **)malloc16(fp->symbols_per_slot * sizeof(uint32_t *)); + AssertFatal(ue->nr_csi_info->nr_gold_csi_rs[slot] != NULL, "NR init: csi reference signal for slot %d - malloc failed\n", slot); for (int symb=0; symbsymbols_per_slot; symb++) { - ue->nr_csi_rs_info->nr_gold_csi_rs[slot][symb] = (uint32_t *)malloc16(csi_dmrs_init_length*sizeof(uint32_t)); - AssertFatal(ue->nr_csi_rs_info->nr_gold_csi_rs[slot][symb]!=NULL, "NR init: csi reference signal for slot %d symbol %d - malloc failed\n", slot, symb); + ue->nr_csi_info->nr_gold_csi_rs[slot][symb] = (uint32_t *)malloc16(csi_dmrs_init_length * sizeof(uint32_t)); + AssertFatal(ue->nr_csi_info->nr_gold_csi_rs[slot][symb] != NULL, "NR init: csi reference signal for slot %d symbol %d - malloc failed\n", slot, symb); } } - ue->nr_csi_rs_info->csi_rs_generated_signal = (int32_t **)malloc16(NR_MAX_NB_PORTS * sizeof(int32_t *) ); + ue->nr_csi_info->csi_rs_generated_signal = (int32_t **)malloc16(NR_MAX_NB_PORTS * sizeof(int32_t *) ); for (i=0; inr_csi_rs_info->csi_rs_generated_signal[i] = (int32_t *) malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t)); + ue->nr_csi_info->csi_rs_generated_signal[i] = (int32_t *) malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t)); } - ue->nr_csi_im_info = (nr_csi_im_info_t *)malloc16_clear(sizeof(nr_csi_im_info_t)); - ue->nr_srs_info = (nr_srs_info_t *)malloc16_clear(sizeof(nr_srs_info_t)); ue->nr_srs_info->sc_list = (uint16_t *) malloc16_clear(6*fp->N_RB_UL*sizeof(uint16_t)); ue->nr_srs_info->srs_generated_signal = (int32_t *) malloc16_clear( (2*(fp->samples_per_frame)+2048)*sizeof(int32_t) ); @@ -483,18 +481,16 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) } for (int i=0; inr_csi_rs_info->csi_rs_generated_signal[i]); + free_and_zero(ue->nr_csi_info->csi_rs_generated_signal[i]); } for (int slot=0; slotslots_per_frame; slot++) { for (int symb=0; symbsymbols_per_slot; symb++) { - free_and_zero(ue->nr_csi_rs_info->nr_gold_csi_rs[slot][symb]); + free_and_zero(ue->nr_csi_info->nr_gold_csi_rs[slot][symb]); } - free_and_zero(ue->nr_csi_rs_info->nr_gold_csi_rs[slot]); + free_and_zero(ue->nr_csi_info->nr_gold_csi_rs[slot]); } - free_and_zero(ue->nr_csi_rs_info->nr_gold_csi_rs); - free_and_zero(ue->nr_csi_rs_info); - - free_and_zero(ue->nr_csi_im_info); + free_and_zero(ue->nr_csi_info->nr_gold_csi_rs); + free_and_zero(ue->nr_csi_info); for (int i = 0; i < fp->nb_antennas_rx; i++) { free_and_zero(ue->nr_srs_info->srs_received_signal[i]); diff --git a/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c b/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c index e0b0432462..0a1619f3e0 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c +++ b/openair1/PHY/NR_TRANSPORT/nr_csi_rs.c @@ -46,7 +46,7 @@ void nr_init_csi_rs(const NR_DL_FRAME_PARMS *fp, uint32_t ***csi_rs, uint32_t Ni void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms, int32_t **dataF, const int16_t amp, - nr_csi_rs_info_t *nr_csi_rs_info, + nr_csi_info_t *nr_csi_info, const nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *csi_params, const int slot, uint8_t *N_cdm_groups, @@ -76,7 +76,7 @@ void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms, #endif int dataF_offset = slot*frame_parms->samples_per_slot_wCP; - uint32_t **nr_gold_csi_rs = nr_csi_rs_info->nr_gold_csi_rs[slot]; + uint32_t **nr_gold_csi_rs = nr_csi_info->nr_gold_csi_rs[slot]; //*8(max allocation per RB)*2(QPSK)) int csi_rs_length = frame_parms->N_RB_DL<<4; int16_t mod_csi[frame_parms->symbols_per_slot][csi_rs_length>>1] __attribute__((aligned(16))); @@ -89,14 +89,14 @@ void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms, uint8_t fi = 0; double rho, alpha; uint32_t beta = amp; - nr_csi_rs_info->csi_rs_generated_signal_bits = log2_approx(amp); + nr_csi_info->csi_rs_generated_signal_bits = log2_approx(amp); AssertFatal(b!=0, "Invalid CSI frequency domain mapping: no bit selected in bitmap\n"); // if the scrambling id is not the one previously used to initialize we need to re-initialize the rs - if (csi_params->scramb_id != nr_csi_rs_info->csi_gold_init) { - nr_csi_rs_info->csi_gold_init = csi_params->scramb_id; - nr_init_csi_rs(frame_parms, nr_csi_rs_info->nr_gold_csi_rs, csi_params->scramb_id); + if (csi_params->scramb_id != nr_csi_info->csi_gold_init) { + nr_csi_info->csi_gold_init = csi_params->scramb_id; + nr_init_csi_rs(frame_parms, nr_csi_info->nr_gold_csi_rs, csi_params->scramb_id); } switch (csi_params->row) { @@ -656,11 +656,11 @@ void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms, if (l_overline) memcpy(l_overline,loverline,16*sizeof(uint8_t)); #ifdef NR_CSIRS_DEBUG - if (N_ports) LOG_I(NR_PHY, "nr_csi_rs_info->N_ports = %d\n", *N_ports); - if (N_cdm_groups) LOG_I(NR_PHY, "nr_csi_rs_info->N_cdm_groups = %d\n", *N_cdm_groups); - if (CDM_group_size) LOG_I(NR_PHY, "nr_csi_rs_info->CDM_group_size = %d\n", *CDM_group_size); - if (k_prime) LOG_I(NR_PHY, "nr_csi_rs_info->kprime = %d\n", *k_prime); - if (l_prime) LOG_I(NR_PHY, "nr_csi_rs_info->lprime = %d\n", *l_prime); + if (N_ports) LOG_I(NR_PHY, "nr_csi_info->N_ports = %d\n", *N_ports); + if (N_cdm_groups) LOG_I(NR_PHY, "nr_csi_info->N_cdm_groups = %d\n", *N_cdm_groups); + if (CDM_group_size) LOG_I(NR_PHY, "nr_csi_info->CDM_group_size = %d\n", *CDM_group_size); + if (k_prime) LOG_I(NR_PHY, "nr_csi_info->kprime = %d\n", *k_prime); + if (l_prime) LOG_I(NR_PHY, "nr_csi_info->lprime = %d\n", *l_prime); if (N_cdm_groups) { for(int ji=0; ji<*N_cdm_groups; ji++) { LOG_I(NR_PHY, "(CDM group %d) j = %d, koverline = %d, loverline = %d\n", ji, j[ji], koverline[ji], loverline[ji]); diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 4b0c056642..257ab5b2ab 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -340,7 +340,7 @@ uint8_t get_nr_prach_duration(uint8_t prach_format); void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms, int32_t **dataF, const int16_t amp, - nr_csi_rs_info_t *nr_csi_rs_info, + nr_csi_info_t *nr_csi_info, const nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *csi_params, const int slot, uint8_t *N_cdm_groups, diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 43b1ae8506..e6fd841129 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -177,7 +177,7 @@ bool is_csi_rs_in_symbol(const fapi_nr_dl_config_csirs_pdu_rel15_t csirs_config_ int nr_get_csi_rs_signal(const PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, - const nr_csi_rs_info_t *nr_csi_rs_info, + const nr_csi_info_t *nr_csi_info, const uint8_t N_cdm_groups, const uint8_t CDM_group_size, const uint8_t k_prime, @@ -219,7 +219,7 @@ int nr_get_csi_rs_signal(const PHY_VARS_NR_UE *ue, #ifdef NR_CSIRS_DEBUG int dataF_offset = proc->nr_slot_rx*ue->frame_parms.samples_per_slot_wCP; uint16_t port_tx = s+j_cdm[cdm_id]*CDM_group_size; - c16_t *tx_csi_rs_signal = (c16_t*)&nr_csi_rs_info->csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset]; + c16_t *tx_csi_rs_signal = (c16_t*)&nr_csi_info->csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset]; LOG_I(NR_PHY, "l,k (%2d,%4d) |\tport_tx %d (%4d,%4d)\tant_rx %d (%4d,%4d)\n", symb, k, @@ -258,7 +258,7 @@ uint32_t calc_power_csirs(const uint16_t *x, const fapi_nr_dl_config_csirs_pdu_r int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, - const nr_csi_rs_info_t *nr_csi_rs_info, + const nr_csi_info_t *nr_csi_info, const int32_t **csi_rs_generated_signal, const int32_t csi_rs_received_signal[][ue->frame_parms.samples_per_slot_wCP], const uint8_t N_cdm_groups, @@ -315,8 +315,8 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, c16_t *rx_csi_rs_signal = (c16_t*)&csi_rs_received_signal[ant_rx][symbol_offset]; c16_t *csi_rs_ls_estimated_channel16 = (c16_t*)&csi_rs_ls_estimated_channel[ant_rx][port_tx][0]; - int16_t csi_rs_ls_estimated_channel_re = (int16_t)(((int32_t)tx_csi_rs_signal[k].r*rx_csi_rs_signal[k].r + (int32_t)tx_csi_rs_signal[k].i*rx_csi_rs_signal[k].i)>>nr_csi_rs_info->csi_rs_generated_signal_bits); - int16_t csi_rs_ls_estimated_channel_im = (int16_t)(((int32_t)tx_csi_rs_signal[k].r*rx_csi_rs_signal[k].i - (int32_t)tx_csi_rs_signal[k].i*rx_csi_rs_signal[k].r)>>nr_csi_rs_info->csi_rs_generated_signal_bits); + int16_t csi_rs_ls_estimated_channel_re = (int16_t)(((int32_t)tx_csi_rs_signal[k].r*rx_csi_rs_signal[k].r + (int32_t)tx_csi_rs_signal[k].i*rx_csi_rs_signal[k].i)>>nr_csi_info->csi_rs_generated_signal_bits); + int16_t csi_rs_ls_estimated_channel_im = (int16_t)(((int32_t)tx_csi_rs_signal[k].r*rx_csi_rs_signal[k].i - (int32_t)tx_csi_rs_signal[k].i*rx_csi_rs_signal[k].r)>>nr_csi_info->csi_rs_generated_signal_bits); // This is not just the LS estimation for each (k,l), but also the sum of the different contributions // for the sake of optimizing the memory used. @@ -436,7 +436,7 @@ int nr_csi_rs_channel_estimation(const PHY_VARS_NR_UE *ue, int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue, const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, - const nr_csi_rs_info_t *nr_csi_rs_info, + const nr_csi_info_t *nr_csi_info, const uint8_t N_ports, int32_t csi_rs_estimated_channel_freq[][N_ports][ue->frame_parms.ofdm_symbol_size], const int16_t log2_maxh, @@ -568,7 +568,7 @@ int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue, int nr_csi_rs_pmi_estimation(const PHY_VARS_NR_UE *ue, const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, - const nr_csi_rs_info_t *nr_csi_rs_info, + const nr_csi_info_t *nr_csi_info, const uint8_t N_ports, const int32_t csi_rs_estimated_channel_freq[][N_ports][ue->frame_parms.ofdm_symbol_size], const uint32_t interference_plus_noise_power, @@ -641,7 +641,7 @@ int nr_csi_rs_pmi_estimation(const PHY_VARS_NR_UE *ue, } } - // We should perform >>nr_csi_rs_info->log2_re here for all terms, but since sum2_re and sum2_im can be high values, + // We should perform >>nr_csi_info->log2_re here for all terms, but since sum2_re and sum2_im can be high values, // we performed this above. for(int p = 0; p<4; p++) { int32_t power_re = sum2_re[p] - (sum_re[p]>>log2_re)*(sum_re[p]>>log2_re); @@ -796,8 +796,8 @@ int nr_ue_csi_im_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t LOG_I(NR_PHY, "csiim_config_pdu->l_csiim = %i.%i.%i.%i\n", csiim_config_pdu->l_csiim[0], csiim_config_pdu->l_csiim[1], csiim_config_pdu->l_csiim[2], csiim_config_pdu->l_csiim[3]); #endif - nr_csi_im_power_estimation(ue, proc, csiim_config_pdu, &ue->nr_csi_im_info->interference_plus_noise_power); - ue->nr_csi_im_info->meas_computed = true; + nr_csi_im_power_estimation(ue, proc, csiim_config_pdu, &ue->nr_csi_info->interference_plus_noise_power); + ue->nr_csi_info->csi_im_meas_computed = true; return 0; } @@ -847,9 +847,9 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t uint8_t i2[1]; nr_generate_csi_rs(frame_parms, - ue->nr_csi_rs_info->csi_rs_generated_signal, + ue->nr_csi_info->csi_rs_generated_signal, AMP, - ue->nr_csi_rs_info, + ue->nr_csi_info, (nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *) csirs_config_pdu, proc->nr_slot_rx, &N_cdm_groups, @@ -867,7 +867,7 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t nr_get_csi_rs_signal(ue, proc, csirs_config_pdu, - ue->nr_csi_rs_info, + ue->nr_csi_info, N_cdm_groups, CDM_group_size, k_prime, @@ -880,8 +880,8 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t nr_csi_rs_channel_estimation(ue, proc, csirs_config_pdu, - ue->nr_csi_rs_info, - (const int32_t **) ue->nr_csi_rs_info->csi_rs_generated_signal, + ue->nr_csi_info, + (const int32_t **) ue->nr_csi_info->csi_rs_generated_signal, csi_rs_received_signal, N_cdm_groups, CDM_group_size, @@ -899,7 +899,7 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t nr_csi_rs_ri_estimation(ue, csirs_config_pdu, - ue->nr_csi_rs_info, + ue->nr_csi_info, N_ports, csi_rs_estimated_channel_freq, log2_maxh, @@ -907,10 +907,10 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t nr_csi_rs_pmi_estimation(ue, csirs_config_pdu, - ue->nr_csi_rs_info, + ue->nr_csi_info, N_ports, csi_rs_estimated_channel_freq, - ue->nr_csi_im_info->meas_computed ? ue->nr_csi_im_info->interference_plus_noise_power : noise_power, + ue->nr_csi_info->csi_im_meas_computed ? ue->nr_csi_info->interference_plus_noise_power : noise_power, rank_indicator, log2_re, i1, diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c index 5f3af5bb39..ea7bde5377 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c @@ -362,7 +362,7 @@ int nr_initial_sync(UE_nr_rxtx_proc_t *proc, nr_gold_pdsch(ue, i, ue->scramblingID_dlsch[i]); } - nr_init_csi_rs(fp, ue->nr_csi_rs_info->nr_gold_csi_rs, fp->Nid_cell); + nr_init_csi_rs(fp, ue->nr_csi_info->nr_gold_csi_rs, fp->Nid_cell); // initialize the pusch dmrs for (int i=0; iactive == 1) { LOG_D(PHY, "CSI-RS generation started in frame %d.%d\n",frame,slot); nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *csi_params = &csirs->csirs_pdu.csi_rs_pdu_rel15; - nr_generate_csi_rs(&gNB->frame_parms, gNB->common_vars.txdataF, AMP, gNB->nr_csi_rs_info, csi_params, slot, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + nr_generate_csi_rs(&gNB->frame_parms, gNB->common_vars.txdataF, AMP, gNB->nr_csi_info, csi_params, slot, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); csirs->active = 0; } } From 03bea3150a8927053a9ab021b020163d447fce76 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 7 Jul 2022 20:16:54 +0100 Subject: [PATCH 199/267] Fix memory leak --- openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index e6fd841129..753040ecc6 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -928,14 +928,13 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t csirs_measurements.i1 = *i1; csirs_measurements.i2 = *i2; csirs_measurements.cqi = cqi; - nr_downlink_indication_t *dl_indication = calloc(sizeof(*dl_indication),1); + nr_downlink_indication_t dl_indication; fapi_nr_rx_indication_t *rx_ind = calloc(sizeof(*rx_ind),1); - nr_fill_dl_indication(dl_indication, NULL, rx_ind, proc, ue, gNB_id, NULL); + nr_fill_dl_indication(&dl_indication, NULL, rx_ind, proc, ue, gNB_id, NULL); nr_fill_rx_indication(rx_ind, FAPI_NR_CSIRS_IND, gNB_id, ue, NULL, NULL, 1, proc, (void *)&csirs_measurements); if (ue->if_inst && ue->if_inst->dl_indication) { - ue->if_inst->dl_indication(dl_indication, NULL); + ue->if_inst->dl_indication(&dl_indication, NULL); } else { - free(dl_indication); free(rx_ind); } From a574c47e9e0eff418d2e703527873c2f6d6e4dc2 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Fri, 8 Jul 2022 10:54:37 +0100 Subject: [PATCH 200/267] Fix memory leak --- openair1/PHY/INIT/nr_init_ue.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 0efdb1e8e1..b901a038bb 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -483,6 +483,7 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) for (int i=0; inr_csi_info->csi_rs_generated_signal[i]); } + free_and_zero(ue->nr_csi_info->csi_rs_generated_signal); for (int slot=0; slotslots_per_frame; slot++) { for (int symb=0; symbsymbols_per_slot; symb++) { free_and_zero(ue->nr_csi_info->nr_gold_csi_rs[slot][symb]); From b0bcff0da2a20e89903f54a71778c2e32502ae33 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Fri, 8 Jul 2022 11:17:28 +0100 Subject: [PATCH 201/267] Fix build warnings in phy simulators --- openair1/SIMULATION/NR_PHY/dlschsim.c | 22 +++++++++++----------- openair1/SIMULATION/NR_PHY/dlsim.c | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c index e81871b146..39cd540795 100644 --- a/openair1/SIMULATION/NR_PHY/dlschsim.c +++ b/openair1/SIMULATION/NR_PHY/dlschsim.c @@ -114,16 +114,16 @@ int main(int argc, char **argv) //int run_initial_sync=0; int loglvl = OAILOG_WARNING; uint8_t dlsch_threads = 0; - float target_error_rate = 0.01; - uint64_t SSB_positions=0x01; - uint16_t nb_symb_sch = 12; - uint16_t nb_rb = 50; - uint8_t Imcs = 9; - uint8_t mcs_table = 0; - double DS_TDL = .03; - cpuf = get_cpu_freq_GHz(); - char gNBthreads[128]="n"; - int Tbslbrm = 950984; + float target_error_rate = 0.01; + uint64_t SSB_positions=0x01; + uint16_t nb_symb_sch = 12; + uint16_t nb_rb = 50; + uint8_t Imcs = 9; + uint8_t mcs_table = 0; + double DS_TDL = .03; + cpuf = get_cpu_freq_GHz(); + char gNBthreads[128]="n"; + int Tbslbrm = 950984; if (load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY) == 0) { exit_fun("[NR_DLSCHSIM] Error, configuration module init failed\n"); @@ -299,7 +299,7 @@ int main(int argc, char **argv) break; case 'X': - strncpy(gNBthreads, optarg, sizeof(gNBthreads)); + strncpy(gNBthreads, optarg, sizeof(gNBthreads)-1); gNBthreads[sizeof(gNBthreads)-1]=0; break; diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 78b253ca2a..1e81cf691a 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -670,7 +670,7 @@ int main(int argc, char **argv) break; case 'X': - strncpy(gNBthreads, optarg, sizeof(gNBthreads)); + strncpy(gNBthreads, optarg, sizeof(gNBthreads)-1); gNBthreads[sizeof(gNBthreads)-1]=0; break; From f1e3f7fb1f0fc8acc69d096987c2f6324f362e50 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 7 Jul 2022 17:59:33 +0200 Subject: [PATCH 202/267] CI: Abort pipeline if DeployObject fails --- ci-scripts/cls_containerize.py | 2 ++ ci-scripts/main.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 259db7bffe..49aeeeed55 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -567,8 +567,10 @@ class Containerize(): if status: HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) else: + self.exitStatus = 1 HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ALL_PROCESSES_OK) + def UndeployObject(self, HTML, RAN): if self.eNB_serverId[self.eNB_instance] == '0': lIpAddr = self.eNBIPAddress diff --git a/ci-scripts/main.py b/ci-scripts/main.py index adef885942..448f2636e3 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -919,6 +919,8 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re CONTAINERS.Copy_Image_to_Test_Server(HTML) elif action == 'Deploy_Object': CONTAINERS.DeployObject(HTML, EPC) + if CONTAINERS.exitStatus==1: + RAN.prematureExit = True elif action == 'Undeploy_Object': CONTAINERS.UndeployObject(HTML, RAN) elif action == 'Cppcheck_Analysis': From 5928d571e7c82040bf8e04f8fc9f1f29a9db7014 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 8 Jul 2022 11:14:04 +0200 Subject: [PATCH 203/267] CI: Fix log message typo in UndeployObject() --- ci-scripts/cls_containerize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 49aeeeed55..6abf444a0d 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -590,7 +590,7 @@ class Containerize(): if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') - logging.debug('\u001B[1m Deploying OAI Object on server: ' + lIpAddr + '\u001B[0m') + logging.debug('\u001B[1m Undeploying OAI Object from server: ' + lIpAddr + '\u001B[0m') mySSH = SSH.SSHConnection() mySSH.open(lIpAddr, lUserName, lPassWord) mySSH.command('cd ' + lSourcePath + '/' + self.yamlPath[self.eNB_instance], '\$', 5) From 87d1a53ca39585246131a5e6af32929e09b89f7b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 14 Jul 2022 17:08:59 +0200 Subject: [PATCH 204/267] CI: Allow publickey authentication in SSHConnection For pubkey, checks that we are on the right machine --- ci-scripts/sshconnection.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py index dca3daa817..d9ab3c5011 100644 --- a/ci-scripts/sshconnection.py +++ b/ci-scripts/sshconnection.py @@ -60,7 +60,7 @@ class SSHConnection(): count = 0 connect_status = False while count < 4: - self.ssh = pexpect.spawn('ssh -o PubkeyAuthentication=no {}@{}'.format(username,ipaddress)) + self.ssh = pexpect.spawn('ssh -o PubkeyAuthentication=yes {}@{}'.format(username,ipaddress)) # Longer timeout at connection due to asterix slowness self.ssh.timeout = 25 self.sshresponse = self.ssh.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', 'Last login', pexpect.EOF, pexpect.TIMEOUT]) @@ -85,13 +85,15 @@ class SSHConnection(): logging.debug('self.sshresponse = ' + str(self.sshresponse)) elif self.sshresponse == 2: # Checking if we are really on the remote client defined by its IP address - self.command('stdbuf -o0 ifconfig | egrep --color=never "inet addr:|inet "', prompt, 5) - result = re.search(str(ipaddress), str(self.ssh.before)) - if result is None: - self.close() - else: + self.ssh.sendline('stdbuf -o0 ifconfig | egrep --color=never "inet addr:|inet "') + self.sshresponse = self.ssh.expect([ipaddress, pexpect.EOF, pexpect.TIMEOUT]) + if self.sshresponse == 0: count = 10 connect_status = True + # this expect seems to be necessary to advance the read buffer until the prompt, or getBefore() will not return the last command + self.sshresponse = self.ssh.expect([prompt]) + else: + logging.error('logged in to ' + ipaddress + ' without password but IP is not found via ifconfig on remote host, aborting') else: # debug output logging.debug(str(self.ssh.before)) From 4b50e4b1f684f958f3bdcd604a4a10de64fa94db Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 14 Jul 2022 22:18:01 +0200 Subject: [PATCH 205/267] CI: decode in getBefore() --- ci-scripts/sshconnection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py index d9ab3c5011..52d799ebe3 100644 --- a/ci-scripts/sshconnection.py +++ b/ci-scripts/sshconnection.py @@ -274,4 +274,4 @@ class SSHConnection(): sys.exit('SCP failed') def getBefore(self): - return str(self.ssh.before) + return self.ssh.before.decode('utf-8') From b308cbe1019002a1f51dedde0c1cb84fd62a62f2 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 7 Jul 2022 09:07:58 +0200 Subject: [PATCH 206/267] Add RAN-SA-B200-Module-SABOX-Container test --- .../gnb.sa.band78.fr1.106PRB.usrpb210.conf | 344 ++++++++++++++++++ .../xml_files/container_sa_b200_quectel.xml | 169 +++++++++ .../xml_files/container_sa_b200_terminate.xml | 42 +++ ci-scripts/xml_files/fr1_5gc_closure.xml | 37 ++ ci-scripts/xml_files/fr1_5gc_start.xml | 38 ++ .../yaml_files/sa_b200_gnb/docker-compose.yml | 44 +++ doc/TESTBenches.md | 5 +- docker/scripts/generateTemplate.py | 1 + docker/scripts/gnb_entrypoint.sh | 1 + docker/scripts/gnb_parameters.yaml | 30 ++ 10 files changed, 710 insertions(+), 1 deletion(-) create mode 100644 ci-scripts/conf_files/gnb.sa.band78.fr1.106PRB.usrpb210.conf create mode 100644 ci-scripts/xml_files/container_sa_b200_quectel.xml create mode 100644 ci-scripts/xml_files/container_sa_b200_terminate.xml create mode 100644 ci-scripts/xml_files/fr1_5gc_closure.xml create mode 100644 ci-scripts/xml_files/fr1_5gc_start.xml create mode 100644 ci-scripts/yaml_files/sa_b200_gnb/docker-compose.yml diff --git a/ci-scripts/conf_files/gnb.sa.band78.fr1.106PRB.usrpb210.conf b/ci-scripts/conf_files/gnb.sa.band78.fr1.106PRB.usrpb210.conf new file mode 100644 index 0000000000..2a6053ab46 --- /dev/null +++ b/ci-scripts/conf_files/gnb.sa.band78.fr1.106PRB.usrpb210.conf @@ -0,0 +1,344 @@ +Active_gNBs = ( "gNB-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_name = "gNB-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ + mcc = 222; + mnc = 01; + mnc_length = 2; + snssaiList = ( + { + sst = 1; + #sd = 0x1; // 0 false, else true + } + ); + + }); + + nr_cellid = 12345678L; + + ////////// Physical parameters: + + min_rxtxtime = 2; + do_CSIRS = 1; + do_SRS = 1; + + pdcch_ConfigSIB1 = ( + { + controlResourceSetZero = 12; + searchSpaceZero = 0; + } + ); + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP) + absoluteFrequencySSB = 641280; + dl_frequencyBand = 78; + # this is 3600 MHz + dl_absoluteFrequencyPointA = 640008; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 106; + #initialDownlinkBWP + #genericParameters + # this is RBstart=27,L=48 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952 +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 106; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 28875; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 13; + preambleReceivedTargetPower = -96; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 4; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; +# ssb_PositionsInBurs_BitmapPR +# 1=short, 2=medium, 3=long + ssb_PositionsInBurst_PR = 2; + ssb_PositionsInBurst_Bitmap = 1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = -25; + } + + ); + +# Dedicated Serving Cell Configuration +servingCellConfigDedicated = ({ + # BWP-Downlink + # BWP 1 Configuration + dl_bwp-Id_1 = 1; + dl_bwp1_locationAndBandwidth = 28875; // RBstart=0, L=106 (40 MHz BW) + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_bwp1_subcarrierSpacing = 1; + + # BWP 2 Configuration + dl_bwp-Id_2 = 2; + dl_bwp2_locationAndBandwidth = 13750; // RBstart=0, L=51 (20 MHz BW) + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_bwp2_subcarrierSpacing = 1; + + # BWP 3 Configuration + dl_bwp-Id_3 = 3; + dl_bwp3_locationAndBandwidth = 6325; // RBstart=0, L=24 (10 MHz BW) + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_bwp3_subcarrierSpacing = 1; + + firstActiveDownlinkBWP-Id = 1; #BWP-Id + defaultDownlinkBWP-Id = 1; #BWP-Id + + # bwp-InactivityTimer ENUMERATED {ms2, ms3, ms4, ms5, ms6, ms8, ms10, ms20, ms30, + # ms40,ms50, ms60, ms80,ms100, ms200,ms300, ms500, + # ms750, ms1280, ms1920, ms2560, spare10, spare9, spare8, + # spare7, spare6, spare5, spare4, spare3, spare2, spare1 } + + # UplinkConfig + # BWP-Uplink + # BWP 1 Configuration + ul_bwp-Id_1 = 1; + ul_bwp1_locationAndBandwidth = 28875; // RBstart=0, L=106 (40 MHz BW) + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_bwp1_subcarrierSpacing = 1; + + # BWP 2 Configuration + ul_bwp-Id_2 = 2; + ul_bwp2_locationAndBandwidth = 13750; // RBstart=0, L=51 (20 MHz BW) + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_bwp2_subcarrierSpacing = 1; + + # BWP 3 Configuration + ul_bwp-Id_3 = 3; + ul_bwp3_locationAndBandwidth = 6325; // RBstart=0, L=24 (10 MHz BW) + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_bwp3_subcarrierSpacing = 1; + + firstActiveUplinkBWP-Id = 1; #BWP-Id + } +); + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// AMF parameters: + amf_ip_address = ( { ipv4 = "172.21.16.136"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + + NETWORK_INTERFACES : + { + GNB_INTERFACE_NAME_FOR_NG_AMF = "demo-oai"; + GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.137/24"; + GNB_INTERFACE_NAME_FOR_NGU = "demo-oai"; + GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.137/24"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + } +); + +MACRLCs = ( +{ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 200; + pucch_TargetSNRx10 = 200; + ulsch_max_frame_inactivity = 0; +} +); + +L1s = ( +{ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 120; + pucch0_dtx_threshold = 100; + ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 +} +); + +RUs = ( +{ + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 10; + att_rx = 10; + bands = [78]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 114; + eNB_instances = [0]; + #beamforming 1x4 matrix: + bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000]; + clock_src = "internal"; +} +); + +THREAD_STRUCT = ( +{ + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_SINGLE_THREAD"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; +} +); + +rfsimulator : +{ + serveraddr = "server"; + serverport = "4043"; + options = (); #("saviq"); or/and "chanmod" + modelname = "AWGN"; + IQfile = "/tmp/rfsimulator.iqs"; +}; + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + +log_config : +{ + global_log_level ="info"; + hw_log_level ="info"; + phy_log_level ="info"; + mac_log_level ="info"; + rlc_log_level ="info"; + pdcp_log_level ="info"; + rrc_log_level ="info"; + ngap_log_level ="debug"; + f1ap_log_level ="debug"; +}; + diff --git a/ci-scripts/xml_files/container_sa_b200_quectel.xml b/ci-scripts/xml_files/container_sa_b200_quectel.xml new file mode 100644 index 0000000000..971fd1deed --- /dev/null +++ b/ci-scripts/xml_files/container_sa_b200_quectel.xml @@ -0,0 +1,169 @@ + + + TEST-SA-FR1-B200 + SA SanityCheck with QUECTEL + tasks + 1 + + 000001 + 010002 + 030000 + 030101 + 000001 + 010000 + 000001 + 050000 + 050001 + 010002 + 000001 + 030201 + + + + + + Initialize_UE + Initialize Quectel + idefix + + + + + Terminate_UE + Terminate Quectel + idefix + + + + Copy_Image_to_Test + Copy gNB image to test server + oai-gnb + 1 + 0 + + + + Deploy_Object + Deploy gNB (TDD/Band78/40MHz/B200) in a container + ci-scripts/yaml_files/sa_b200_gnb + 0 + 0 + + + + IdleSleep + Sleep + 5 + + + + IdleSleep + Sleep + 20 + + + + + Ping + Ping: 20pings in 20sec + idefix + -c 20 + 1 + 15 + + + + Ping + Ping: 100pings in 20sec + idefix + -c 100 -i 0.2 + 1 + 15 + + + + Ping + Ping: 20pings in 20sec + idefix + -c 20 + 1 + 15 + + + + Ping + Ping: 100pings in 20sec + idefix + -c 100 -i 0.2 + 1 + 15 + + + + Iperf + iperf (DL/125Mbps/UDP)(60 sec)(single-ue profile) + -u -b 125M -t 60 -i 1 -fm + DL + idefix + 25 + 80 + single-ue + + + + Iperf + iperf (UL/8Mbps/UDP)(60 sec)(single-ue profile) + -u -b 8M -t 60 -i 1 -fm + UL + idefix + 1 + 95 + single-ue + + + + Iperf + iperf (BIDIR TCP)(10 sec)(single-ue profile) + -t 10 --bidir + BIDIR + idefix + single-ue + + + + Undeploy_Object + Undeploy gNB + ci-scripts/yaml_files/sa_b200_gnb + 0 + 0 + + + + diff --git a/ci-scripts/xml_files/container_sa_b200_terminate.xml b/ci-scripts/xml_files/container_sa_b200_terminate.xml new file mode 100644 index 0000000000..5a2b6bd454 --- /dev/null +++ b/ci-scripts/xml_files/container_sa_b200_terminate.xml @@ -0,0 +1,42 @@ + + + TEST-SA-FR1-B200-terminate + SA tear-down in case of problem + tasks + 1 + + 030201 + + + + + Undeploy_Object + Undeploy gNB + ci-scripts/yaml_files/sa_b200_gnb + 1 + 1 + sa-test + + + diff --git a/ci-scripts/xml_files/fr1_5gc_closure.xml b/ci-scripts/xml_files/fr1_5gc_closure.xml new file mode 100644 index 0000000000..e5e57fa694 --- /dev/null +++ b/ci-scripts/xml_files/fr1_5gc_closure.xml @@ -0,0 +1,37 @@ + + + 5gc-closure + 5GC-Closure + log-out + +060000 + + + + + Terminate_5GCN + Terminate 5GC + + + diff --git a/ci-scripts/xml_files/fr1_5gc_start.xml b/ci-scripts/xml_files/fr1_5gc_start.xml new file mode 100644 index 0000000000..8758b761cd --- /dev/null +++ b/ci-scripts/xml_files/fr1_5gc_start.xml @@ -0,0 +1,38 @@ + + + 5gc-start-tab + 5GC-Start + log-in + + 000100 + + + + + + Initialize_5GCN + Initialize 5GC + + + diff --git a/ci-scripts/yaml_files/sa_b200_gnb/docker-compose.yml b/ci-scripts/yaml_files/sa_b200_gnb/docker-compose.yml new file mode 100644 index 0000000000..9ea52c1247 --- /dev/null +++ b/ci-scripts/yaml_files/sa_b200_gnb/docker-compose.yml @@ -0,0 +1,44 @@ +version: '3.8' + +services: + gnb_mono_tdd: + image: oai-gnb:latest + privileged: true + container_name: sa-b200-gnb + environment: + USE_SA_TDD_MONO_B2XX: 'yes' + USE_B2XX: 'yes' + GNB_NAME: gNB-in-docker + MCC: '222' + MNC: '01' + MNC_LENGTH: 2 + TAC: 1 + NSSAI_SST: 1 + NSSAI_SD0: 1 + AMF_IP_ADDRESS: 172.21.16.136 + GNB_NGA_IF_NAME: eth0 + GNB_NGA_IP_ADDRESS: 192.168.68.194 + GNB_NGU_IF_NAME: eth0 + GNB_NGU_IP_ADDRESS: 192.168.68.194 + USE_ADDITIONAL_OPTIONS: --sa -E -q --RUs.[0].sdr_addrs serial=30C51D4 --continuous-tx --log_config.global_log_options level,nocolor,time,line_num,function + volumes: + - /dev:/dev + networks: + public_net: + ipv4_address: 192.168.68.194 + #entrypoint: /bin/bash -c "sleep infinity" + healthcheck: + # pgrep does NOT work + test: /bin/bash -c "ps aux | grep -v grep | grep -c softmodem" + interval: 10s + timeout: 5s + retries: 5 + +networks: + public_net: + name: sa-b200-gnb-net + ipam: + config: + - subnet: 192.168.68.192/26 + driver_opts: + com.docker.network.bridge.name: "sa-gnb-net" diff --git a/doc/TESTBenches.md b/doc/TESTBenches.md index 547fd5a23b..24e649ccc0 100644 --- a/doc/TESTBenches.md +++ b/doc/TESTBenches.md @@ -89,7 +89,10 @@ Webhook currently only ping - [RAN-NSA-B200-Module-LTEBOX-Container](https://jenkins-oai.eurecom.fr/job/RAN-NSA-B200-Module-LTEBOX-Container/) - obelix + B200, nepes + B200, idefix + Quectel, porcepix w/ ltebox - - basic NSA test, known to be instable + - basic NSA test +- [RAN-SA-B200-Module-SABOX-Container](https://jenkins-oai.eurecom.fr/job/RAN-SA-B200-Module-SABOX-Container/) + - obelix + B200, nepes + B200, idefix + Quectel, porcepix w/ sabox + - basic SA test (40 MHz TDD) - [RAN-PhySim-Cluster](https://jenkins-oai.eurecom.fr/job/RAN-PhySim-Cluster/) - asterix (`Asterix-OC-oaicicd-session` resource), tests in OpenShift Cluster - unitary simulators (`nr_dlsim`, etc.) diff --git a/docker/scripts/generateTemplate.py b/docker/scripts/generateTemplate.py index 850bb535a5..ec8f32ec6e 100644 --- a/docker/scripts/generateTemplate.py +++ b/docker/scripts/generateTemplate.py @@ -60,6 +60,7 @@ def main(): "rcc.band40.tm1.25PRB": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}', "gnb.band78.tm1.fr1.106PRB.usrpb210.conf": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}', "gnb.band78.sa.fr1.106PRB.usrpn310.conf": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}', + "gnb.sa.band78.fr1.106PRB.usrpb210.conf": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}', "gnb.sa.band66.fr1.106PRB.usrpn300.conf": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}', "gNB_SA_CU.conf": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}', "gNB_SA_DU.conf": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}', diff --git a/docker/scripts/gnb_entrypoint.sh b/docker/scripts/gnb_entrypoint.sh index dd6256609c..ac0e0d4c88 100755 --- a/docker/scripts/gnb_entrypoint.sh +++ b/docker/scripts/gnb_entrypoint.sh @@ -10,6 +10,7 @@ THREAD_PARALLEL_CONFIG=${THREAD_PARALLEL_CONFIG:-PARALLEL_SINGLE_THREAD} if [[ -v USE_NSA_TDD_MONO ]]; then cp $PREFIX/etc/gnb.nsa.tdd.conf $PREFIX/etc/gnb.conf; fi if [[ -v USE_SA_TDD_MONO ]]; then cp $PREFIX/etc/gnb.sa.tdd.conf $PREFIX/etc/gnb.conf; fi +if [[ -v USE_SA_TDD_MONO_B2XX ]]; then cp $PREFIX/etc/gnb.sa.tdd.b2xx.conf $PREFIX/etc/gnb.conf; fi if [[ -v USE_SA_FDD_MONO ]]; then cp $PREFIX/etc/gnb.sa.fdd.conf $PREFIX/etc/gnb.conf; fi if [[ -v USE_SA_CU ]]; then cp $PREFIX/etc/gnb.sa.cu.conf $PREFIX/etc/gnb.conf; fi if [[ -v USE_SA_TDD_CU ]]; then cp $PREFIX/etc/gnb.sa.du.tdd.conf $PREFIX/etc/gnb.conf; fi diff --git a/docker/scripts/gnb_parameters.yaml b/docker/scripts/gnb_parameters.yaml index d5942f2c9b..420559ff3f 100644 --- a/docker/scripts/gnb_parameters.yaml +++ b/docker/scripts/gnb_parameters.yaml @@ -94,6 +94,36 @@ - key: parallel_config env: "@THREAD_PARALLEL_CONFIG@" + - filePrefix: gnb.sa.band78.fr1.106PRB.usrpb210.conf + outputfilename: "gnb.sa.tdd.b2xx.conf" + config: + - key: Active_gNBs + env: "@GNB_NAME@" + - key: gNB_name + env: "@GNB_NAME@" + - key: mcc + env: "@MCC@" + - key: mnc + env: "@MNC@" + - key: mnc_length + env: "@MNC_LENGTH@" + - key: tracking_area_code + env: "@TAC@" + - key: sst + env: "@NSSAI_SST@" + - key: ipv4 + env: "@AMF_IP_ADDRESS@" + - key: GNB_INTERFACE_NAME_FOR_NG_AMF + env: "@GNB_NGA_IF_NAME@" + - key: GNB_IPV4_ADDRESS_FOR_NG_AMF + env: "@GNB_NGA_IP_ADDRESS@" + - key: GNB_INTERFACE_NAME_FOR_NGU + env: "@GNB_NGU_IF_NAME@" + - key: GNB_IPV4_ADDRESS_FOR_NGU + env: "@GNB_NGU_IP_ADDRESS@" + - key: parallel_config + env: "@THREAD_PARALLEL_CONFIG@" + - filePrefix: gnb.sa.band66.fr1.106PRB.usrpn300.conf outputfilename: "gnb.sa.fdd.conf" config: From 0c4aa33939cf0b6cb9142a37019b8fc58bf97cde Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 14 Jul 2022 23:57:52 +0200 Subject: [PATCH 207/267] Trigger SA-B200 test from RAN-Container-Parent --- ci-scripts/Jenkinsfile-GitLab-Container | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ci-scripts/Jenkinsfile-GitLab-Container b/ci-scripts/Jenkinsfile-GitLab-Container index c22e6fabec..b37c9d4f4b 100644 --- a/ci-scripts/Jenkinsfile-GitLab-Container +++ b/ci-scripts/Jenkinsfile-GitLab-Container @@ -278,6 +278,26 @@ pipeline { } } } + stage ("SA B200 Sanity Check") { + when { expression {doMandatoryTests} } + steps { + script { + triggerSlaveJob ('RAN-SA-B200-Module-SABOX-Container', 'Test-SA-B200') + } + } + post { + always { + script { + finalizeSlaveJob('RAN-SA-B200-Module-SABOX-Container') + } + } + failure { + script { + currentBuild.result = 'FAILURE' + } + } + } + } stage ("Test OAI NR UE - OAI gNB - TDD - Band 78 - N300") { when { expression {doMandatoryTests} } steps { From 63daf5793b414a92fb87e6f77845fb9c68c22752 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 15 Jul 2022 11:01:26 +0200 Subject: [PATCH 208/267] Remove useless SA test sleep --- ci-scripts/xml_files/container_sa_b200_quectel.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/ci-scripts/xml_files/container_sa_b200_quectel.xml b/ci-scripts/xml_files/container_sa_b200_quectel.xml index 971fd1deed..7f0475629d 100644 --- a/ci-scripts/xml_files/container_sa_b200_quectel.xml +++ b/ci-scripts/xml_files/container_sa_b200_quectel.xml @@ -26,7 +26,6 @@ tasks 1 - 000001 010002 030000 030101 From 52168e5201c9b93a2632ec6c40f8de210491e351 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 15 Jul 2022 11:00:18 +0200 Subject: [PATCH 209/267] Shut off quectel before running SA tests --- ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml | 1 + ci-scripts/xml_files/fr1_nsa_2x2_quectel_attach_detach.xml | 1 + ci-scripts/xml_files/fr1_nsa_quectel.xml | 1 + ci-scripts/xml_files/fr1_sa_quectel.xml | 1 + ci-scripts/xml_files/fr1_sa_quectel_162prb.xml | 1 + ci-scripts/xml_files/fr1_sa_quectel_stages.xml | 1 + ci-scripts/xml_files/lte_2x2_tm1_quectel.xml | 1 + ci-scripts/xml_files/lte_2x2_tm2_quectel.xml | 1 + 8 files changed, 8 insertions(+) diff --git a/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml b/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml index 2ef2b7d7ce..459a16c323 100644 --- a/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml +++ b/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml @@ -26,6 +26,7 @@ tasks 1 + 010002 030000 040000 000002 diff --git a/ci-scripts/xml_files/fr1_nsa_2x2_quectel_attach_detach.xml b/ci-scripts/xml_files/fr1_nsa_2x2_quectel_attach_detach.xml index 335fe873a1..c8e0659330 100644 --- a/ci-scripts/xml_files/fr1_nsa_2x2_quectel_attach_detach.xml +++ b/ci-scripts/xml_files/fr1_nsa_2x2_quectel_attach_detach.xml @@ -26,6 +26,7 @@ tasks 1 + 010002 031000 041000 000002 diff --git a/ci-scripts/xml_files/fr1_nsa_quectel.xml b/ci-scripts/xml_files/fr1_nsa_quectel.xml index a7fd0fc0d7..c72c61c0a2 100644 --- a/ci-scripts/xml_files/fr1_nsa_quectel.xml +++ b/ci-scripts/xml_files/fr1_nsa_quectel.xml @@ -26,6 +26,7 @@ tasks 1 + 010002 030000 040000 000002 diff --git a/ci-scripts/xml_files/fr1_sa_quectel.xml b/ci-scripts/xml_files/fr1_sa_quectel.xml index 2b215479c2..fd983d8835 100644 --- a/ci-scripts/xml_files/fr1_sa_quectel.xml +++ b/ci-scripts/xml_files/fr1_sa_quectel.xml @@ -26,6 +26,7 @@ tasks 1 + 010002 040000 000002 010000 diff --git a/ci-scripts/xml_files/fr1_sa_quectel_162prb.xml b/ci-scripts/xml_files/fr1_sa_quectel_162prb.xml index 23eaccfcfd..f426bd6035 100644 --- a/ci-scripts/xml_files/fr1_sa_quectel_162prb.xml +++ b/ci-scripts/xml_files/fr1_sa_quectel_162prb.xml @@ -26,6 +26,7 @@ tasks 1 + 010002 042000 000002 010000 diff --git a/ci-scripts/xml_files/fr1_sa_quectel_stages.xml b/ci-scripts/xml_files/fr1_sa_quectel_stages.xml index 603f3f919b..48a9b60e7d 100644 --- a/ci-scripts/xml_files/fr1_sa_quectel_stages.xml +++ b/ci-scripts/xml_files/fr1_sa_quectel_stages.xml @@ -26,6 +26,7 @@ tasks 1 + 011002 041000 000002 011000 diff --git a/ci-scripts/xml_files/lte_2x2_tm1_quectel.xml b/ci-scripts/xml_files/lte_2x2_tm1_quectel.xml index 0d18a52839..b6388eede2 100644 --- a/ci-scripts/xml_files/lte_2x2_tm1_quectel.xml +++ b/ci-scripts/xml_files/lte_2x2_tm1_quectel.xml @@ -26,6 +26,7 @@ tasks 1 + 010002 030000 000002 010000 diff --git a/ci-scripts/xml_files/lte_2x2_tm2_quectel.xml b/ci-scripts/xml_files/lte_2x2_tm2_quectel.xml index f84691ab48..99c8f75e06 100644 --- a/ci-scripts/xml_files/lte_2x2_tm2_quectel.xml +++ b/ci-scripts/xml_files/lte_2x2_tm2_quectel.xml @@ -26,6 +26,7 @@ tasks 1 + 010002 030001 000002 010000 From 0700d5d078297494331c0ee112c658a66e67af8b Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Tue, 14 Jun 2022 18:35:40 +0100 Subject: [PATCH 210/267] Add 5G SA end-to-end, step-by-step, tutorials for OAI CN5G, OAI gNB and COTS UE --- doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md | 14 ++- doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md | 14 ++- .../docker-compose-basic-nrf.yaml | 96 ++++++++++++++----- doc/tutorial_resources/oai_db.sql | 22 ++++- 4 files changed, 107 insertions(+), 39 deletions(-) diff --git a/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md b/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md index 1110a5bc6c..da013515da 100644 --- a/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md +++ b/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md @@ -86,6 +86,7 @@ cd ~/oai-cn5g-fed git checkout master ./scripts/syncComponents.sh --nrf-branch develop --amf-branch develop --smf-branch develop --spgwu-tiny-branch develop --ausf-branch develop --udm-branch develop --udr-branch develop --upf-vpp-branch develop --nssf-branch develop +# Pull docker images docker pull oaisoftwarealliance/oai-amf:develop docker pull oaisoftwarealliance/oai-nrf:develop docker pull oaisoftwarealliance/oai-smf:develop @@ -95,7 +96,9 @@ docker pull oaisoftwarealliance/oai-ausf:develop docker pull oaisoftwarealliance/oai-upf-vpp:develop docker pull oaisoftwarealliance/oai-spgwu-tiny:develop docker pull oaisoftwarealliance/oai-nssf:develop +docker pull oaisoftwarealliance/trf-gen-cn5g:latest +# Tag docker images docker image tag oaisoftwarealliance/oai-amf:develop oai-amf:develop docker image tag oaisoftwarealliance/oai-nrf:develop oai-nrf:develop docker image tag oaisoftwarealliance/oai-smf:develop oai-smf:develop @@ -105,16 +108,17 @@ docker image tag oaisoftwarealliance/oai-ausf:develop oai-ausf:develop docker image tag oaisoftwarealliance/oai-upf-vpp:develop oai-upf-vpp:develop docker image tag oaisoftwarealliance/oai-spgwu-tiny:develop oai-spgwu-tiny:develop docker image tag oaisoftwarealliance/oai-nssf:develop oai-nssf:develop +docker image tag oaisoftwarealliance/trf-gen-cn5g:latest trf-gen-cn5g:latest ``` ## 2.3 OAI CN5G Configuration files -Download and copy the configuration files to ~/oai-cn5g-fed/docker-compose: -- [docker-compose-basic-nrf.yaml](tutorial_resources/docker-compose-basic-nrf.yaml) -- [oai_db.sql](tutorial_resources/oai_db.sql) +Download and copy configuration files: +- Copy [docker-compose-basic-nrf.yaml](tutorial_resources/docker-compose-basic-nrf.yaml) to `~/oai-cn5g-fed/docker-compose` +- Copy [oai_db.sql](tutorial_resources/oai_db.sql) to `~/oai-cn5g-fed/docker-compose/database` Change permissions on oai_db.sql to prevent mysql permission denied error: ```bash -chmod 644 ~/oai-cn5g-fed/docker-compose/oai_db.sql +chmod 644 ~/oai-cn5g-fed/docker-compose/database/oai_db.sql ``` ## 2.4 SIM Card @@ -175,7 +179,7 @@ cd cmake_targets ```bash cd ~/oai-cn5g-fed/docker-compose -python3 core-network.py --type start-basic --fqdn yes --scenario 1 +python3 core-network.py --type start-basic --scenario 1 ``` ## 4.2 Run OAI gNB diff --git a/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md b/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md index ed917e09ea..ac61363af0 100644 --- a/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md +++ b/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md @@ -87,6 +87,7 @@ cd ~/oai-cn5g-fed git checkout master ./scripts/syncComponents.sh --nrf-branch develop --amf-branch develop --smf-branch develop --spgwu-tiny-branch develop --ausf-branch develop --udm-branch develop --udr-branch develop --upf-vpp-branch develop --nssf-branch develop +# Pull docker images docker pull oaisoftwarealliance/oai-amf:develop docker pull oaisoftwarealliance/oai-nrf:develop docker pull oaisoftwarealliance/oai-smf:develop @@ -96,7 +97,9 @@ docker pull oaisoftwarealliance/oai-ausf:develop docker pull oaisoftwarealliance/oai-upf-vpp:develop docker pull oaisoftwarealliance/oai-spgwu-tiny:develop docker pull oaisoftwarealliance/oai-nssf:develop +docker pull oaisoftwarealliance/trf-gen-cn5g:latest +# Tag docker images docker image tag oaisoftwarealliance/oai-amf:develop oai-amf:develop docker image tag oaisoftwarealliance/oai-nrf:develop oai-nrf:develop docker image tag oaisoftwarealliance/oai-smf:develop oai-smf:develop @@ -106,16 +109,17 @@ docker image tag oaisoftwarealliance/oai-ausf:develop oai-ausf:develop docker image tag oaisoftwarealliance/oai-upf-vpp:develop oai-upf-vpp:develop docker image tag oaisoftwarealliance/oai-spgwu-tiny:develop oai-spgwu-tiny:develop docker image tag oaisoftwarealliance/oai-nssf:develop oai-nssf:develop +docker image tag oaisoftwarealliance/trf-gen-cn5g:latest trf-gen-cn5g:latest ``` ## 2.3 OAI CN5G Configuration files -Download and copy the configuration files to ~/oai-cn5g-fed/docker-compose: -- [docker-compose-basic-nrf.yaml](tutorial_resources/docker-compose-basic-nrf.yaml) -- [oai_db.sql](tutorial_resources/oai_db.sql) +Download and copy configuration files: +- Copy [docker-compose-basic-nrf.yaml](tutorial_resources/docker-compose-basic-nrf.yaml) to `~/oai-cn5g-fed/docker-compose` +- Copy [oai_db.sql](tutorial_resources/oai_db.sql) to `~/oai-cn5g-fed/docker-compose/database` Change permissions on oai_db.sql to prevent mysql permission denied error: ```bash -chmod 644 ~/oai-cn5g-fed/docker-compose/oai_db.sql +chmod 644 ~/oai-cn5g-fed/docker-compose/database/oai_db.sql ``` ## 2.4 SIM Card @@ -193,7 +197,7 @@ The following steps are recommended. Please change the network interface(s) as r ```bash cd ~/oai-cn5g-fed/docker-compose -python3 core-network.py --type start-basic --fqdn yes --scenario 1 +python3 core-network.py --type start-basic --scenario 1 ``` ## 4.2 Run OAI gNB diff --git a/doc/tutorial_resources/docker-compose-basic-nrf.yaml b/doc/tutorial_resources/docker-compose-basic-nrf.yaml index 6750cb78be..93c438055e 100644 --- a/doc/tutorial_resources/docker-compose-basic-nrf.yaml +++ b/doc/tutorial_resources/docker-compose-basic-nrf.yaml @@ -4,8 +4,8 @@ services: container_name: "mysql" image: mysql:5.7 volumes: - - ./oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql - - ./mysql-healthcheck2.sh:/tmp/mysql-healthcheck.sh + - ./database/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql + - ./healthscripts/mysql-healthcheck2.sh:/tmp/mysql-healthcheck.sh environment: - TZ=Europe/Paris - MYSQL_DATABASE=oai_db @@ -21,35 +21,45 @@ services: public_net: ipv4_address: 192.168.70.131 oai-udr: - container_name: oai-udr + container_name: "oai-udr" image: oai-udr:develop environment: - TZ=Europe/Paris - INSTANCE=0 - PID_DIRECTORY=/var/run + - UDR_NAME=OAI_UDR - UDR_INTERFACE_NAME_FOR_NUDR=eth0 - UDR_INTERFACE_PORT_FOR_NUDR=80 - UDR_INTERFACE_HTTP2_PORT_FOR_NUDR=8080 + - USE_HTTP2=no - UDR_API_VERSION=v1 - MYSQL_IPV4_ADDRESS=192.168.70.131 - MYSQL_USER=test - MYSQL_PASS=test + - DB_CONNECTION_TIMEOUT=300 # Reset the connection to the DB after expiring the timeout (in second) currently can't be changed - MYSQL_DB=oai_db - WAIT_MYSQL=120 + - USE_FQDN_DNS=yes + - REGISTER_NRF=yes + - NRF_IPV4_ADDRESS=192.168.70.130 + - NRF_PORT=80 + - NRF_API_VERSION=v1 + - NRF_FQDN=oai-nrf depends_on: - mysql + - oai-nrf networks: public_net: ipv4_address: 192.168.70.136 volumes: - - ./udr-healthcheck.sh:/openair-udr/bin/udr-healthcheck.sh + - ./healthscripts/udr-healthcheck.sh:/openair-udr/bin/udr-healthcheck.sh healthcheck: test: /bin/bash -c "/openair-udr/bin/udr-healthcheck.sh" interval: 10s timeout: 5s retries: 5 oai-udm: - container_name: oai-udm + container_name: "oai-udm" image: oai-udm:develop environment: - TZ=Europe/Paris @@ -58,26 +68,33 @@ services: - UDM_NAME=OAI_UDM - SBI_IF_NAME=eth0 - SBI_PORT=80 + - SBI_HTTP2_PORT=8080 + - USE_HTTP2=no - UDM_VERSION_NB=v1 - USE_FQDN_DNS=yes - UDR_IP_ADDRESS=192.168.70.136 - UDR_PORT=80 - UDR_VERSION_NB=v1 - UDR_FQDN=oai-udr + - REGISTER_NRF=yes + - NRF_IPV4_ADDRESS=192.168.70.130 + - NRF_PORT=80 + - NRF_API_VERSION=v1 + - NRF_FQDN=oai-nrf depends_on: - oai-udr networks: public_net: ipv4_address: 192.168.70.137 volumes: - - ./udm-healthcheck.sh:/openair-udm/bin/udm-healthcheck.sh + - ./healthscripts/udm-healthcheck.sh:/openair-udm/bin/udm-healthcheck.sh healthcheck: test: /bin/bash -c "/openair-udm/bin/udm-healthcheck.sh" interval: 10s timeout: 5s retries: 5 oai-ausf: - container_name: oai-ausf + container_name: "oai-ausf" image: oai-ausf:develop environment: - TZ=Europe/Paris @@ -86,18 +103,25 @@ services: - AUSF_NAME=OAI_AUSF - SBI_IF_NAME=eth0 - SBI_PORT=80 + - USE_HTTP2 + - SBI_HTTP2_PORT - USE_FQDN_DNS=yes - UDM_IP_ADDRESS=192.168.70.137 - UDM_PORT=80 - UDM_VERSION_NB=v1 - UDM_FQDN=oai-udm + - REGISTER_NRF=yes + - NRF_IPV4_ADDRESS=192.168.70.130 + - NRF_PORT=80 + - NRF_API_VERSION=v1 + - NRF_FQDN=oai-nrf depends_on: - oai-udm networks: public_net: ipv4_address: 192.168.70.138 volumes: - - ./ausf-healthcheck.sh:/openair-ausf/bin/ausf-healthcheck.sh + - ./healthscripts/ausf-healthcheck.sh:/openair-ausf/bin/ausf-healthcheck.sh healthcheck: test: /bin/bash -c "/openair-ausf/bin/ausf-healthcheck.sh" interval: 10s @@ -107,9 +131,10 @@ services: container_name: "oai-nrf" image: oai-nrf:develop environment: + - TZ=Europe/Paris - NRF_INTERFACE_NAME_FOR_SBI=eth0 - NRF_INTERFACE_PORT_FOR_SBI=80 - - NRF_INTERFACE_HTTP2_PORT_FOR_SBI=9090 + - NRF_INTERFACE_HTTP2_PORT_FOR_SBI=8080 - NRF_API_VERSION=v1 - INSTANCE=0 - PID_DIRECTORY=/var/run @@ -117,7 +142,7 @@ services: public_net: ipv4_address: 192.168.70.130 volumes: - - ./nrf-healthcheck.sh:/openair-nrf/bin/nrf-healthcheck.sh + - ./healthscripts/nrf-healthcheck.sh:/openair-nrf/bin/nrf-healthcheck.sh healthcheck: test: /bin/bash -c "/openair-nrf/bin/nrf-healthcheck.sh" interval: 10s @@ -146,9 +171,7 @@ services: - PLMN_SUPPORT_MNC=99 - PLMN_SUPPORT_TAC=0x0001 - SST_0=1 - - SD_0=1 - - SST_1=1 - - SD_1=12 + - SD_0=0x1 - AMF_INTERFACE_NAME_FOR_NGAP=eth0 - AMF_INTERFACE_NAME_FOR_N11=eth0 - SMF_INSTANCE_ID_0=1 @@ -168,22 +191,30 @@ services: - OPERATOR_KEY=1006020f0a478bf6b699f15c062e42b3 - NRF_IPV4_ADDRESS=192.168.70.130 - NRF_PORT=80 + - EXTERNAL_NRF=no - NF_REGISTRATION=yes - SMF_SELECTION=yes - USE_FQDN_DNS=yes - EXTERNAL_AUSF=yes + - EXTERNAL_UDM=no + - EXTERNAL_NSSF=no + - USE_HTTP2=no - NRF_API_VERSION=v1 - NRF_FQDN=oai-nrf - AUSF_IPV4_ADDRESS=192.168.70.138 - AUSF_PORT=80 - AUSF_API_VERSION=v1 - AUSF_FQDN=oai-ausf + - UDM_IPV4_ADDRESS=192.168.70.137 + - UDM_PORT=80 + - UDM_API_VERSION=v2 + - UDM_FQDN=oai-udm depends_on: - mysql - oai-nrf - oai-ausf volumes: - - ./amf-healthcheck.sh:/openair-amf/bin/amf-healthcheck.sh + - ./healthscripts/amf-healthcheck.sh:/openair-amf/bin/amf-healthcheck.sh healthcheck: test: /bin/bash -c "/openair-amf/bin/amf-healthcheck.sh" interval: 10s @@ -212,26 +243,35 @@ services: - AMF_FQDN=oai-amf - UDM_IPV4_ADDRESS=192.168.70.137 - UDM_PORT=80 - - UDM_API_VERSION=v1 + - UDM_API_VERSION=v2 - UDM_FQDN=oai-udm - UPF_IPV4_ADDRESS=192.168.70.134 - UPF_FQDN_0=oai-spgwu - NRF_IPV4_ADDRESS=192.168.70.130 - NRF_PORT=80 - NRF_API_VERSION=v1 - - USE_LOCAL_SUBSCRIPTION_INFO=yes + - USE_LOCAL_SUBSCRIPTION_INFO=yes #Set to yes if SMF uses local subscription information instead of from an UDM + - USE_NETWORK_INSTANCE=no #Set yes if network instance is to be used for given UPF - NRF_FQDN=oai-nrf - REGISTER_NRF=yes - DISCOVER_UPF=yes - USE_FQDN_DNS=yes - - DNN_RANGE1=12.1.1.2 - 12.1.1.128 - - DNN_RANGE0=12.2.1.2 - 12.2.1.128 - - DNN_NI1=oai + - HTTP_VERSION=1 # Default: 1 + - UE_MTU=1500 + - DNN_NI0=oai + - TYPE0=IPv4 + - DNN_RANGE0=12.1.1.2 - 12.1.1.253 + - NSSAI_SST0=1 + - NSSAI_SD0=0x1 + - SESSION_AMBR_UL0=1000Mbps + - SESSION_AMBR_DL0=1000Mbps + - DEFAULT_CSCF_IPV4_ADDRESS=127.0.0.1 # only needed when ims is being used + - ENABLE_USAGE_REPORTING=no # Set yes if UE USAGE REPORTING is to be done at UPF depends_on: - oai-nrf - oai-amf volumes: - - ./smf-healthcheck.sh:/openair-smf/bin/smf-healthcheck.sh + - ./healthscripts/smf-healthcheck.sh:/openair-smf/bin/smf-healthcheck.sh healthcheck: test: /bin/bash -c "/openair-smf/bin/smf-healthcheck.sh" interval: 10s @@ -258,17 +298,23 @@ services: - MNC03=099 - TAC=1 - GW_ID=1 + - THREAD_S1U_PRIO=80 + - S1U_THREADS=8 + - THREAD_SX_PRIO=81 + - SX_THREADS=1 + - THREAD_SGI_PRIO=80 + - SGI_THREADS=8 - REALM=openairinterface.org - ENABLE_5G_FEATURES=yes - REGISTER_NRF=yes - - USE_FQDN_NRF=no + - USE_FQDN_NRF=yes - UPF_FQDN_5G=oai-spgwu - NRF_IPV4_ADDRESS=192.168.70.130 - NRF_PORT=80 - NRF_API_VERSION=v1 - NRF_FQDN=oai-nrf - NSSAI_SST_0=1 - - NSSAI_SD_0=1 + - NSSAI_SD_0=0x1 - DNN_0=oai depends_on: - oai-nrf @@ -280,7 +326,7 @@ services: - ALL privileged: true volumes: - - ./spgwu-healthcheck.sh:/openair-spgwu-tiny/bin/spgwu-healthcheck.sh + - ./healthscripts/spgwu-healthcheck.sh:/openair-spgwu-tiny/bin/spgwu-healthcheck.sh healthcheck: test: /bin/bash -c "/openair-spgwu-tiny/bin/spgwu-healthcheck.sh" interval: 10s @@ -290,12 +336,10 @@ services: public_net: ipv4_address: 192.168.70.134 oai-ext-dn: - image: ubuntu:bionic + image: trf-gen-cn5g:latest privileged: true container_name: oai-ext-dn entrypoint: /bin/bash -c \ - "apt update; apt install -y iptables iproute2 iperf iperf3 iputils-ping;"\ - "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ "ip route add 12.1.1.0/24 via 192.168.70.134 dev eth0; sleep infinity" depends_on: - oai-spgwu diff --git a/doc/tutorial_resources/oai_db.sql b/doc/tutorial_resources/oai_db.sql index e019c60e86..fb8f4b20ed 100644 --- a/doc/tutorial_resources/oai_db.sql +++ b/doc/tutorial_resources/oai_db.sql @@ -151,10 +151,13 @@ CREATE TABLE `AuthenticationSubscription` ( -- INSERT INTO `AuthenticationSubscription` (`ueid`, `authenticationMethod`, `encPermanentKey`, `protectionParameterId`, `sequenceNumber`, `authenticationManagementField`, `algorithmId`, `encOpcKey`, `encTopcKey`, `vectorGenerationInHss`, `n5gcAuthMethod`, `rgAuthenticationInd`, `supi`) VALUES -('208950000000031', '5G_AKA', '0C0A34601D4F07677303652C0462535B', '0C0A34601D4F07677303652C0462535B', '{\"sqn\": \"000000000020\", \"sqnScheme\": \"NON_TIME_BASED\", \"lastIndexes\": {\"ausf\": 0}}', '8000', 'milenage', '63bfa50ee6523365ff14c1f45f88737d', NULL, NULL, NULL, NULL, '208950000000031'); - + ('2089900007487', '5G_AKA', 'fec86ba6eb707ed08905757b1bb44b8f', 'fec86ba6eb707ed08905757b1bb44b8f', '{\"sqn\": \"000000000000\", \"sqnScheme\": \"NON_TIME_BASED\", \"lastIndexes\": {\"ausf\": 0}}', '8000', 'milenage', 'C42449363BBAD02B66D16BC975D77CC1', NULL, NULL, NULL, NULL, '2089900007487'); INSERT INTO `AuthenticationSubscription` (`ueid`, `authenticationMethod`, `encPermanentKey`, `protectionParameterId`, `sequenceNumber`, `authenticationManagementField`, `algorithmId`, `encOpcKey`, `encTopcKey`, `vectorGenerationInHss`, `n5gcAuthMethod`, `rgAuthenticationInd`, `supi`) VALUES -('208990000000001', '5G_AKA', 'fec86ba6eb707ed08905757b1bb44b8f', 'fec86ba6eb707ed08905757b1bb44b8f', '{\"sqn\": \"000000000020\", \"sqnScheme\": \"NON_TIME_BASED\", \"lastIndexes\": {\"ausf\": 0}}', '8000', 'milenage', 'C42449363BBAD02B66D16BC975D77CC1', NULL, NULL, NULL, NULL, '208990000000001'); + ('208990000000001', '5G_AKA', 'fec86ba6eb707ed08905757b1bb44b8f', 'fec86ba6eb707ed08905757b1bb44b8f', '{\"sqn\": \"000000000000\", \"sqnScheme\": \"NON_TIME_BASED\", \"lastIndexes\": {\"ausf\": 0}}', '8000', 'milenage', 'C42449363BBAD02B66D16BC975D77CC1', NULL, NULL, NULL, NULL, '208990000000001'); +INSERT INTO `AuthenticationSubscription` (`ueid`, `authenticationMethod`, `encPermanentKey`, `protectionParameterId`, `sequenceNumber`, `authenticationManagementField`, `algorithmId`, `encOpcKey`, `encTopcKey`, `vectorGenerationInHss`, `n5gcAuthMethod`, `rgAuthenticationInd`, `supi`) VALUES + ('208990000000002', '5G_AKA', 'fec86ba6eb707ed08905757b1bb44b8f', 'fec86ba6eb707ed08905757b1bb44b8f', '{\"sqn\": \"000000000000\", \"sqnScheme\": \"NON_TIME_BASED\", \"lastIndexes\": {\"ausf\": 0}}', '8000', 'milenage', 'C42449363BBAD02B66D16BC975D77CC1', NULL, NULL, NULL, NULL, '208990000000002'); +INSERT INTO `AuthenticationSubscription` (`ueid`, `authenticationMethod`, `encPermanentKey`, `protectionParameterId`, `sequenceNumber`, `authenticationManagementField`, `algorithmId`, `encOpcKey`, `encTopcKey`, `vectorGenerationInHss`, `n5gcAuthMethod`, `rgAuthenticationInd`, `supi`) VALUES + ('208990000000003', '5G_AKA', 'fec86ba6eb707ed08905757b1bb44b8f', 'fec86ba6eb707ed08905757b1bb44b8f', '{\"sqn\": \"000000000000\", \"sqnScheme\": \"NON_TIME_BASED\", \"lastIndexes\": {\"ausf\": 0}}', '8000', 'milenage', 'C42449363BBAD02B66D16BC975D77CC1', NULL, NULL, NULL, NULL, '208990000000003'); -- -------------------------------------------------------- @@ -203,6 +206,19 @@ CREATE TABLE `SessionManagementSubscriptionData` ( `3gppChargingCharacteristics` varchar(50) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Dumping data for table `SessionManagementSubscriptionData` +-- + +INSERT INTO `SessionManagementSubscriptionData` (`ueid`, `servingPlmnid`, `singleNssai`, `dnnConfigurations`) VALUES + ('2089900007487', '20899', '{\"sst\": 1, \"sd\": \"1\"}','{\"oai\":{\"pduSessionTypes\":{ \"defaultSessionType\": \"IPV4\"},\"sscModes\": {\"defaultSscMode\": \"SSC_MODE_1\"},\"5gQosProfile\": {\"5qi\": 6,\"arp\":{\"priorityLevel\": 1,\"preemptCap\": \"NOT_PREEMPT\",\"preemptVuln\":\"NOT_PREEMPTABLE\"},\"priorityLevel\":1},\"sessionAmbr\":{\"uplink\":\"1000Mbps\", \"downlink\":\"1000Mbps\"},\"staticIpAddress\":[{\"ipv4Addr\": \"12.1.1.2\"}]}}'); +INSERT INTO `SessionManagementSubscriptionData` (`ueid`, `servingPlmnid`, `singleNssai`, `dnnConfigurations`) VALUES + ('208990000000001', '20899', '{\"sst\": 1, \"sd\": \"1\"}','{\"oai\":{\"pduSessionTypes\":{ \"defaultSessionType\": \"IPV4\"},\"sscModes\": {\"defaultSscMode\": \"SSC_MODE_1\"},\"5gQosProfile\": {\"5qi\": 6,\"arp\":{\"priorityLevel\": 1,\"preemptCap\": \"NOT_PREEMPT\",\"preemptVuln\":\"NOT_PREEMPTABLE\"},\"priorityLevel\":1},\"sessionAmbr\":{\"uplink\":\"1000Mbps\", \"downlink\":\"1000Mbps\"},\"staticIpAddress\":[{\"ipv4Addr\": \"12.1.1.2\"}]}}'); +INSERT INTO `SessionManagementSubscriptionData` (`ueid`, `servingPlmnid`, `singleNssai`, `dnnConfigurations`) VALUES + ('208990000000002', '20899', '{\"sst\": 1, \"sd\": \"1\"}','{\"oai\":{\"pduSessionTypes\":{ \"defaultSessionType\": \"IPV4\"},\"sscModes\": {\"defaultSscMode\": \"SSC_MODE_1\"},\"5gQosProfile\": {\"5qi\": 6,\"arp\":{\"priorityLevel\": 1,\"preemptCap\": \"NOT_PREEMPT\",\"preemptVuln\":\"NOT_PREEMPTABLE\"},\"priorityLevel\":1},\"sessionAmbr\":{\"uplink\":\"1000Mbps\", \"downlink\":\"1000Mbps\"},\"staticIpAddress\":[{\"ipv4Addr\": \"12.1.1.3\"}]}}'); +INSERT INTO `SessionManagementSubscriptionData` (`ueid`, `servingPlmnid`, `singleNssai`, `dnnConfigurations`) VALUES + ('208990000000003', '20899', '{\"sst\": 1, \"sd\": \"1\"}','{\"oai\":{\"pduSessionTypes\":{ \"defaultSessionType\": \"IPV4\"},\"sscModes\": {\"defaultSscMode\": \"SSC_MODE_1\"},\"5gQosProfile\": {\"5qi\": 6,\"arp\":{\"priorityLevel\": 1,\"preemptCap\": \"NOT_PREEMPT\",\"preemptVuln\":\"NOT_PREEMPTABLE\"},\"priorityLevel\":1},\"sessionAmbr\":{\"uplink\":\"1000Mbps\", \"downlink\":\"1000Mbps\"},\"staticIpAddress\":[{\"ipv4Addr\": \"12.1.1.4\"}]}}'); + -- -------------------------------------------------------- -- From ae05420c84ccbdc04843db1d5b318176998220b4 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 15 Jul 2022 13:35:19 +0200 Subject: [PATCH 211/267] CI: log error if oai-amf container is not present for AMF IP addr retrieval --- ci-scripts/epc.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py index 0e0afefaaf..9113d29ac9 100644 --- a/ci-scripts/epc.py +++ b/ci-scripts/epc.py @@ -311,6 +311,8 @@ class EPCManagement(): tmp = str(response[0],'utf-8') self.MmeIPAddress = tmp.rstrip() logging.debug('AMF IP Address ' + self.MmeIPAddress) + else: + logging.error('no container with name oai-amf found, could not retrieve AMF IP address') mySSH.close() def CheckHSSProcess(self, status_queue): From 43298fd02ce8b46636273049a393338117e63aca Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Fri, 15 Jul 2022 13:19:37 +0100 Subject: [PATCH 212/267] Address merge request review comments --- doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md | 11 ---------- doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md | 11 ---------- .../docker-compose-basic-nrf.yaml | 20 +++++++++---------- 3 files changed, 10 insertions(+), 32 deletions(-) diff --git a/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md b/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md index da013515da..fc0700c699 100644 --- a/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md +++ b/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md @@ -71,10 +71,6 @@ reboot # https://docs.docker.com/compose/install/ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose - -docker network create --driver=bridge --subnet=192.168.70.128/26 -o "com.docker.network.bridge.name"="demo-oai" demo-oai-public-net -sudo service docker restart - ``` ## 2.2 OAI CN5G Setup @@ -82,9 +78,6 @@ sudo service docker restart ```bash # Git oai-cn5g-fed repository git clone https://gitlab.eurecom.fr/oai/cn5g/oai-cn5g-fed.git ~/oai-cn5g-fed -cd ~/oai-cn5g-fed -git checkout master -./scripts/syncComponents.sh --nrf-branch develop --amf-branch develop --smf-branch develop --spgwu-tiny-branch develop --ausf-branch develop --udm-branch develop --udr-branch develop --upf-vpp-branch develop --nssf-branch develop # Pull docker images docker pull oaisoftwarealliance/oai-amf:develop @@ -93,9 +86,7 @@ docker pull oaisoftwarealliance/oai-smf:develop docker pull oaisoftwarealliance/oai-udr:develop docker pull oaisoftwarealliance/oai-udm:develop docker pull oaisoftwarealliance/oai-ausf:develop -docker pull oaisoftwarealliance/oai-upf-vpp:develop docker pull oaisoftwarealliance/oai-spgwu-tiny:develop -docker pull oaisoftwarealliance/oai-nssf:develop docker pull oaisoftwarealliance/trf-gen-cn5g:latest # Tag docker images @@ -105,9 +96,7 @@ docker image tag oaisoftwarealliance/oai-smf:develop oai-smf:develop docker image tag oaisoftwarealliance/oai-udr:develop oai-udr:develop docker image tag oaisoftwarealliance/oai-udm:develop oai-udm:develop docker image tag oaisoftwarealliance/oai-ausf:develop oai-ausf:develop -docker image tag oaisoftwarealliance/oai-upf-vpp:develop oai-upf-vpp:develop docker image tag oaisoftwarealliance/oai-spgwu-tiny:develop oai-spgwu-tiny:develop -docker image tag oaisoftwarealliance/oai-nssf:develop oai-nssf:develop docker image tag oaisoftwarealliance/trf-gen-cn5g:latest trf-gen-cn5g:latest ``` diff --git a/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md b/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md index ac61363af0..d68057fd08 100644 --- a/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md +++ b/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md @@ -72,10 +72,6 @@ reboot # https://docs.docker.com/compose/install/ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose - -docker network create --driver=bridge --subnet=192.168.70.128/26 -o "com.docker.network.bridge.name"="demo-oai" demo-oai-public-net -sudo service docker restart - ``` ## 2.2 OAI CN5G Setup @@ -83,9 +79,6 @@ sudo service docker restart ```bash # Git oai-cn5g-fed repository git clone https://gitlab.eurecom.fr/oai/cn5g/oai-cn5g-fed.git ~/oai-cn5g-fed -cd ~/oai-cn5g-fed -git checkout master -./scripts/syncComponents.sh --nrf-branch develop --amf-branch develop --smf-branch develop --spgwu-tiny-branch develop --ausf-branch develop --udm-branch develop --udr-branch develop --upf-vpp-branch develop --nssf-branch develop # Pull docker images docker pull oaisoftwarealliance/oai-amf:develop @@ -94,9 +87,7 @@ docker pull oaisoftwarealliance/oai-smf:develop docker pull oaisoftwarealliance/oai-udr:develop docker pull oaisoftwarealliance/oai-udm:develop docker pull oaisoftwarealliance/oai-ausf:develop -docker pull oaisoftwarealliance/oai-upf-vpp:develop docker pull oaisoftwarealliance/oai-spgwu-tiny:develop -docker pull oaisoftwarealliance/oai-nssf:develop docker pull oaisoftwarealliance/trf-gen-cn5g:latest # Tag docker images @@ -106,9 +97,7 @@ docker image tag oaisoftwarealliance/oai-smf:develop oai-smf:develop docker image tag oaisoftwarealliance/oai-udr:develop oai-udr:develop docker image tag oaisoftwarealliance/oai-udm:develop oai-udm:develop docker image tag oaisoftwarealliance/oai-ausf:develop oai-ausf:develop -docker image tag oaisoftwarealliance/oai-upf-vpp:develop oai-upf-vpp:develop docker image tag oaisoftwarealliance/oai-spgwu-tiny:develop oai-spgwu-tiny:develop -docker image tag oaisoftwarealliance/oai-nssf:develop oai-nssf:develop docker image tag oaisoftwarealliance/trf-gen-cn5g:latest trf-gen-cn5g:latest ``` diff --git a/doc/tutorial_resources/docker-compose-basic-nrf.yaml b/doc/tutorial_resources/docker-compose-basic-nrf.yaml index 93c438055e..cd1e957ad8 100644 --- a/doc/tutorial_resources/docker-compose-basic-nrf.yaml +++ b/doc/tutorial_resources/docker-compose-basic-nrf.yaml @@ -347,14 +347,14 @@ services: public_net: ipv4_address: 192.168.70.135 networks: + # public_net: + # external: + # name: demo-oai-public-net public_net: - external: - name: demo-oai-public-net -# public_net: -# driver: bridge -# name: demo-oai-public-net -# ipam: -# config: -# - subnet: 192.168.70.128/26 -# driver_opts: -# com.docker.network.bridge.name: "demo-oai" + driver: bridge + name: demo-oai-public-net + ipam: + config: + - subnet: 192.168.70.128/26 + driver_opts: + com.docker.network.bridge.name: "demo-oai" From 16c758ae0972a35bef28af38c82122232926f563 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 15 Jul 2022 16:00:52 +0200 Subject: [PATCH 213/267] CI: Drop IP check when connectiong via SSH and pubkey --- ci-scripts/sshconnection.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py index 52d799ebe3..035da71426 100644 --- a/ci-scripts/sshconnection.py +++ b/ci-scripts/sshconnection.py @@ -84,16 +84,11 @@ class SSHConnection(): else: logging.debug('self.sshresponse = ' + str(self.sshresponse)) elif self.sshresponse == 2: - # Checking if we are really on the remote client defined by its IP address - self.ssh.sendline('stdbuf -o0 ifconfig | egrep --color=never "inet addr:|inet "') - self.sshresponse = self.ssh.expect([ipaddress, pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - count = 10 - connect_status = True - # this expect seems to be necessary to advance the read buffer until the prompt, or getBefore() will not return the last command - self.sshresponse = self.ssh.expect([prompt]) - else: - logging.error('logged in to ' + ipaddress + ' without password but IP is not found via ifconfig on remote host, aborting') + # We directly ended up on the remote server because of pubkey auth + count = 10 + connect_status = True + # this expect() seems to be necessary to advance the read buffer until the prompt, or getBefore() will not return the last command + self.sshresponse = self.ssh.expect([prompt]) else: # debug output logging.debug(str(self.ssh.before)) From 04251d5b06f4ab5abbe560905efac74e496a101c Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 18 Jul 2022 17:39:52 +0200 Subject: [PATCH 214/267] Correctly initialize protocol_ctxt in F1 code In the previous version, not all fields, and in particular the `eNB_index`, were not initialized, leading to errors when they were used (e.g., the PDCP code checks that eNB_index == 0). --- openair2/RRC/NR/rrc_gNB.c | 63 ++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 43082003df..400be0bd4d 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -197,7 +197,7 @@ static void init_NR_SI(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration } char openair_rrc_gNB_configuration(const module_id_t gnb_mod_idP, gNB_RrcConfigurationReq *configuration) { - protocol_ctxt_t ctxt; + protocol_ctxt_t ctxt = { 0 }; gNB_RRC_INST *rrc=RC.nrrrc[gnb_mod_idP]; PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, gnb_mod_idP, GNB_FLAG_YES, NOT_A_RNTI, 0, 0,gnb_mod_idP); LOG_I(NR_RRC, @@ -3030,11 +3030,13 @@ void rrc_gNB_process_dc_overall_timeout(const module_id_t gnb_mod_idP, x2ap_ENDC static int rrc_process_DU_DL(MessageDef *msg_p, const char *msg_name, instance_t instance) { NRDuDlReq_t * req=&NRDuDlReq(msg_p); - protocol_ctxt_t ctxt; - ctxt.rnti = req->rnti; - ctxt.module_id = instance; - ctxt.instance = instance; - ctxt.enb_flag = 1; + protocol_ctxt_t ctxt = { + .rnti = req->rnti, + .module_id = instance, + .instance = instance, + .enb_flag = 1, + .eNB_index = instance + }; gNB_RRC_INST *rrc = RC.nrrrc[ctxt.module_id]; struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_get_ue_context(rrc, ctxt.rnti); @@ -3285,11 +3287,13 @@ return 0; static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const char *msg_name, instance_t instance){ f1ap_ue_context_setup_t * req=&F1AP_UE_CONTEXT_SETUP_REQ(msg_p); - protocol_ctxt_t ctxt; - ctxt.rnti = req->rnti; - ctxt.module_id = instance; - ctxt.instance = instance; - ctxt.enb_flag = 1; + protocol_ctxt_t ctxt = { + .rnti = req->rnti, + .module_id = instance, + .instance = instance, + .enb_flag = 1, + .eNB_index = instance + }; gNB_RRC_INST *rrc = RC.nrrrc[ctxt.module_id]; gNB_MAC_INST *mac = RC.nrmac[ctxt.module_id]; struct rrc_gNB_ue_context_s *ue_context_p = @@ -3515,11 +3519,13 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha static void rrc_DU_process_ue_context_modification_request(MessageDef *msg_p, const char *msg_name, instance_t instance){ f1ap_ue_context_setup_t * req=&F1AP_UE_CONTEXT_MODIFICATION_REQ(msg_p); - protocol_ctxt_t ctxt; - ctxt.rnti = req->rnti; - ctxt.module_id = instance; - ctxt.instance = instance; - ctxt.enb_flag = 1; + protocol_ctxt_t ctxt = { + .rnti = req->rnti, + .module_id = instance, + .instance = instance, + .enb_flag = 1, + .eNB_index = instance + }; gNB_RRC_INST *rrc = RC.nrrrc[ctxt.module_id]; gNB_MAC_INST *mac = RC.nrmac[ctxt.module_id]; struct rrc_gNB_ue_context_s *ue_context_p = @@ -3664,11 +3670,13 @@ static void rrc_DU_process_ue_context_modification_request(MessageDef *msg_p, co static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, const char *msg_name, instance_t instance){ f1ap_ue_context_setup_t * resp=&F1AP_UE_CONTEXT_SETUP_RESP(msg_p); - protocol_ctxt_t ctxt; - ctxt.rnti = resp->rnti; - ctxt.module_id = instance; - ctxt.instance = instance; - ctxt.enb_flag = 1; + protocol_ctxt_t ctxt = { + .rnti = resp->rnti, + .module_id = instance, + .instance = instance, + .enb_flag = 1, + .eNB_index = instance + }; gNB_RRC_INST *rrc = RC.nrrrc[ctxt.module_id]; struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_get_ue_context(rrc, ctxt.rnti); NR_CellGroupConfig_t *cellGroupConfig = NULL; @@ -3721,12 +3729,13 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, const ch static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, const char *msg_name, instance_t instance){ f1ap_ue_context_setup_t * resp=&F1AP_UE_CONTEXT_SETUP_RESP(msg_p); - protocol_ctxt_t ctxt; - ctxt.rnti = resp->rnti; - ctxt.module_id = instance; - ctxt.instance = instance; - ctxt.enb_flag = 1; - ctxt.eNB_index = instance; + protocol_ctxt_t ctxt = { + .rnti = resp->rnti, + .module_id = instance, + .instance = instance, + .enb_flag = 1, + .eNB_index = instance + }; gNB_RRC_INST *rrc = RC.nrrrc[ctxt.module_id]; struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_get_ue_context(rrc, ctxt.rnti); NR_CellGroupConfig_t *cellGroupConfig = NULL; From 24b651b465f002d8814e20492fa0e8baf6766d1f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Sun, 19 Jun 2022 17:31:57 +0200 Subject: [PATCH 215/267] Provide build_oai option UBSan --- cmake_targets/CMakeLists.txt | 6 ++++++ cmake_targets/build_oai | 12 +++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 25e10931c7..6446ced4bd 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -271,6 +271,12 @@ if (SANITIZE_ADDRESS) # wrong in the pthread library, or something subtly wrong in this CMakeLists.txt. Use Ubuntu 20.04 instead. endif () +add_boolean_option(SANITIZE_UNDEFINED False "enable the undefined behavior sanitizer (UBSan)") +if (SANITIZE_UNDEFINED) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all") +endif () + add_definitions("-DASN_DISABLE_OER_SUPPORT") ######################### diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 5a201fcfef..16a0d559dd 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -171,8 +171,12 @@ Options: Skip build for shared libraries to reduce compilation time when building frequently for debugging purposes --ninja Tell cmake to use the Ninja build system. Without, will generate make files +--sanitize + Shortcut for usage of --sanitize-address --sanitize-undefined --sanitize-address | -fsanitize=address - Enable the address sanitizer on all targets + Enable the address sanitizer on all targets +--sanitize-undefined | -fsanitize=undefined + Enable the undefined behavior sanitizer on all targets --ittiSIM Makes the itti simulator -h | --help @@ -451,10 +455,16 @@ function main() { CMAKE_CMD="$CMAKE_CMD -GNinja" MAKE_CMD=ninja shift;; + --sanitize) + CMAKE_CMD="$CMAKE_CMD -DSANITIZE_ADDRESS=True -DSANITIZE_UNDEFINED=True" + shift;; --sanitize-address | -fsanitize=address) grep -sq "Ubuntu 18.04" /etc/os-release && echo_error "Bug in OS with this option, see CMakeLists.txt" CMAKE_CMD="$CMAKE_CMD -DSANITIZE_ADDRESS=True" shift;; + --sanitize-undefined | -fundefined=address) + CMAKE_CMD="$CMAKE_CMD -DSANITIZE_UNDEFINED=True" + shift;; --ittiSIM) ittiSIM=1 CMAKE_CMD="$CMAKE_CMD -DITTI_SIM=True" From b07a167370d5a61fcdd2fd083b386be49ea80c2f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 24 May 2022 14:43:11 +0200 Subject: [PATCH 216/267] Correct indentation in nr_rx_pdsch() --- .../NR_UE_TRANSPORT/nr_dlsch_demodulation.c | 145 +++++++++--------- 1 file changed, 72 insertions(+), 73 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index eb43d80525..6728f0260c 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -466,88 +466,87 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, if (cpumeas(CPUMEAS_GETSTATE)) LOG_D(PHY, "[AbsSFN %u.%d] Slot%d Symbol %d: Channel Combine and zero forcing %5.2f \n",frame,nr_slot_rx,slot,symbol,ue->generic_stat_bis[proc->thread_id][slot].p_time/(cpuf*1000.0)); - start_meas(&ue->generic_stat_bis[proc->thread_id][slot]); + start_meas(&ue->generic_stat_bis[proc->thread_id][slot]); /* Store the valid DL RE's */ - pdsch_vars[gNB_id]->dl_valid_re[symbol-1] = nb_re_pdsch; + pdsch_vars[gNB_id]->dl_valid_re[symbol-1] = nb_re_pdsch; - if(dlsch0_harq->status == ACTIVE) { - startSymbIdx = dlsch0_harq->start_symbol; - nbSymb = dlsch0_harq->nb_symbols; - pduBitmap = dlsch0_harq->pduBitmap; - } - if(dlsch1_harq) { - startSymbIdx = dlsch1_harq->start_symbol; - nbSymb = dlsch1_harq->nb_symbols; - pduBitmap = dlsch1_harq->pduBitmap; - } + if(dlsch0_harq->status == ACTIVE) { + startSymbIdx = dlsch0_harq->start_symbol; + nbSymb = dlsch0_harq->nb_symbols; + pduBitmap = dlsch0_harq->pduBitmap; + } + if(dlsch1_harq) { + startSymbIdx = dlsch1_harq->start_symbol; + nbSymb = dlsch1_harq->nb_symbols; + pduBitmap = dlsch1_harq->pduBitmap; + } - /* Check for PTRS bitmap and process it respectively */ - if((pduBitmap & 0x1) && (type == PDSCH)) { - nr_pdsch_ptrs_processing(ue, - pdsch_vars, - frame_parms, - dlsch0_harq, - dlsch1_harq, - gNB_id, - nr_slot_rx, - symbol, - (nb_rb_pdsch*12), - dlsch[0]->rnti,rx_type); - pdsch_vars[gNB_id]->dl_valid_re[symbol-1] -= pdsch_vars[gNB_id]->ptrs_re_per_slot[0][symbol]; - } + /* Check for PTRS bitmap and process it respectively */ + if((pduBitmap & 0x1) && (type == PDSCH)) { + nr_pdsch_ptrs_processing(ue, + pdsch_vars, + frame_parms, + dlsch0_harq, + dlsch1_harq, + gNB_id, + nr_slot_rx, + symbol, + (nb_rb_pdsch*12), + dlsch[0]->rnti,rx_type); + pdsch_vars[gNB_id]->dl_valid_re[symbol-1] -= pdsch_vars[gNB_id]->ptrs_re_per_slot[0][symbol]; + } - /* at last symbol in a slot calculate LLR's for whole slot */ - if(symbol == (startSymbIdx + nbSymb -1)) { - for(uint8_t i =startSymbIdx; i < (startSymbIdx+nbSymb);i++) { - /* re evaluating the first symbol flag as LLR's are done in symbol loop */ - if(i == startSymbIdx && i < 3) { - first_symbol_flag =1; - } - else { - first_symbol_flag=0; - } - /* Calculate LLR's for each symbol */ - nr_dlsch_llr(pdsch_vars, frame_parms, - rxdataF_comp_ptr, dl_ch_mag_ptr, - dlsch0_harq, dlsch1_harq, - rx_type, harq_pid, - gNB_id, gNB_id_i, - first_symbol_flag, - i, nb_rb_pdsch, - codeword_TB0, codeword_TB1, - pdsch_vars[gNB_id]->dl_valid_re[i-1], - nr_slot_rx, beamforming_mode); + /* at last symbol in a slot calculate LLR's for whole slot */ + if(symbol == (startSymbIdx + nbSymb -1)) { + for(uint8_t i =startSymbIdx; i < (startSymbIdx+nbSymb);i++) { + /* re evaluating the first symbol flag as LLR's are done in symbol loop */ + if(i == startSymbIdx && i < 3) { + first_symbol_flag =1; } - - int dmrs_type = dlsch[0]->harq_processes[harq_pid]->dmrsConfigType; - uint8_t nb_re_dmrs; - uint16_t dmrs_len = get_num_dmrs(dlsch[0]->harq_processes[harq_pid]->dlDmrsSymbPos); - if (dmrs_type==NFAPI_NR_DMRS_TYPE1) { - nb_re_dmrs = 6*dlsch[0]->harq_processes[harq_pid]->n_dmrs_cdm_groups; - } else { - nb_re_dmrs = 4*dlsch[0]->harq_processes[harq_pid]->n_dmrs_cdm_groups; + else { + first_symbol_flag=0; } - dlsch[0]->harq_processes[harq_pid]->G = nr_get_G(dlsch[0]->harq_processes[harq_pid]->nb_rb, - dlsch[0]->harq_processes[harq_pid]->nb_symbols, - nb_re_dmrs, - dmrs_len, - dlsch[0]->harq_processes[harq_pid]->Qm, - dlsch[0]->harq_processes[harq_pid]->Nl); - nr_dlsch_layer_demapping(pdsch_vars[gNB_id]->llr, - dlsch[0]->harq_processes[harq_pid]->Nl, - dlsch[0]->harq_processes[harq_pid]->Qm, - dlsch[0]->harq_processes[harq_pid]->G, - codeword_TB0, - codeword_TB1, - pdsch_vars[gNB_id]->layer_llr); - + /* Calculate LLR's for each symbol */ + nr_dlsch_llr(pdsch_vars, frame_parms, + rxdataF_comp_ptr, dl_ch_mag_ptr, + dlsch0_harq, dlsch1_harq, + rx_type, harq_pid, + gNB_id, gNB_id_i, + first_symbol_flag, + i, nb_rb_pdsch, + codeword_TB0, codeword_TB1, + pdsch_vars[gNB_id]->dl_valid_re[i-1], + nr_slot_rx, beamforming_mode); } - stop_meas(&ue->generic_stat_bis[proc->thread_id][slot]); - if (cpumeas(CPUMEAS_GETSTATE)) - LOG_D(PHY, "[AbsSFN %u.%d] Slot%d Symbol %d: LLR Computation %5.2f \n",frame,nr_slot_rx,slot,symbol,ue->generic_stat_bis[proc->thread_id][slot].p_time/(cpuf*1000.0)); + int dmrs_type = dlsch[0]->harq_processes[harq_pid]->dmrsConfigType; + uint8_t nb_re_dmrs; + uint16_t dmrs_len = get_num_dmrs(dlsch[0]->harq_processes[harq_pid]->dlDmrsSymbPos); + if (dmrs_type==NFAPI_NR_DMRS_TYPE1) { + nb_re_dmrs = 6*dlsch[0]->harq_processes[harq_pid]->n_dmrs_cdm_groups; + } else { + nb_re_dmrs = 4*dlsch[0]->harq_processes[harq_pid]->n_dmrs_cdm_groups; + } + dlsch[0]->harq_processes[harq_pid]->G = nr_get_G(dlsch[0]->harq_processes[harq_pid]->nb_rb, + dlsch[0]->harq_processes[harq_pid]->nb_symbols, + nb_re_dmrs, + dmrs_len, + dlsch[0]->harq_processes[harq_pid]->Qm, + dlsch[0]->harq_processes[harq_pid]->Nl); + nr_dlsch_layer_demapping(pdsch_vars[gNB_id]->llr, + dlsch[0]->harq_processes[harq_pid]->Nl, + dlsch[0]->harq_processes[harq_pid]->Qm, + dlsch[0]->harq_processes[harq_pid]->G, + codeword_TB0, + codeword_TB1, + pdsch_vars[gNB_id]->layer_llr); + } -// Please keep it: useful for debugging + stop_meas(&ue->generic_stat_bis[proc->thread_id][slot]); + if (cpumeas(CPUMEAS_GETSTATE)) + LOG_D(PHY, "[AbsSFN %u.%d] Slot%d Symbol %d: LLR Computation %5.2f \n",frame,nr_slot_rx,slot,symbol,ue->generic_stat_bis[proc->thread_id][slot].p_time/(cpuf*1000.0)); + + // Please keep it: useful for debugging #ifdef DEBUG_PDSCH_RX char filename[50]; uint8_t aa = 0; From 6b757c53209bbffa4b3eb58d1d61948969b09037 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 24 May 2022 14:43:49 +0200 Subject: [PATCH 217/267] Correct array sizes in dlsim --- openair1/SIMULATION/LTE_PHY/dlsim.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 231d63cf04..d715423bb1 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -512,12 +512,12 @@ int main(int argc, char **argv) { int re; int s,Kr,Kr_bytes; LTE_DL_FRAME_PARMS *frame_parms; - double s_re0[30720*2],s_im0[30720*2],r_re0[30720*2],r_im0[30720*2]; - double s_re1[30720*2],s_im1[30720*2],r_re1[30720*2],r_im1[30720*2]; - double *s_re[2]= {s_re0,s_re1}; - double *s_im[2]= {s_im0,s_im1}; - double *r_re[2]= {r_re0,r_re1}; - double *r_im[2]= {r_im0,r_im1}; + double s_re0[30720*NB_ANTENNAS_TX],s_im0[30720*NB_ANTENNAS_TX],r_re0[30720*NB_ANTENNAS_RX],r_im0[30720*NB_ANTENNAS_RX]; + double s_re1[30720*NB_ANTENNAS_TX],s_im1[30720*NB_ANTENNAS_TX],r_re1[30720*NB_ANTENNAS_RX],r_im1[30720*NB_ANTENNAS_RX]; + double *s_re[NB_ANTENNAS_TX]= {s_re0,s_re1}; + double *s_im[NB_ANTENNAS_TX]= {s_im0,s_im1}; + double *r_re[NB_ANTENNAS_RX]= {r_re0,r_re1}; + double *r_im[NB_ANTENNAS_RX]= {r_im0,r_im1}; uint8_t transmission_mode=1,n_tx_port=1,n_tx_phy=1,n_rx=2; int eNB_id = 0; unsigned char round; From db7f39ba19e10ec27d05673ab1f1a6a518327af8 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 24 May 2022 14:47:30 +0200 Subject: [PATCH 218/267] Use correct structure in sctp_eNB_accept_associations() --- openair3/SCTP/sctp_eNB_task.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openair3/SCTP/sctp_eNB_task.c b/openair3/SCTP/sctp_eNB_task.c index 06e606e36b..df6dde0f99 100644 --- a/openair3/SCTP/sctp_eNB_task.c +++ b/openair3/SCTP/sctp_eNB_task.c @@ -859,7 +859,7 @@ sctp_eNB_accept_associations( struct sctp_cnx_list_elm_s *sctp_cnx) { int client_sd; - struct sockaddr saddr; + struct sockaddr_in6 saddr; socklen_t saddr_size; DevAssert(sctp_cnx != NULL); @@ -868,14 +868,14 @@ sctp_eNB_accept_associations( /* There is a new client connecting. Accept it... */ - if ((client_sd = accept(sctp_cnx->sd, &saddr, &saddr_size)) < 0) { + if ((client_sd = accept(sctp_cnx->sd, (struct sockaddr*)&saddr, &saddr_size)) < 0) { SCTP_ERROR("[%d] accept failed: %s:%d\n", sctp_cnx->sd, strerror(errno), errno); } else { struct sctp_cnx_list_elm_s *new_cnx; uint16_t port; /* This is an ipv6 socket */ - port = ((struct sockaddr_in6*)&saddr)->sin6_port; + port = saddr.sin6_port; /* Contrary to BSD, client socket does not inherit O_NONBLOCK option */ if (fcntl(client_sd, F_SETFL, O_NONBLOCK) < 0) { From 017fd225bcd0716b1856be1584438e7b4c64a3b8 Mon Sep 17 00:00:00 2001 From: laurent Date: Sun, 29 May 2022 14:27:51 +0200 Subject: [PATCH 219/267] fix ubsan detected errors --- common/utils/time_meas.h | 4 +- .../nfapi/public_inc/fapi_nr_ue_interface.h | 2 +- .../nfapi/public_inc/nfapi_nr_interface_scf.h | 2 +- .../CODING/3gpplte_turbo_decoder_sse_8bit.c | 6 +- openair1/PHY/CODING/crc_byte.c | 4 +- .../PHY/CODING/nrLDPC_decoder/nrLDPC_cnProc.h | 45 ++++--- openair1/PHY/LTE_TRANSPORT/dci_tools_common.c | 116 +++++++++--------- openair1/PHY/LTE_TRANSPORT/dlsch_coding.c | 2 +- .../PHY/LTE_UE_TRANSPORT/transport_proto_ue.h | 8 -- openair1/PHY/LTE_UE_TRANSPORT/transport_ue.h | 2 +- openair1/PHY/LTE_UE_TRANSPORT/ulsch_coding.c | 47 +++---- openair1/PHY/MODULATION/nr_modulation.c | 7 +- .../PHY/NR_ESTIMATION/nr_measurements_gNB.c | 2 +- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 5 +- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 2 +- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 3 +- openair1/SIMULATION/LTE_PHY/dlsim.c | 16 ++- openair1/SIMULATION/LTE_PHY/ulsim.c | 14 +-- openair1/SIMULATION/NR_PHY/dlsim.c | 2 +- openair2/LAYER2/NR_MAC_UE/config_ue.c | 4 +- openair2/LAYER2/NR_MAC_UE/mac_proto.h | 7 -- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 22 ++-- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 44 ++++--- openair2/LAYER2/NR_MAC_gNB/config.c | 2 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 2 + openair2/RRC/NR_UE/rrc_UE.c | 4 +- 26 files changed, 191 insertions(+), 183 deletions(-) diff --git a/common/utils/time_meas.h b/common/utils/time_meas.h index fded7f1a9c..eb81d09434 100644 --- a/common/utils/time_meas.h +++ b/common/utils/time_meas.h @@ -62,7 +62,7 @@ typedef struct time_stats { oai_cputime_t in; /*!< \brief time at measure starting point */ oai_cputime_t diff; /*!< \brief average difference between time at starting point and time at endpoint*/ oai_cputime_t p_time; /*!< \brief absolute process duration */ - oai_cputime_t diff_square; /*!< \brief process duration square */ + double diff_square; /*!< \brief process duration square */ oai_cputime_t max; /*!< \brief maximum difference between time at starting point and time at endpoint*/ int trials; /*!< \brief number of start point - end point iterations */ int meas_flag; /*!< \brief 1: stop_meas not called (consecutive calls of start_meas) */ @@ -156,7 +156,7 @@ static inline void stop_meas(time_stats_t *ts) { ts->diff += (out-ts->in); /// process duration is the difference between two clock points ts->p_time = (out-ts->in); - ts->diff_square += (out-ts->in)*(out-ts->in); + ts->diff_square += ((double)out-ts->in)*((double)out-ts->in); if ((out-ts->in) > ts->max) ts->max = out-ts->in; diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index fd9af01720..10f881bae6 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -87,7 +87,7 @@ typedef struct { // N_CCE is L, or number of CCEs for DCI int N_CCE; uint8_t payloadSize; - uint8_t payloadBits[16]; + uint8_t payloadBits[16] __attribute__((aligned(16))); // will be cast as uint64 //fapi_nr_dci_pdu_rel15_t dci; } fapi_nr_dci_indication_pdu_t; diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index 8b564a5e37..0e393066c8 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -738,7 +738,7 @@ typedef struct { // The total DCI length (in bits) including padding bits [TS38.212 sec 7.3.1] Range 0->DCI_PAYLOAD_BYTE_LEN*8 uint16_t PayloadSizeBits; // DCI payload, where the actual size is defined by PayloadSizeBits. The bit order is as following bit0-bit7 are mapped to first byte of MSB - LSB - uint8_t Payload[DCI_PAYLOAD_BYTE_LEN]; + uint8_t Payload[DCI_PAYLOAD_BYTE_LEN] __attribute__((aligned(32))); } nfapi_nr_dl_dci_pdu_t; diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c index 264b25deca..af02a16054 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c @@ -814,7 +814,7 @@ uint8_t phy_threegpplte_turbo_decoder8(int16_t *y, llr_t *s1,*s2,*yp1,*yp2,*yp; unsigned int i,j,iind;//,pi; unsigned char iteration_cnt=0; - unsigned int crc,oldcrc,crc_len; + unsigned int crc, crc_len; uint8_t temp; #if defined(__x86_64__) || defined(__i386__) __m128i *yp128; @@ -1233,8 +1233,8 @@ uint8_t phy_threegpplte_turbo_decoder8(int16_t *y, } // check the CRC - oldcrc= *((unsigned int *)(&decoded_bytes[(n>>3)-crc_len])); - + uint32_t oldcrc; + memcpy(&oldcrc, &decoded_bytes[(n >> 3) - crc_len], crc_len); switch (crc_type) { case CRC24_A: oldcrc&=0x00ffffff; diff --git a/openair1/PHY/CODING/crc_byte.c b/openair1/PHY/CODING/crc_byte.c index 9ad18cc1a6..471b26fe24 100644 --- a/openair1/PHY/CODING/crc_byte.c +++ b/openair1/PHY/CODING/crc_byte.c @@ -244,11 +244,11 @@ crc16 (unsigned char * inptr, int bitlen) while (octetlen-- > 0) { - crc = (crc << 8) ^ (crc16Table[(*inptr++) ^ (crc >> 24)] << 16); + crc = (crc << 8) ^ (((uint32_t)crc16Table[(*inptr++) ^ (crc >> 24)]) << 16); } if (resbit > 0) - crc = (crc << resbit) ^ (crc16Table[((*inptr) >> (8 - resbit)) ^ (crc >> (32 - resbit))] << 16); + crc = (crc << resbit) ^ (((uint32_t)crc16Table[(*inptr) >> (8 - resbit) ^ (crc >> (32 - resbit))]) << 16); return crc; } diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_cnProc.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_cnProc.h index f4ea4a9434..f792f993e9 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_cnProc.h +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_cnProc.h @@ -961,7 +961,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1028,7 +1029,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1096,7 +1098,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1163,7 +1166,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1230,7 +1234,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1297,7 +1302,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1364,7 +1370,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1431,7 +1438,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1498,7 +1506,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1593,7 +1602,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG2(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1660,7 +1670,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG2(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1727,7 +1738,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG2(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1794,7 +1806,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG2(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1861,7 +1874,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG2(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1928,7 +1942,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG2(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c b/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c index 64e74ebfbf..cb2f190384 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c @@ -562,9 +562,9 @@ uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap) { case 15: if (vrb<12) { if ((vrb&3) < 2) // even: 0->0, 1->4, 4->1, 5->5, 8->2, 9->6 odd: 0->7, 1->11 - return(((7*odd_slot) + 4*(vrb&3) + (vrb>>2))%14) + 14*(vrb/14); + return(((7*odd_slot) + 4*(vrb&3) + (vrb>>2))%14) + 14*(vrb/14); else if (vrb < 12) // even: 2->7, 3->11, 6->8, 7->12, 10->9, 11->13 - return (((7*odd_slot) + 4*(vrb&3) + (vrb>>2) +13 )%14) + 14*(vrb/14); + return (((7*odd_slot) + 4*(vrb&3) + (vrb>>2) +13 )%14) + 14*(vrb/14); } if (vrb==12) return (3+(7*odd_slot)) % 14; @@ -573,6 +573,8 @@ uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap) { return 14; break; + // Formula in TS 36.211, chap 6.2.3.2 + // Fix me: returns a PRB number > 24 when vrb is 24 case 25: return (((12*odd_slot) + 6*(vrb&3) + (vrb>>2))%24) + 24*(vrb/24); break; @@ -581,43 +583,44 @@ uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap) { if (Ngap==0) { // Nrow=12,Nnull=2,NVRBDL=46,Ngap1= 27 if (vrb>=23) - offset=4; + offset=4; else - offset=0; + offset=0; if (vrb<44) { - if ((vrb&3)>=2) - return offset+((23*odd_slot) + 12*(vrb&3) + (vrb>>2) + 45)%46; - else - return offset+((23*odd_slot) + 12*(vrb&3) + (vrb>>2))%46; + if ((vrb&3)>=2) + return offset+((23*odd_slot) + 12*(vrb&3) + (vrb>>2) + 45)%46; + else + return offset+((23*odd_slot) + 12*(vrb&3) + (vrb>>2))%46; } if (vrb==44) // even: 44->11, odd: 45->34 - return offset+((23*odd_slot) + 22-12+1); + return offset+((23*odd_slot) + 22-12+1); if (vrb==45) // even: 45->10, odd: 45->33 - return offset+((23*odd_slot) + 22+12); + return offset+((23*odd_slot) + 22+12); if (vrb==46) - return offset+46+((23*odd_slot) + 23-12+1) % 46; + return offset+46+((23*odd_slot) + 23-12+1) % 46; if (vrb==47) - return offset+46+((23*odd_slot) + 23+12) % 46; + return offset+46+((23*odd_slot) + 23+12) % 46; if (vrb==48) - return offset+46+((23*odd_slot) + 23-12+1) % 46; + return offset+46+((23*odd_slot) + 23-12+1) % 46; if (vrb==49) - return offset+46+((23*odd_slot) + 23+12) % 46; + return offset+46+((23*odd_slot) + 23+12) % 46; } else { // Nrow=6,Nnull=6,NVRBDL=18,Ngap1= 27 if (vrb>=9) - offset=18; + offset=18; else - offset=0; + offset=0; if (vrb<12) { - if ((vrb&3)>=2) - return offset+((9*odd_slot) + 6*(vrb&3) + (vrb>>2) + 17)%18; - else - return offset+((9*odd_slot) + 6*(vrb&3) + (vrb>>2))%18; + if ((vrb&3)>=2) + return offset+((9*odd_slot) + 6*(vrb&3) + (vrb>>2) + 17)%18; + else + return offset+((9*odd_slot) + 6*(vrb&3) + (vrb>>2))%18; } else { - return offset+((9*odd_slot) + 12*(vrb&1)+(vrb>>1) )%18 + 18*(vrb/18); + // Same issue as for 25 PRB: returns larger than 0..49 + return ((9*odd_slot) + 12*(vrb&1) + (vrb>>1))%18 + 18*(vrb/18); } } break; @@ -677,7 +680,7 @@ void generate_RIV_tables(void) // printf("RIV %d (%d) : first_rb %d NBRB %d\n",RIV,localRIV2alloc_LUT25[RIV],RBstart,Lcrbs); localRIV2alloc_LUT6[RIV] = alloc0; - distRIV2alloc_even_LUT6[RIV] = allocdist0_0_even; + distRIV2alloc_even_LUT6[RIV] = allocdist0_0_even; distRIV2alloc_odd_LUT6[RIV] = allocdist0_0_odd; RIV2nb_rb_LUT6[RIV] = Lcrbs; RIV2first_rb_LUT6[RIV] = RBstart; @@ -693,15 +696,14 @@ void generate_RIV_tables(void) nVRB = Lcrbs-1+RBstart; //printf("RBstart %d, len %d --> ",RBstart,Lcrbs); alloc0 |= (1<RIV_max25) - RIV_max25 = RIV;; - + RIV_max25 = RIV; localRIV2alloc_LUT25[RIV] = alloc0; distRIV2alloc_even_LUT25[RIV] = allocdist0_0_even; @@ -730,37 +732,37 @@ void generate_RIV_tables(void) if (nVRB<32) - alloc0 |= (1< nVRB_even_dist %d\n",nVRB,nVRB_even_dist); - if (nVRB_even_dist<32) - allocdist0_0_even |= (1<(%08x.%08x.%08x.%08x)\n", allocdist0_0_even, @@ -845,38 +846,37 @@ void generate_RIV_tables(void) // Distributed Gap1, odd slot nVRB_odd_dist = get_prb(100,1,nVRB,0); if (nVRB_odd_dist<32) - allocdist0_0_odd |= (1<dlsch->harq_processes[harq_pid]; if ( rdata-> round == 0) { - uint8_t tmp[96+12+3+3*6144]; + uint8_t tmp[96+12+3+3*6144] __attribute__((aligned(32))); memset(tmp,LTE_NULL, TURBO_SIMD_SOFTBITS); start_meas(rdata->te_stats); encoder(rdata->input, diff --git a/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h b/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h index f5b8c6b64a..36da4ccab0 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h +++ b/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h @@ -1272,14 +1272,6 @@ uint32_t get_TBS_DL(uint8_t mcs, uint16_t nb_rb); @return Transport block size */ uint32_t get_TBS_UL(uint8_t mcs, uint16_t nb_rb); -/* \brief Return bit-map of resource allocation for a given DCI rballoc (RIV format) and vrb type - @param N_RB_DL number of PRB on DL - @param indicator for even/odd slot - @param vrb vrb index - @param Ngap Gap indicator -*/ -uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap); - /* \brief Return prb for a given vrb index @param vrb_type VRB type (0=localized,1=distributed) @param rb_alloc_dci rballoc field from DCI diff --git a/openair1/PHY/LTE_UE_TRANSPORT/transport_ue.h b/openair1/PHY/LTE_UE_TRANSPORT/transport_ue.h index b4ae44f6ea..5f8763414e 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/transport_ue.h +++ b/openair1/PHY/LTE_UE_TRANSPORT/transport_ue.h @@ -90,7 +90,7 @@ typedef struct { /// Redundancy-version of the current sub-frame uint8_t rvidx; /// Turbo-code outputs (36-212 V8.6 2009-03, p.12 - uint8_t d[MAX_NUM_ULSCH_SEGMENTS][(96+3+(3*6144))]; + uint8_t *d[MAX_NUM_ULSCH_SEGMENTS]; /// Sub-block interleaver outputs (36-212 V8.6 2009-03, p.16-17) uint8_t w[MAX_NUM_ULSCH_SEGMENTS][3*6144]; /// Number of code segments (for definition see 36-212 V8.6 2009-03, p.9) diff --git a/openair1/PHY/LTE_UE_TRANSPORT/ulsch_coding.c b/openair1/PHY/LTE_UE_TRANSPORT/ulsch_coding.c index ae3ebbce9d..c04ec160aa 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/ulsch_coding.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/ulsch_coding.c @@ -71,6 +71,7 @@ void free_ue_ulsch(LTE_UE_ULSCH_t *ulsch) { for (r=0; rharq_processes[i]->c[r]) { free16(ulsch->harq_processes[i]->c[r],((r==0)?8:0) + 3+768); + free16(ulsch->harq_processes[i]->d[r],0); ulsch->harq_processes[i]->c[r] = NULL; } } @@ -86,7 +87,7 @@ void free_ue_ulsch(LTE_UE_ULSCH_t *ulsch) { LTE_UE_ULSCH_t *new_ue_ulsch(unsigned char N_RB_UL, uint8_t abstraction_flag) { LTE_UE_ULSCH_t *ulsch; - unsigned char exit_flag = 0,i,j,r; + unsigned char exit_flag = 0; unsigned char bw_scaling =1; switch (N_RB_UL) { @@ -113,7 +114,7 @@ LTE_UE_ULSCH_t *new_ue_ulsch(unsigned char N_RB_UL, uint8_t abstraction_flag) { memset(ulsch,0,sizeof(LTE_UE_ULSCH_t)); ulsch->Mlimit = 4; - for (i=0; i<8; i++) { + for (int i=0; i<8; i++) { ulsch->harq_processes[i] = (LTE_UL_UE_HARQ_t *)malloc16(sizeof(LTE_UL_UE_HARQ_t)); // printf("ulsch->harq_processes[%d] %p\n",i,ulsch->harq_processes[i]); @@ -129,15 +130,11 @@ LTE_UE_ULSCH_t *new_ue_ulsch(unsigned char N_RB_UL, uint8_t abstraction_flag) { } if (abstraction_flag==0) { - for (r=0; rharq_processes[i]->c[r] = (unsigned char *)malloc16(((r==0)?8:0) + 3+768); // account for filler in first segment and CRCs for multiple segment case - - if (ulsch->harq_processes[i]->c[r]) - memset(ulsch->harq_processes[i]->c[r],0,((r==0)?8:0) + 3+768); - else { - LOG_E(PHY,"Can't get c\n"); - exit_flag=2; - } + for (int r=0; rharq_processes[i]->c[r] = malloc16_clear(((r==0)?8:0) + 3+768); // account for filler in first segment and CRCs for multiple segment case + AssertFatal(ulsch->harq_processes[i]->c[r], ""); + ulsch->harq_processes[i]->d[r] = malloc16_clear(96+3+(3*6144)); + AssertFatal(ulsch->harq_processes[i]->d[r], ""); } } @@ -148,15 +145,7 @@ LTE_UE_ULSCH_t *new_ue_ulsch(unsigned char N_RB_UL, uint8_t abstraction_flag) { exit_flag=3; } } - - if ((abstraction_flag == 0) && (exit_flag==0)) { - for (i=0; i<8; i++) - for (j=0; j<96; j++) - for (r=0; rharq_processes[i]->d[r][j] = LTE_NULL; - - return(ulsch); - } else if (abstraction_flag==1) + if (!exit_flag) return(ulsch); } @@ -191,7 +180,7 @@ uint32_t ulsch_encoding(uint8_t *a, uint32_t Qprime_ACK=0,Qprime_CQI=0,Qprime_RI=0,len_ACK=0,len_RI=0; // uint32_t E; uint8_t ack_parity; - uint32_t i,q,j,iprime,j2; + uint32_t q,j,iprime,j2; uint16_t o_RCC; uint8_t o_flip[8]; uint32_t wACK_idx; @@ -327,6 +316,8 @@ uint32_t ulsch_encoding(uint8_t *a, #endif // offset=0; start_meas(te_stats); + for (int z=0; z<96; z++) + ulsch->harq_processes[harq_pid]->d[r][z] = LTE_NULL; encoder(ulsch->harq_processes[harq_pid]->c[r], Kr>>3, &ulsch->harq_processes[harq_pid]->d[r][96], @@ -539,8 +530,6 @@ uint32_t ulsch_encoding(uint8_t *a, ulsch->q); } - i=0; - // Do RI coding if (ulsch->O_RI == 1) { switch (Q_m) { @@ -691,7 +680,7 @@ uint32_t ulsch_encoding(uint8_t *a, j=0; - for (i=0; i>2); for (q=0; q>2); for (q=0; qh[j++] = *yptr++; @@ -818,7 +807,7 @@ uint32_t ulsch_encoding(uint8_t *a, break; case 4: - for (i=0; ih[j++] = *yptr++; @@ -830,7 +819,7 @@ uint32_t ulsch_encoding(uint8_t *a, break; case 6: - for (i=0; ih[j++] = *yptr++; diff --git a/openair1/PHY/MODULATION/nr_modulation.c b/openair1/PHY/MODULATION/nr_modulation.c index 8ebd70fb92..1b5c4f4af0 100644 --- a/openair1/PHY/MODULATION/nr_modulation.c +++ b/openair1/PHY/MODULATION/nr_modulation.c @@ -226,10 +226,11 @@ void nr_modulation(uint32_t *in, i *= 24; bit_cnt = i * 8; while (bit_cnt < length) { - x = *((uint32_t*)(in_bytes+i)); - x1 = x&4095; + uint32_t xx; + memcpy(&xx, in_bytes+i, sizeof(xx)); + x1 = xx & 4095; out64[j++] = nr_64qam_mod_table[x1]; - x1 = (x>>12)&4095; + x1 = (xx >> 12) & 4095; out64[j++] = nr_64qam_mod_table[x1]; i += 3; bit_cnt += 24; diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index fb56322e54..93bd9587a0 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -119,7 +119,7 @@ void gNB_I0_measurements(PHY_VARS_gNB *gNB,int slot, int first_symb,int num_symb measurements->n0_subband_power[aarx][rb]=0; } int offset0 = (slot&3)*(frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size) + (frame_parms->first_carrier_offset + (rb*12))%frame_parms->ofdm_symbol_size; - if ((gNB->rb_mask_ul[s][rb>>5]&(1<<(rb&31))) == 0) { // check that rb was not used in this subframe + if ((gNB->rb_mask_ul[s][rb >> 5] & (1U << (rb & 31))) == 0) { // check that rb was not used in this subframe nb_symb[rb]++; for (int aarx=0; aarxnb_antennas_rx; aarx++) { int offset = offset0 + (s*frame_parms->ofdm_symbol_size); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index d32fd77b03..30dbc39185 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -123,7 +123,6 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, rel15->dlDmrsSymbPos); n_ptrs = (rel15->rbSize + rel15->PTRSFreqDensity - 1)/rel15->PTRSFreqDensity; } - int16_t mod_ptrs[n_ptrs<<1] __attribute__ ((aligned(16))); /// CRC, coding, interleaving and rate matching AssertFatal(harq->pdu!=NULL,"harq->pdu is null\n"); @@ -302,12 +301,14 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, /* calculate if current symbol is PTRS symbols */ ptrs_idx = 0; - + int16_t *mod_ptrs = NULL; if(rel15->pduBitmap & 0x1) { ptrs_symbol = is_ptrs_symbol(l,dlPtrsSymPos); if(ptrs_symbol) { /* PTRS QPSK Modulation for each OFDM symbol in a slot */ LOG_D(PHY,"Doing ptrs modulation for symbol %d, n_ptrs %d\n",l,n_ptrs); + int16_t mod_ptrsBuf[n_ptrs<<1] __attribute__ ((aligned(16))); + mod_ptrs =mod_ptrsBuf; nr_modulation(pdsch_dmrs[l][rel15->SCID], (n_ptrs<<1), DMRS_MOD_ORDER, mod_ptrs); } } diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 1428987d40..5c44bde4fe 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -569,7 +569,7 @@ void fill_ul_rb_mask(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { LOG_D(PHY,"symbol %d Filling rb_mask_ul rb_size %d\n",symbol,ulsch_harq->ulsch_pdu.rb_size); for (rb=0; rbulsch_pdu.rb_size; rb++) { rb2 = rb+ulsch_harq->ulsch_pdu.rb_start+ulsch_harq->ulsch_pdu.bwp_start; - gNB->rb_mask_ul[symbol][rb2>>5] |= (1<<(rb2&31)); + gNB->rb_mask_ul[symbol][rb2 >> 5] |= 1U << (rb2 & 31); } } } diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index d366ae9ec1..38fa3880bb 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -1321,8 +1321,7 @@ int is_ssb_in_slot(fapi_nr_config_request_t *config, int frame, int slot, NR_DL_ //uint8_t half_frame_index = fp->half_frame_bit; //uint8_t i_ssb = fp->ssb_index; uint8_t Lmax = fp->Lmax; - - if (!(frame%(1<<(config->ssb_table.ssb_period-1)))){ + if ((config->ssb_table.ssb_period > 0) && !(frame % (1 << (config->ssb_table.ssb_period - 1)))) { if(Lmax <= 8) { if(slot <=3 && (((config->ssb_table.ssb_mask_list[0].ssb_mask << 2*slot)&0x80000000) == 0x80000000 || ((config->ssb_table.ssb_mask_list[0].ssb_mask << (2*slot +1))&0x80000000) == 0x80000000)) diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index d715423bb1..8aff47c86b 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -512,12 +512,16 @@ int main(int argc, char **argv) { int re; int s,Kr,Kr_bytes; LTE_DL_FRAME_PARMS *frame_parms; - double s_re0[30720*NB_ANTENNAS_TX],s_im0[30720*NB_ANTENNAS_TX],r_re0[30720*NB_ANTENNAS_RX],r_im0[30720*NB_ANTENNAS_RX]; - double s_re1[30720*NB_ANTENNAS_TX],s_im1[30720*NB_ANTENNAS_TX],r_re1[30720*NB_ANTENNAS_RX],r_im1[30720*NB_ANTENNAS_RX]; - double *s_re[NB_ANTENNAS_TX]= {s_re0,s_re1}; - double *s_im[NB_ANTENNAS_TX]= {s_im0,s_im1}; - double *r_re[NB_ANTENNAS_RX]= {r_re0,r_re1}; - double *r_im[NB_ANTENNAS_RX]= {r_im0,r_im1}; + double *tmpTX[4], *tmpRX[4] ; + for (int i = 0; i < 4; i++) { + tmpTX[i] = malloc(30720 * NB_ANTENNAS_TX * sizeof(*tmpTX)); + tmpRX[i] = malloc(30720 * NB_ANTENNAS_RX * sizeof(*tmpRX)); + } + double *s_re[NB_ANTENNAS_TX] = {tmpTX[0], tmpTX[1]}; + double *s_im[NB_ANTENNAS_TX] = {tmpTX[2], tmpTX[3]}; + double *r_re[NB_ANTENNAS_RX] = {tmpRX[0], tmpRX[1]}; + double *r_im[NB_ANTENNAS_RX] = {tmpRX[2], tmpRX[3]}; + uint8_t transmission_mode=1,n_tx_port=1,n_tx_phy=1,n_rx=2; int eNB_id = 0; unsigned char round; diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index 0843d00ffd..0f98eb337a 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -358,7 +358,7 @@ int main(int argc, char **argv) { unsigned short input_buffer_length; unsigned int ret; unsigned int coded_bits_per_codeword,nsymb; - unsigned int tx_lev=0,tx_lev_dB=0,trials,errs[5]= {0,0,0,0,0},round_trials[4]= {0,0,0,0}; + unsigned int tx_lev = 0, tx_lev_dB = 0, trials, errs[6] = {0}, round_trials[4] = {0}; FILE *bler_fd=NULL; char bler_fname[512]; FILE *time_meas_fd=NULL; @@ -387,7 +387,6 @@ int main(int argc, char **argv) { double cpu_freq_GHz; int iter_trials; uint32_t UL_alloc_pdu; - int s,Kr,Kr_bytes; int dump_perf=0; static int dump_table =0; double effective_rate=0.0; @@ -1233,20 +1232,21 @@ int main(int argc, char **argv) { if (n_frames==1) { printf("ULSCH errors found o_ACK[0]= %d\n",eNB->ulsch[0]->harq_processes[harq_pid]->o_ACK[0]); - +#ifdef DUMP_EACH_VALUE + int Kr_bytes; for (s=0; sulsch[0]->harq_processes[harq_pid]->C; s++) { if (sulsch[0]->harq_processes[harq_pid]->Cminus) - Kr = eNB->ulsch[0]->harq_processes[harq_pid]->Kminus; + Kr_bytes = eNB->ulsch[0]->harq_processes[harq_pid]->Kminus; else - Kr = eNB->ulsch[0]->harq_processes[harq_pid]->Kplus; - - Kr_bytes = Kr>>3; + Kr_bytes = eNB->ulsch[0]->harq_processes[harq_pid]->Kplus; + Kr_bytes = Kr_bytes >> 3; printf("Decoded_output (Segment %d):\n",s); for (i=0; iulsch[0]->harq_processes[harq_pid]->c[s][i], eNB->ulsch[0]->harq_processes[harq_pid]->c[s][i]^UE->ulsch[0]->harq_processes[harq_pid]->c[s][i]); } +#endif dump_ulsch(eNB,eNB->proc.frame_rx,subframe,0,round); round=5; diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 78b253ca2a..8500749fe2 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -1142,7 +1142,7 @@ int main(int argc, char **argv) Sched_INFO.frame = frame; Sched_INFO.slot = slot; Sched_INFO.DL_req = &gNB_mac->DL_req[0]; - Sched_INFO.UL_tti_req = gNB_mac->UL_tti_req_ahead[slot]; + Sched_INFO.UL_tti_req = gNB_mac->UL_tti_req_ahead[0]; Sched_INFO.UL_dci_req = NULL; Sched_INFO.TX_req = &gNB_mac->TX_req[0]; pushNotifiedFIFO(gNB->L1_tx_free,msgL1Tx); diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 072f0e58de..2804a9ec1e 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -190,7 +190,7 @@ void config_common_ue_sa(NR_UE_MAC_INST_t *mac, cfg->ssb_table.ssb_subcarrier_offset = mac->ssb_subcarrier_offset; if (mac->frequency_range == FR1){ - cfg->ssb_table.ssb_mask_list[0].ssb_mask = scc->ssb_PositionsInBurst.inOneGroup.buf[0]<<24; + cfg->ssb_table.ssb_mask_list[0].ssb_mask = ((uint32_t) scc->ssb_PositionsInBurst.inOneGroup.buf[0]) << 24; cfg->ssb_table.ssb_mask_list[1].ssb_mask = 0; } else{ @@ -353,7 +353,7 @@ void config_common_ue(NR_UE_MAC_INST_t *mac, cfg->ssb_table.ssb_mask_list[1].ssb_mask = 0; break; case 2 : - cfg->ssb_table.ssb_mask_list[0].ssb_mask = scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0]<<24; + cfg->ssb_table.ssb_mask_list[0].ssb_mask = ((uint32_t) scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0]) << 24; cfg->ssb_table.ssb_mask_list[1].ssb_mask = 0; break; case 3 : diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 38f774be76..aa68791466 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -257,13 +257,6 @@ void get_bwp_info(NR_UE_MAC_INST_t *mac, NR_BWP_DownlinkCommon_t *get_bwp_downlink_common(NR_UE_MAC_INST_t *mac, NR_BWP_Id_t dl_bwp_id); -uint8_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac, - uint8_t dci_format, - uint8_t dci_length, - uint16_t rnti, - uint64_t *dci_pdu, - dci_pdu_rel15_t *nr_pdci_info_extracted); - NR_PUSCH_TimeDomainResourceAllocationList_t *choose_ul_tda_list(const NR_PUSCH_Config_t *pusch_Config,NR_PUSCH_ConfigCommon_t *pusch_ConfigCommon); NR_PDSCH_TimeDomainResourceAllocationList_t *choose_dl_tda_list(NR_PDSCH_Config_t *pdsch_Config,NR_PDSCH_ConfigCommon_t *pdsch_ConfigCommon); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 6166fc7038..ccb1b4e72a 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -134,6 +134,13 @@ const initial_pucch_resource_t initial_pucch_resource[16] = { }; +static uint8_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac, + uint8_t dci_format, + uint8_t dci_length, + uint16_t rnti, + uint64_t *dci_pdu, + dci_pdu_rel15_t *nr_pdci_info_extracted); + void nr_ue_init_mac(module_id_t module_idP) { int i; @@ -985,7 +992,8 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr if (dci->tpc == 3) dlsch_config_pdu_1_0->accumulated_delta_PUCCH = 3; // Sanity check for pucch_resource_indicator value received to check for false DCI. valid = 0; - if (mac->ULbwp[ul_bwp_id-1] && + if (ul_bwp_id > 0 && + mac->ULbwp[ul_bwp_id-1] && mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated && mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pucch_Config && mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pucch_Config->choice.setup&& @@ -1512,13 +1520,12 @@ void nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, NR_BWP_UplinkCommon_t *initialUplinkBWP; if (mac->scc) initialUplinkBWP = mac->scc->uplinkConfigCommon->initialUplinkBWP; else initialUplinkBWP = &mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP; - NR_BWP_Uplink_t *ubwp = mac->ULbwp[bwp_id-1]; - if (mac->cg && ubwp && + if (mac->cg && bwp_id > 1 && mac->ULbwp[bwp_id - 1] && mac->cg->spCellConfig && mac->cg->spCellConfig->spCellConfigDedicated && mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig && mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { - scs = ubwp->bwp_Common->genericParameters.subcarrierSpacing; + scs = mac->ULbwp[bwp_id - 1]->bwp_Common->genericParameters.subcarrierSpacing; } else scs = initialUplinkBWP->genericParameters.subcarrierSpacing; @@ -2340,17 +2347,16 @@ bool trigger_periodic_scheduling_request(NR_UE_MAC_INST_t *mac, NR_BWP_Id_t bwp_id = mac->UL_BWP_Id; NR_PUCCH_Config_t *pucch_Config = NULL; int scs; - NR_BWP_Uplink_t *ubwp = mac->ULbwp[bwp_id-1]; NR_BWP_UplinkCommon_t *initialUplinkBWP; if (mac->scc) initialUplinkBWP = mac->scc->uplinkConfigCommon->initialUplinkBWP; else initialUplinkBWP = &mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP; - if (mac->cg && ubwp && + if (mac->cg && bwp_id && mac->ULbwp[bwp_id - 1] && mac->cg->spCellConfig && mac->cg->spCellConfig->spCellConfigDedicated && mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig && mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { - scs = ubwp->bwp_Common->genericParameters.subcarrierSpacing; + scs = mac->ULbwp[bwp_id - 1]->bwp_Common->genericParameters.subcarrierSpacing; } else scs = initialUplinkBWP->genericParameters.subcarrierSpacing; @@ -2732,7 +2738,7 @@ int get_n_rb(NR_UE_MAC_INST_t *mac, int rnti_type){ } -uint8_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac, +static uint8_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac, uint8_t dci_format, uint8_t dci_size, uint16_t rnti, diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index f6a42ccaab..49b8e3d05f 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -118,12 +118,13 @@ long get_k2(NR_UE_MAC_INST_t *mac, uint8_t time_domain_ind) { NR_BWP_Id_t ul_bwp_id = mac->UL_BWP_Id; // Get K2 from RRC configuration - NR_PUSCH_Config_t *pusch_config=mac->ULbwp[ul_bwp_id-1] ? mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pusch_Config->choice.setup : NULL; + NR_PUSCH_Config_t *pusch_config= ul_bwp_id > 0 && mac->ULbwp[ul_bwp_id-1] ? mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pusch_Config->choice.setup : NULL; NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = NULL; if (pusch_config && pusch_config->pusch_TimeDomainAllocationList) { pusch_TimeDomainAllocationList = pusch_config->pusch_TimeDomainAllocationList->choice.setup; } - else if (mac->ULbwp[ul_bwp_id-1] && + else if (ul_bwp_id > 0 && + mac->ULbwp[ul_bwp_id-1] && mac->ULbwp[ul_bwp_id-1]->bwp_Common&& mac->ULbwp[ul_bwp_id-1]->bwp_Common->pusch_ConfigCommon&& mac->ULbwp[ul_bwp_id-1]->bwp_Common->pusch_ConfigCommon->choice.setup && @@ -169,7 +170,7 @@ fapi_nr_ul_config_request_t *get_ul_config_request(NR_UE_MAC_INST_t *mac, int sl // Calculate the index of the UL slot in mac->ul_config_request list. This is // based on the TDD pattern (slot configuration period) and number of UL+mixed // slots in the period. TS 38.213 Sec 11.1 - int mu = mac->ULbwp[ul_bwp_id-1] ? + int mu = ul_bwp_id > 0 && mac->ULbwp[ul_bwp_id-1] ? mac->ULbwp[ul_bwp_id-1]->bwp_Common->genericParameters.subcarrierSpacing : mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.genericParameters.subcarrierSpacing; const int n = nr_slots_per_frame[mu]; @@ -205,7 +206,7 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con srs_config = mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->srs_Config->choice.setup; } - NR_PUSCH_Config_t *pusch_Config = mac->ULbwp[ul_bwp_id-1] ? + NR_PUSCH_Config_t *pusch_Config = ul_bwp_id > 0 && mac->ULbwp[ul_bwp_id-1] ? mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pusch_Config->choice.setup : (ubwpd? ubwpd->pusch_Config->choice.setup: @@ -361,7 +362,7 @@ void ul_ports_config(NR_UE_MAC_INST_t *mac, int *n_front_load_symb, nfapi_nr_ue_ mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) ubwpd = mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; - NR_PUSCH_Config_t *pusch_Config = mac->ULbwp[ul_bwp_id-1] ? mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pusch_Config->choice.setup : (ubwpd?ubwpd->pusch_Config->choice.setup:NULL); + NR_PUSCH_Config_t *pusch_Config = ul_bwp_id > 0 && mac->ULbwp[ul_bwp_id-1] ? mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pusch_Config->choice.setup : (ubwpd?ubwpd->pusch_Config->choice.setup:NULL); AssertFatal(pusch_Config!=NULL,"pusch_Config shouldn't be null\n"); long transformPrecoder; @@ -581,7 +582,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, if (rar_grant) { // Note: for Msg3 or MsgA PUSCH transmission the N_PRB_oh is always set to 0 - NR_BWP_Uplink_t *ubwp = mac->ULbwp[ul_bwp_id-1]; + NR_BWP_Uplink_t *ubwp = ul_bwp_id > 0 ? mac->ULbwp[ul_bwp_id - 1] : NULL; NR_BWP_UplinkDedicated_t *ibwp; int scs,abwp_start,abwp_size,startSymbolAndLength,mappingtype; NR_PUSCH_Config_t *pusch_Config=NULL; @@ -839,11 +840,15 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, mappingtype, add_pos, dmrslength, pusch_config_pdu->start_symbol_index, mac->scc ? mac->scc->dmrs_TypeA_Position : mac->mib->dmrs_TypeA_Position); - if (mac->ULbwp[ul_bwp_id-1] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled) { - if (*dci_format != NR_UL_DCI_FORMAT_0_1) { - pusch_config_pdu->num_dmrs_cdm_grps_no_data = 1; - } - } else if (*dci_format == NR_UL_DCI_FORMAT_0_0 || (mac->ULbwp[ul_bwp_id-1] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled)) { + if (ul_bwp_id > 0 && + mac->ULbwp[ul_bwp_id - 1] && + pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled && + *dci_format != NR_UL_DCI_FORMAT_0_1) { + pusch_config_pdu->num_dmrs_cdm_grps_no_data = 1; + } else if (*dci_format == NR_UL_DCI_FORMAT_0_0 || + (ul_bwp_id > 0 && + mac->ULbwp[ul_bwp_id-1] && + pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled)) { pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; } @@ -859,7 +864,8 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, else N_PRB_oh = 0; /* PTRS */ - if (mac->ULbwp[ul_bwp_id-1] && + if (ul_bwp_id > 0 && + mac->ULbwp[ul_bwp_id-1] && mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated && mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pusch_Config && mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pusch_Config->choice.setup && @@ -1086,9 +1092,10 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in dcireq.dl_config_req = mac->dl_config_request; fill_scheduled_response(&scheduled_response, &dcireq.dl_config_req, NULL, NULL, mod_id, cc_id, rx_frame, rx_slot, dl_info->thread_id, dl_info->phy_data); - if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL) + if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL) { LOG_D(NR_MAC,"1# scheduled_response transmitted, %d, %d\n", rx_frame, rx_slot); - mac->if_module->scheduled_response(&scheduled_response); + mac->if_module->scheduled_response(&scheduled_response); + } } else { // this is for Msg2/Msg4 @@ -1557,15 +1564,14 @@ int nr_ue_pusch_scheduler(NR_UE_MAC_INST_t *mac, int delta = 0; NR_BWP_Id_t ul_bwp_id = mac->UL_BWP_Id; - NR_BWP_Uplink_t *ubwp = mac->ULbwp[ul_bwp_id-1]; // Get the numerology to calculate the Tx frame and slot - int mu = ubwp ? - ubwp->bwp_Common->genericParameters.subcarrierSpacing : + int mu = ul_bwp_id > 0 && mac->ULbwp[ul_bwp_id-1] ? + mac->ULbwp[ul_bwp_id-1]->bwp_Common->genericParameters.subcarrierSpacing : mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.genericParameters.subcarrierSpacing; - NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = ubwp ? - ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList: + NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = ul_bwp_id > 0 && mac->ULbwp[ul_bwp_id-1] ? + mac->ULbwp[ul_bwp_id-1]->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList: mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; // k2 as per 3GPP TS 38.214 version 15.9.0 Release 15 ch 6.1.2.1.1 // PUSCH time domain resource allocation is higher layer configured from uschTimeDomainAllocationList in either pusch-ConfigCommon diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 218b75b2e8..20ac69ce55 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -366,7 +366,7 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, int pusch_AntennaPorts, cfg->ssb_table.ssb_mask_list[1].ssb_mask.value = 0; break; case 2 : - cfg->ssb_table.ssb_mask_list[0].ssb_mask.value = scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0]<<24; + cfg->ssb_table.ssb_mask_list[0].ssb_mask.value = ((uint32_t) scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0]) << 24; cfg->ssb_table.ssb_mask_list[1].ssb_mask.value = 0; break; case 3 : diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index d9a0a50b7e..d32709e731 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1349,6 +1349,8 @@ void nr_schedule_ue_spec(module_id_t module_id, header->L = htons(bufEnd-buf); dlsch_total_bytes += bufEnd-buf; + for (; ((intptr_t)buf) % 4; buf++) + *buf = lrand48() & 0xff; for (; buf < bufEnd - 3; buf += 4) { uint32_t *buf32 = (uint32_t *)buf; *buf32 = lrand48(); diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 078f7f51a1..53817af48e 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -1320,11 +1320,11 @@ nr_rrc_ue_process_masterCellGroup( //TODO (perform SCell addition/modification as specified in 5.3.5.5.9) } - if( cellGroupConfig->ext2->bh_RLC_ChannelToReleaseList_r16 != NULL){ + if(cellGroupConfig->ext2 != NULL && cellGroupConfig->ext2->bh_RLC_ChannelToReleaseList_r16 != NULL){ //TODO (perform the BH RLC channel addition/modification as specified in 5.3.5.5.11) } - if( cellGroupConfig->ext2->bh_RLC_ChannelToAddModList_r16 != NULL){ + if(cellGroupConfig->ext2 != NULL && cellGroupConfig->ext2->bh_RLC_ChannelToAddModList_r16 != NULL){ //TODO (perform the BH RLC channel addition/modification as specified in 5.3.5.5.11) } } From ab36474811d591303eb8f7f24db9fe39a0b0bdc8 Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 4 Jul 2022 19:32:33 +0200 Subject: [PATCH 220/267] dirty workaround in LTE get_prb(): it is not good, but keep safe in memory instead of writing outside the range --- openair1/PHY/LTE_TRANSPORT/dci_tools_common.c | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c b/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c index cb2f190384..0addfdf14c 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c @@ -532,9 +532,12 @@ uint32_t conv_1C_RIV(int32_t rballoc,uint32_t N_RB_DL) { } +// FIXME: this function is compting PRB outside the range, so I FORCED in the range +// I can't understand the 3GPP spec, see below note uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap) { int offset; + int ret=-1; switch (N_RB_DL) { @@ -545,16 +548,16 @@ uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap) { switch (vrb) { case 0: // even: 0->0, 1->2, odd: 0->3, 1->5 case 1: - return ((3*odd_slot) + 2*(vrb&3))%6; + ret= ((3*odd_slot) + 2*(vrb&3))%6; break; case 2: // even: 2->3, 3->5, odd: 2->0, 3->2 case 3: - return ((3*odd_slot) + 2*(vrb&3) + 5)%6; + ret= ((3*odd_slot) + 2*(vrb&3) + 5)%6; break; case 4: // even: 4->1, odd: 4->4 - return ((3*odd_slot) + 1)%6; + ret= ((3*odd_slot) + 1)%6; case 5: // even: 5->4, odd: 5->1 - return ((3*odd_slot) + 4)%6; + ret= ((3*odd_slot) + 4)%6; break; } break; @@ -562,21 +565,21 @@ uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap) { case 15: if (vrb<12) { if ((vrb&3) < 2) // even: 0->0, 1->4, 4->1, 5->5, 8->2, 9->6 odd: 0->7, 1->11 - return(((7*odd_slot) + 4*(vrb&3) + (vrb>>2))%14) + 14*(vrb/14); + ret= (((7*odd_slot) + 4*(vrb&3) + (vrb>>2))%14) + 14*(vrb/14); else if (vrb < 12) // even: 2->7, 3->11, 6->8, 7->12, 10->9, 11->13 - return (((7*odd_slot) + 4*(vrb&3) + (vrb>>2) +13 )%14) + 14*(vrb/14); + ret= (((7*odd_slot) + 4*(vrb&3) + (vrb>>2) +13 )%14) + 14*(vrb/14); } if (vrb==12) - return (3+(7*odd_slot)) % 14; + ret= (3+(7*odd_slot)) % 14; if (vrb==13) - return (10+(7*odd_slot)) % 14; - return 14; + ret= (10+(7*odd_slot)) % 14; + ret= 14; break; // Formula in TS 36.211, chap 6.2.3.2 // Fix me: returns a PRB number > 24 when vrb is 24 case 25: - return (((12*odd_slot) + 6*(vrb&3) + (vrb>>2))%24) + 24*(vrb/24); + ret= (((12*odd_slot) + 6*(vrb&3) + (vrb>>2))%24) + 24*(vrb/24); break; case 50: // P=3 @@ -588,22 +591,22 @@ uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap) { offset=0; if (vrb<44) { if ((vrb&3)>=2) - return offset+((23*odd_slot) + 12*(vrb&3) + (vrb>>2) + 45)%46; + ret= offset+((23*odd_slot) + 12*(vrb&3) + (vrb>>2) + 45)%46; else - return offset+((23*odd_slot) + 12*(vrb&3) + (vrb>>2))%46; + ret= offset+((23*odd_slot) + 12*(vrb&3) + (vrb>>2))%46; } if (vrb==44) // even: 44->11, odd: 45->34 - return offset+((23*odd_slot) + 22-12+1); + ret= offset+((23*odd_slot) + 22-12+1); if (vrb==45) // even: 45->10, odd: 45->33 - return offset+((23*odd_slot) + 22+12); + ret= offset+((23*odd_slot) + 22+12); if (vrb==46) - return offset+46+((23*odd_slot) + 23-12+1) % 46; + ret= offset+46+((23*odd_slot) + 23-12+1) % 46; if (vrb==47) - return offset+46+((23*odd_slot) + 23+12) % 46; + ret= offset+46+((23*odd_slot) + 23+12) % 46; if (vrb==48) - return offset+46+((23*odd_slot) + 23-12+1) % 46; + ret= offset+46+((23*odd_slot) + 23-12+1) % 46; if (vrb==49) - return offset+46+((23*odd_slot) + 23+12) % 46; + ret= offset+46+((23*odd_slot) + 23+12) % 46; } else { // Nrow=6,Nnull=6,NVRBDL=18,Ngap1= 27 @@ -614,39 +617,38 @@ uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap) { if (vrb<12) { if ((vrb&3)>=2) - return offset+((9*odd_slot) + 6*(vrb&3) + (vrb>>2) + 17)%18; + ret= offset+((9*odd_slot) + 6*(vrb&3) + (vrb>>2) + 17)%18; else - return offset+((9*odd_slot) + 6*(vrb&3) + (vrb>>2))%18; + ret= offset+((9*odd_slot) + 6*(vrb&3) + (vrb>>2))%18; } else { - // Same issue as for 25 PRB: returns larger than 0..49 - return ((9*odd_slot) + 12*(vrb&1) + (vrb>>1))%18 + 18*(vrb/18); + ret= offset+((9*odd_slot) + 12*(vrb&1)+(vrb>>1) )%18 + 18*(vrb/18); } } break; case 75: // Ngap1 = 32, NVRBRL=64, P=4, Nrow= 16, Nnull=0 if (Ngap ==0) { - return ((32*odd_slot) + 16*(vrb&3) + (vrb>>2))%64 + (vrb/64); + ret= ((32*odd_slot) + 16*(vrb&3) + (vrb>>2))%64 + (vrb/64); } else { // Ngap2 = 16, NVRBDL=32, Nrow=8, Nnull=0 - return ((16*odd_slot) + 8*(vrb&3) + (vrb>>2))%32 + (vrb/32); + ret= ((16*odd_slot) + 8*(vrb&3) + (vrb>>2))%32 + (vrb/32); } break; case 100: // Ngap1 = 48, NVRBDL=96, Nrow=24, Nnull=0 if (Ngap ==0) { - return ((48*odd_slot) + 24*(vrb&3) + (vrb>>2))%96 + (vrb/96); + ret= ((48*odd_slot) + 24*(vrb&3) + (vrb>>2))%96 + (vrb/96); } else { // Ngap2 = 16, NVRBDL=32, Nrow=8, Nnull=0 - return ((16*odd_slot) + 8*(vrb&3) + (vrb>>2))%32 + (vrb/32); + ret= ((16*odd_slot) + 8*(vrb&3) + (vrb>>2))%32 + (vrb/32); } break; default: LOG_E(PHY,"Unknown N_RB_DL %d\n",N_RB_DL); - return 0; + ret= 0; } - return 0; + return ret%N_RB_DL; } From b1a3cbb068eeeac04a0c14ccbba7d6c28cc491bc Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Wed, 20 Jul 2022 12:55:17 +0100 Subject: [PATCH 221/267] Fix segmentation fault when changing BWP --- openair2/RRC/NR/rrc_gNB.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 400be0bd4d..648df1a306 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1949,7 +1949,7 @@ int nr_rrc_reconfiguration_req(rrc_gNB_ue_context_t *const ue_context_pP NULL, NULL, NULL, - NULL, + ue_context_pP, NULL, NULL, NULL, From 667b8e5eed245e55927a92dc15ed976bef51a089 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 21 Jul 2022 09:04:29 +0200 Subject: [PATCH 222/267] nr_pdcp: nia1 implementation We reuse existing code from eia1 for actual computation. Maybe not the most efficient. To be revised if needed. Some hacks in CMakeLists.txt were introduced to compile phy simulators. To be removed at some point. --- cmake_targets/CMakeLists.txt | 8 +++ openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c | 20 ++++-- .../LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.c | 66 +++++++++++++++++++ .../LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.h | 34 ++++++++++ 4 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.c create mode 100644 openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 25e10931c7..ef9e22e7ee 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1804,7 +1804,15 @@ set(NR_PDCP_SRC ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_timer_thread.c ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_security_nea2.c ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_integrity_nia2.c + ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.c ${OPENAIR2_DIR}/LAYER2/nr_pdcp/asn1_utils.c + #hack: include these files to compile the nr phy simulators + #these files should not be here, will be removed at some point when the + #computation is done directly inside nr_pdcp_integrity_nia1.c instead + #of reusing code of osa_stream_eia.c + ${OPENAIR2_DIR}/UTIL/OSA/osa_stream_eia.c + ${OPENAIR2_DIR}/UTIL/OSA/osa_snow3g.c + ${OPENAIR2_DIR}/UTIL/OSA/osa_rijndael.c ) set(NR_SDAP_SRC diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c index 7e1ddb62bd..480b651593 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c @@ -27,6 +27,7 @@ #include "nr_pdcp_security_nea2.h" #include "nr_pdcp_integrity_nia2.h" +#include "nr_pdcp_integrity_nia1.h" #include "nr_pdcp_sdu.h" #include "LOG/log.h" @@ -240,16 +241,21 @@ static void nr_pdcp_entity_set_security(nr_pdcp_entity_t *entity, } if (integrity_algorithm != 0 && integrity_algorithm != -1) { - if (integrity_algorithm != 2) { - LOG_E(PDCP, "FATAL: only nia2 supported for the moment\n"); - exit(1); - } entity->has_integrity = 1; if (entity->free_integrity != NULL) entity->free_integrity(entity->integrity_context); - entity->integrity_context = nr_pdcp_integrity_nia2_init(entity->integrity_key); - entity->integrity = nr_pdcp_integrity_nia2_integrity; - entity->free_integrity = nr_pdcp_integrity_nia2_free_integrity; + if (integrity_algorithm == 2) { + entity->integrity_context = nr_pdcp_integrity_nia2_init(entity->integrity_key); + entity->integrity = nr_pdcp_integrity_nia2_integrity; + entity->free_integrity = nr_pdcp_integrity_nia2_free_integrity; + } else if (integrity_algorithm == 1) { + entity->integrity_context = nr_pdcp_integrity_nia1_init(entity->integrity_key); + entity->integrity = nr_pdcp_integrity_nia1_integrity; + entity->free_integrity = nr_pdcp_integrity_nia1_free_integrity; + } else { + LOG_E(PDCP, "FATAL: only nia1 and nia2 supported for the moment\n"); + exit(1); + } } if (ciphering_algorithm == 0) { diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.c new file mode 100644 index 0000000000..08ec959937 --- /dev/null +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.c @@ -0,0 +1,66 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "nr_pdcp_integrity_nia1.h" + +#include +#include +#include +#include + +#include "UTIL/OSA/osa_defs.h" + +int stream_compute_integrity_eia1(stream_cipher_t *stream_cipher, uint8_t out[4]); + +void *nr_pdcp_integrity_nia1_init(unsigned char *integrity_key) +{ + stream_cipher_t *ret; + + ret = calloc(1, sizeof(*ret)); if (ret == NULL) abort(); + ret->key = malloc(16); if (ret->key == NULL) abort(); + memcpy(ret->key, integrity_key, 16); + ret->key_length = 16; /* unused */ + + return ret; +} + +void nr_pdcp_integrity_nia1_integrity(void *integrity_context, + unsigned char *out, + unsigned char *buffer, int length, + int bearer, int count, int direction) +{ + stream_cipher_t *ctx = integrity_context; + + ctx->message = buffer; + ctx->count = count; + ctx->bearer = bearer-1; + ctx->direction = direction; + ctx->blength = length * 8; + + stream_compute_integrity_eia1(ctx, out); +} + +void nr_pdcp_integrity_nia1_free_integrity(void *integrity_context) +{ + stream_cipher_t *ctx = integrity_context; + free(ctx->key); + free(ctx); +} diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.h new file mode 100644 index 0000000000..5c44bad4a7 --- /dev/null +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.h @@ -0,0 +1,34 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _NR_PDCP_INTEGRITY_NIA1_H_ +#define _NR_PDCP_INTEGRITY_NIA1_H_ + +void *nr_pdcp_integrity_nia1_init(unsigned char *integrity_key); + +void nr_pdcp_integrity_nia1_integrity(void *integrity_context, + unsigned char *out, + unsigned char *buffer, int length, + int bearer, int count, int direction); + +void nr_pdcp_integrity_nia1_free_integrity(void *integrity_context); + +#endif /* _NR_PDCP_INTEGRITY_NIA1_H_ */ From 3c2375eadab4a508f85e0fcda7c7524b25b59067 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 21 Jul 2022 17:57:20 +0200 Subject: [PATCH 223/267] CI: do not trigger tests if nothing is tagged NSA The previous version would trigger sub-pipelines (LTE-2x2, ...) if no MR had the NSA tag (without a commit, etc). Of course, this would make all pipelines subsequently fail (as not enough arguments, such as the commit, were given). In this commit, we read the output of `jq` from JSON, which will result in an empty list if no MR is tagged with the NSA label (and the output in the console will be nicer as well). --- ci-scripts/Jenkinsfile-trig-nsa | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/ci-scripts/Jenkinsfile-trig-nsa b/ci-scripts/Jenkinsfile-trig-nsa index 3616b2c404..8e81b75e58 100644 --- a/ci-scripts/Jenkinsfile-trig-nsa +++ b/ci-scripts/Jenkinsfile-trig-nsa @@ -20,6 +20,9 @@ * contact@openairinterface.org */ +// necessary for reading JSON +import groovy.json.JsonSlurper + // Template Jenkins Declarative Pipeline script to run Test w/ RF HW // Location of the python executor node shall be in the same subnet as the others servers @@ -37,12 +40,12 @@ pipeline { stages { stage ("Launcher") { steps { - script { - //retrieve MR that are opened nd with tag NSA - MR_LIST= sh returnStdout: true, script: 'curl --silent "https://gitlab.eurecom.fr/api/v4/projects/oai%2Fopenairinterface5g/merge_requests?state=opened&per_page=100&labels=NSA" | jq ".[].iid" || true ' - echo "List of selected MR:\n${MR_LIST}" - def MR_ARRAY = MR_LIST.split('\n') - //for every selected MR, retrieve the branch name and the latest commit + script { + // retrieve MR that are opened nd with tag NSA + MR_LIST = sh returnStdout: true, script: 'curl --silent "https://gitlab.eurecom.fr/api/v4/projects/oai%2Fopenairinterface5g/merge_requests?state=opened&per_page=100&labels=NSA" | jq -cj "[.[].iid]"' + echo "List of selected MRs: ${MR_LIST.trim()}" + def MR_ARRAY = new JsonSlurper().parseText(MR_LIST.trim()) + // for every selected MR, retrieve the branch name and the latest commit for (MR in MR_ARRAY) { SRC_BRANCH=sh returnStdout: true, script: """curl --silent "https://gitlab.eurecom.fr/api/v4/projects/oai%2Fopenairinterface5g/merge_requests/${MR}" | jq ".source_branch" || true """ SRC_BRANCH=SRC_BRANCH.trim() From 228bd5f16d86d4ebc8d2a6777379455e22346e39 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 22 Jul 2022 17:01:47 +0200 Subject: [PATCH 224/267] fix for ssb subcarrier offset in case of <3GHz --- openair2/LAYER2/NR_MAC_gNB/config.c | 2 +- openair2/RRC/NR/MESSAGES/asn1_msg.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 4daddbf03a..a79748238f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -337,7 +337,7 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, int pusch_AntennaPorts, // SSB Table Configuration uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); const int scaling_5khz = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA < 600000 ? 3 : 1; - int sco = (absolute_diff*scaling_5khz) % 24; + int sco = (absolute_diff/scaling_5khz) % 24; if(frequency_range == FR2) sco >>= 1; // this assumes 120kHz SCS for SSB and subCarrierSpacingCommon (only option supported by OAI for const int scs_scaling = frequency_range == FR2 ? 1 << (*scc->ssbSubcarrierSpacing - 2) : 1 << *scc->ssbSubcarrierSpacing; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index a93d2a8623..ff139c9895 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -230,7 +230,7 @@ uint8_t do_MIB_NR(gNB_RRC_INST *rrc,uint32_t frame) { if (get_softmodem_params()->sa) { uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); int scs_scaling = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA < 600000 ? 3 : 1; - ssb_subcarrier_offset = (absolute_diff*scs_scaling)%24; + ssb_subcarrier_offset = (absolute_diff/scs_scaling)%24; if(frequency_range == FR2) ssb_subcarrier_offset >>= 1; // this assumes 120kHz SCS for SSB and subCarrierSpacingCommon (only option supported by OAI for now) } From e1798745ef70265baa7fd8809980e31725fc0dcb Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 19 Jul 2022 18:21:28 +0200 Subject: [PATCH 225/267] Dynamically build L2sim proxy --- ci-scripts/Jenkinsfile-push-registry | 2 +- ci-scripts/Jenkinsfile-tmp-multi-enb | 187 +++++++++++++++++- ci-scripts/cls_containerize.py | 119 +++++++++++ ci-scripts/main.py | 7 +- ci-scripts/xml_class_list.yml | 1 + .../xml_files/container_5g_l2sim_proxy.xml | 42 ++++ 6 files changed, 354 insertions(+), 4 deletions(-) create mode 100644 ci-scripts/xml_files/container_5g_l2sim_proxy.xml diff --git a/ci-scripts/Jenkinsfile-push-registry b/ci-scripts/Jenkinsfile-push-registry index bc1a80ba61..feb1807c91 100644 --- a/ci-scripts/Jenkinsfile-push-registry +++ b/ci-scripts/Jenkinsfile-push-registry @@ -66,7 +66,7 @@ pipeline { withCredentials([ [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.DH_Credentials}", usernameVariable: 'DH_Username', passwordVariable: 'DH_Password'] ]) { - def listOfImages = ["oai-enb", "oai-gnb", "oai-lte-ue", "oai-nr-ue"] + def listOfImages = ["oai-enb", "oai-gnb", "oai-lte-ue", "oai-nr-ue", "proxy"] sh "docker login -u ${DH_Username} -p ${DH_Password} > /dev/null 2>&1" listOfImages.eachWithIndex { item, iindex -> sh "docker image tag ${item}:develop ${DH_Account}/${item}:develop" diff --git a/ci-scripts/Jenkinsfile-tmp-multi-enb b/ci-scripts/Jenkinsfile-tmp-multi-enb index c3b825ec06..fb52316920 100644 --- a/ci-scripts/Jenkinsfile-tmp-multi-enb +++ b/ci-scripts/Jenkinsfile-tmp-multi-enb @@ -36,6 +36,9 @@ def testStageName = params.pipelineTestStageName // Name of the phone resource def ciSmartPhoneResource = params.smartphonesResource +// Name of the phone resource +def ciEpcResource = params.epcResource + // Global Parameters. Normally they should be populated when the master job // triggers the slave job with parameters def eNB_Repository @@ -51,7 +54,7 @@ pipeline { options { disableConcurrentBuilds() ansiColor('xterm') - lock (ciSmartPhoneResource) + lock(extra: [[resource: ciEpcResource]], resource: ciSmartPhoneResource) } stages { stage ("Verify Parameters") { @@ -216,6 +219,76 @@ pipeline { } } } + stage ("Terminate") { + parallel { + stage('Terminate UE') { + // Bypassing this stage if there are no abd server defined + when { + expression { params.ADB_IPAddress != "none" } + } + steps { + echo '\u2705 \u001B[32mTerminate UE\u001B[0m' + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.ADB_Credentials}", usernameVariable: 'ADB_Username', passwordVariable: 'ADB_Password'] + ]) { + sh "python3 ci-scripts/main.py --mode=TerminateUE --ADBIPAddress=${params.ADB_IPAddress} --ADBUserName=${ADB_Username} --ADBPassword=${ADB_Password}" + } + } + } + stage('Terminate eNB') { + steps { + echo '\u2705 \u001B[32mTerminate eNB\u001B[0m' + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] + ]) { + sh "python3 ci-scripts/main.py --mode=TerminateeNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}" + } + } + } + stage('Terminate SPGW') { + // Bypassing this stage if EPC server is not defined + when { + expression { params.EPC_IPAddress != "none" } + } + steps { + echo '\u2705 \u001B[32mTerminate SPGW\u001B[0m' + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'] + ]) { + sh "python3 ci-scripts/main.py --mode=TerminateSPGW --EPCIPAddress=${params.EPC_IPAddress} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCType=${params.EPC_Type} --EPCSourceCodePath=${params.EPC_SourceCodePath}" + } + } + } + stage('Terminate MME') { + // Bypassing this stage if EPC server is not defined + when { + expression { params.EPC_IPAddress != "none" } + } + steps { + echo '\u2705 \u001B[32mTerminate MME\u001B[0m' + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'] + ]) { + sh "python3 ci-scripts/main.py --mode=TerminateMME --EPCIPAddress=${params.EPC_IPAddress} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCType=${params.EPC_Type} --EPCSourceCodePath=${params.EPC_SourceCodePath}" + } + } + } + stage('Terminate HSS') { + // Bypassing this stage if EPC server is not defined + when { + expression { params.EPC_IPAddress != "none" } + } + steps { + echo '\u2705 \u001B[32mTerminate HSS\u001B[0m' + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'] + ]) { + sh "python3 ci-scripts/main.py --mode=TerminateHSS --EPCIPAddress=${params.EPC_IPAddress} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCType=${params.EPC_Type} --EPCSourceCodePath=${params.EPC_SourceCodePath}" + } + } + } + } + } stage('Log Collection') { parallel { stage('Log Collection (eNB - Build)') { @@ -242,7 +315,7 @@ pipeline { [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] ]) { echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m' - sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath}" + sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}" echo '\u2705 \u001B[32mLog Transfer (eNB - Run)\u001B[0m' sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/enb.log.zip ./enb.log.${env.BUILD_ID}.zip || true" @@ -259,6 +332,116 @@ pipeline { } } } + stage('Log Collection (SPGW)') { + // Bypassing this stage if EPC server is not defined + when { + expression { params.EPC_IPAddress != "none" } + } + steps { + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'] + ]) { + echo '\u2705 \u001B[32mLog Collection (SPGW)\u001B[0m' + sh "python3 ci-scripts/main.py --mode=LogCollectSPGW --EPCIPAddress=${params.EPC_IPAddress} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCSourceCodePath=${params.EPC_SourceCodePath} --EPCType=${params.EPC_Type}" + + echo '\u2705 \u001B[32mLog Transfer (SPGW)\u001B[0m' + sh "sshpass -p \'${EPC_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${EPC_Username}@${params.EPC_IPAddress}:${EPC_SourceCodePath}/scripts/spgw.log.zip ./spgw.log.${env.BUILD_ID}.zip || true" + } + script { + if(fileExists("spgw.log.${env.BUILD_ID}.zip")) { + archiveArtifacts "spgw.log.${env.BUILD_ID}.zip" + } + } + } + } + stage('Log Collection (MME)') { + // Bypassing this stage if EPC server is not defined + when { + expression { params.EPC_IPAddress != "none" } + } + steps { + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'] + ]) { + echo '\u2705 \u001B[32mLog Collection (MME)\u001B[0m' + sh "python3 ci-scripts/main.py --mode=LogCollectMME --EPCIPAddress=${params.EPC_IPAddress} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCSourceCodePath=${params.EPC_SourceCodePath} --EPCType=${params.EPC_Type}" + + echo '\u2705 \u001B[32mLog Transfer (MME)\u001B[0m' + sh "sshpass -p \'${EPC_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${EPC_Username}@${params.EPC_IPAddress}:${EPC_SourceCodePath}/scripts/mme.log.zip ./mme.log.${env.BUILD_ID}.zip || true" + } + script { + if(fileExists("mme.log.${env.BUILD_ID}.zip")) { + archiveArtifacts "mme.log.${env.BUILD_ID}.zip" + } + } + } + } + stage('Log Collection (HSS)') { + // Bypassing this stage if EPC server is not defined + when { + expression { params.EPC_IPAddress != "none" } + } + steps { + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'] + ]) { + echo '\u2705 \u001B[32mLog Collection (HSS)\u001B[0m' + sh "python3 ci-scripts/main.py --mode=LogCollectHSS --EPCIPAddress=${params.EPC_IPAddress} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCSourceCodePath=${params.EPC_SourceCodePath} --EPCType=${params.EPC_Type}" + + echo '\u2705 \u001B[32mLog Transfer (HSS)\u001B[0m' + sh "sshpass -p \'${EPC_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${EPC_Username}@${params.EPC_IPAddress}:${EPC_SourceCodePath}/scripts/hss.log.zip ./hss.log.${env.BUILD_ID}.zip || true" + } + script { + if(fileExists("hss.log.${env.BUILD_ID}.zip")) { + archiveArtifacts "hss.log.${env.BUILD_ID}.zip" + } + } + } + } + stage('Log Collection (Ping)') { + // Bypassing this stage if EPC server is not defined + when { + expression { params.EPC_IPAddress != "none" } + } + steps { + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'] + ]) { + echo '\u2705 \u001B[32mLog Collection (Ping)\u001B[0m' + sh "python3 ci-scripts/main.py --mode=LogCollectPing --EPCIPAddress=${params.EPC_IPAddress} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCSourceCodePath=${params.EPC_SourceCodePath} --EPCType=${params.EPC_Type}" + + echo '\u2705 \u001B[32mLog Transfer (Ping)\u001B[0m' + sh "sshpass -p \'${EPC_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${EPC_Username}@${params.EPC_IPAddress}:${EPC_SourceCodePath}/scripts/ping.log.zip ./ping.log.${env.BUILD_ID}.zip || true" + } + script { + if(fileExists("ping.log.${env.BUILD_ID}.zip")) { + archiveArtifacts "ping.log.${env.BUILD_ID}.zip" + } + } + } + } + stage('Log Collection (Iperf)') { + // Bypassing this stage if EPC server is not defined + when { + expression { params.EPC_IPAddress != "none" } + } + steps { + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'] + ]) { + echo '\u2705 \u001B[32mLog Collection (Iperf)\u001B[0m' + sh "python3 ci-scripts/main.py --mode=LogCollectIperf --EPCIPAddress=${params.EPC_IPAddress} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCSourceCodePath=${params.EPC_SourceCodePath} --EPCType=${params.EPC_Type}" + + echo '\u2705 \u001B[32mLog Transfer (Iperf)\u001B[0m' + sh "sshpass -p \'${EPC_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${EPC_Username}@${params.EPC_IPAddress}:${EPC_SourceCodePath}/scripts/iperf.log.zip ./iperf.log.${env.BUILD_ID}.zip || true" + } + script { + if(fileExists("iperf.log.${env.BUILD_ID}.zip")) { + archiveArtifacts "iperf.log.${env.BUILD_ID}.zip" + } + } + } + } } } } diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 6abf444a0d..8f992689e2 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -74,6 +74,7 @@ class Containerize(): self.eNB2SourceCodePath = '' self.forcedWorkspaceCleanup = False self.imageKind = '' + self.proxyCommit = None self.eNB_instance = 0 self.eNB_serverId = ['', '', ''] self.yamlPath = ['', '', ''] @@ -421,6 +422,124 @@ class Containerize(): HTML.CreateHtmlTabFooter(False) sys.exit(1) + def BuildProxy(self, HTML): + if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': + HELP.GenericHelp(CONST.Version) + sys.exit('Insufficient Parameter') + if self.eNB_serverId[self.eNB_instance] == '0': + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = self.eNBSourceCodePath + elif self.eNB_serverId[self.eNB_instance] == '1': + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + lSourcePath = self.eNB1SourceCodePath + elif self.eNB_serverId[self.eNB_instance] == '2': + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + lSourcePath = self.eNB2SourceCodePath + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + HELP.GenericHelp(CONST.Version) + sys.exit('Insufficient Parameter') + if self.proxyCommit is None: + HELP.GenericHelp(CONST.Version) + sys.exit('Insufficient Parameter (need proxyCommit for proxy build)') + logging.debug('Building on server: ' + lIpAddr) + mySSH = SSH.SSHConnection() + mySSH.open(lIpAddr, lUserName, lPassWord) + + # Check that we are on Ubuntu + mySSH.command('hostnamectl', '\$', 5) + result = re.search('Ubuntu', mySSH.getBefore()) + self.host = result.group(0) + if self.host != 'Ubuntu': + logging.error('\u001B[1m Can build proxy only on Ubuntu server\u001B[0m') + mySSH.close() + sys.exit(1) + + self.cli = 'docker' + self.cliBuildOptions = '--no-cache' + + # Workaround for some servers, we need to erase completely the workspace + if self.forcedWorkspaceCleanup: + mySSH.command('echo ' + lPassWord + ' | sudo -S rm -Rf ' + lSourcePath, '\$', 15) + + oldRanCommidID = self.ranCommitID + oldRanRepository = self.ranRepository + oldRanAllowMerge = self.ranAllowMerge + self.ranCommitID = self.proxyCommit + self.ranRepository = 'https://github.com/EpiSci/oai-lte-5g-multi-ue-proxy.git' + self.ranAllowMerge = False + self._createWorkspace(mySSH, lPassWord, lSourcePath) + # to prevent accidentally overwriting data that might be used later + self.ranCommitID = oldRanCommidID + self.ranRepository = oldRanRepository + self.ranAllowMerge = oldRanAllowMerge + + # Let's remove any previous run artifacts if still there + mySSH.command(self.cli + ' image prune --force', '\$', 30) + # Remove any previous proxy image + mySSH.command(self.cli + ' image rm oai-lte-multi-ue-proxy:latest || true', '\$', 30) + + tag = self.proxyCommit + logging.debug('building L2sim proxy image for tag ' + tag) + # check if the corresponding proxy image with tag exists. If not, build it + mySSH.command(self.cli + ' image inspect --format=\'Size = {{.Size}} bytes\' proxy:' + tag, '\$', 5) + buildProxy = mySSH.getBefore().count('o such image') != 0 + if buildProxy: + mySSH.command(self.cli + ' build ' + self.cliBuildOptions + ' --target oai-lte-multi-ue-proxy --tag proxy:' + tag + ' --file docker/Dockerfile.ubuntu18.04 . > cmake_targets/log/proxy-build.log 2>&1', '\$', 180) + # Note: at this point, OAI images are flattened, but we cannot do this + # here, as the flatten script is not in the proxy repo + mySSH.command(self.cli + ' image inspect --format=\'Size = {{.Size}} bytes\' proxy:' + tag, '\$', 5) + if mySSH.getBefore().count('o such image') != 0: + logging.error('\u001B[1m Build of L2sim proxy failed\u001B[0m') + mySSH.close() + HTML.CreateHtmlTestRow('commit ' + tag, 'KO', CONST.ALL_PROCESSES_OK) + HTML.CreateHtmlTabFooter(False) + sys.exit(1) + else: + logging.debug('L2sim proxy image for tag ' + tag + ' already exists, skipping build') + + # retag the build images to that we pick it up later + mySSH.command('docker image tag proxy:' + tag + ' oai-lte-multi-ue-proxy:latest', '\$', 5) + + # no merge: is a push to develop, tag the image so we can push it to the registry + if not self.ranAllowMerge: + mySSH.command('docker image tag proxy:' + tag + ' proxy:develop', '\$', 5) + + # we assume that the host on which this is built will also run the proxy. The proxy + # currently requires the following command, and the docker-compose up mechanism of + # the CI does not allow to run arbitrary commands. Note that the following actually + # belongs to the deployment, not the build of the proxy... + logging.warning('the following command belongs to deployment, but no mechanism exists to exec it there!') + mySSH.command('sudo ifconfig lo: 127.0.0.2 netmask 255.0.0.0 up', '\$', 5) + + # Analyzing the logs + if buildProxy: + self.testCase_id = HTML.testCase_id + mySSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5) + mySSH.command('mkdir -p proxy_build_log_' + self.testCase_id, '\$', 5) + mySSH.command('mv log/* ' + 'proxy_build_log_' + self.testCase_id, '\$', 5) + if (os.path.isfile('./proxy_build_log_' + self.testCase_id + '.zip')): + os.remove('./proxy_build_log_' + self.testCase_id + '.zip') + if (os.path.isdir('./proxy_build_log_' + self.testCase_id)): + shutil.rmtree('./proxy_build_log_' + self.testCase_id) + mySSH.command('zip -r -qq proxy_build_log_' + self.testCase_id + '.zip proxy_build_log_' + self.testCase_id, '\$', 5) + mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/build_log_' + self.testCase_id + '.zip', '.') + # don't delete such that we might recover the zips + #mySSH.command('rm -f build_log_' + self.testCase_id + '.zip','\$', 5) + + # Cleaning any created tmp volume + mySSH.command(self.cli + ' volume prune --force || true','\$', 15) + mySSH.close() + + logging.info('\u001B[1m Building L2sim Proxy Image Pass\u001B[0m') + HTML.CreateHtmlTestRow('commit ' + tag, 'OK', CONST.ALL_PROCESSES_OK) + HTML.CreateHtmlNextTabHeaderTestRow(self.collectInfo, self.allImagesSize) + def Copy_Image_to_Test_Server(self, HTML): imageTag = 'develop' if (self.ranAllowMerge): diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 448f2636e3..baed6a6011 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -102,7 +102,7 @@ def AssignParams(params_dict): def GetParametersFromXML(action): - if action == 'Build_eNB' or action == 'Build_Image': + if action == 'Build_eNB' or action == 'Build_Image' or action == 'Build_Proxy': RAN.Build_eNB_args=test.findtext('Build_eNB_args') CONTAINERS.imageKind=test.findtext('kind') forced_workspace_cleanup = test.findtext('forced_workspace_cleanup') @@ -138,6 +138,9 @@ def GetParametersFromXML(action): RAN.backgroundBuild=True else: RAN.backgroundBuild=False + proxy_commit = test.findtext('proxy_commit') + if proxy_commit is not None: + CONTAINERS.proxyCommit = proxy_commit elif action == 'WaitEndBuild_eNB': RAN.Build_eNB_args=test.findtext('Build_eNB_args') @@ -915,6 +918,8 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re HTML=ldpc.Run_PhySim(HTML,CONST,id) elif action == 'Build_Image': CONTAINERS.BuildImage(HTML) + elif action == 'Build_Proxy': + CONTAINERS.BuildProxy(HTML) elif action == 'Copy_Image_to_Test': CONTAINERS.Copy_Image_to_Test_Server(HTML) elif action == 'Deploy_Object': diff --git a/ci-scripts/xml_class_list.yml b/ci-scripts/xml_class_list.yml index b305aff424..2c5f04b11f 100755 --- a/ci-scripts/xml_class_list.yml +++ b/ci-scripts/xml_class_list.yml @@ -1,3 +1,4 @@ + - Build_Proxy - Build_PhySim - Run_PhySim - Build_eNB diff --git a/ci-scripts/xml_files/container_5g_l2sim_proxy.xml b/ci-scripts/xml_files/container_5g_l2sim_proxy.xml new file mode 100644 index 0000000000..af1715d793 --- /dev/null +++ b/ci-scripts/xml_files/container_5g_l2sim_proxy.xml @@ -0,0 +1,42 @@ + + + l2sim-5gnr-proxy-build + Build L2sim proxy image + wrench + 1 + + 000001 + + + + + Build_Proxy + Build L2sim Proxy Image + 1 + 1 + True + 56cfdc0 + + + From 1f818b41782ffcee64d4db3f5f13f3b8c9c857e3 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 26 Jul 2022 12:45:30 +0100 Subject: [PATCH 226/267] RSRP computation at UE based on CSI-RS --- .../nfapi/public_inc/fapi_nr_ue_interface.h | 2 ++ openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 35 ++++++++++++++++--- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index 6e1a4adb65..d78eebd440 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -48,6 +48,8 @@ typedef struct { } fapi_nr_uci_pdu_rel15_t; typedef struct { + uint32_t rsrp; + int rsrp_dBm; uint8_t rank_indicator; uint8_t i1; uint8_t i2; diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 753040ecc6..43944b2fa8 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -33,12 +33,15 @@ #include #include +#include "executables/nr-softmodem-common.h" #include "nr_transport_proto_ue.h" #include "PHY/phy_extern_nr_ue.h" #include "common/utils/nr/nr_common.h" #include "PHY/NR_TRANSPORT/nr_transport_proto.h" #include "PHY/NR_UE_ESTIMATION/filt16a_32.h" +// 10*log10(pow(2,30)) +#define pow_2_30_dB 90 //#define NR_CSIRS_DEBUG //#define NR_CSIIM_DEBUG @@ -185,10 +188,14 @@ int nr_get_csi_rs_signal(const PHY_VARS_NR_UE *ue, const uint8_t *j_cdm, const uint8_t *k_overline, const uint8_t *l_overline, - int32_t csi_rs_received_signal[][ue->frame_parms.samples_per_slot_wCP]) { + int32_t csi_rs_received_signal[][ue->frame_parms.samples_per_slot_wCP], + uint32_t *rsrp, + int *rsrp_dBm) { int32_t **rxdataF = ue->common_vars.common_vars_rx_data_per_thread[proc->thread_id].rxdataF; const NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + uint16_t meas_count = 0; + uint32_t rsrp_sum = 0; for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) { @@ -216,6 +223,11 @@ int nr_get_csi_rs_signal(const PHY_VARS_NR_UE *ue, rx_csi_rs_signal[k].r = rx_signal[k].r; rx_csi_rs_signal[k].i = rx_signal[k].i; + rsrp_sum += (((int32_t)(rx_csi_rs_signal[k].r)*rx_csi_rs_signal[k].r) + + ((int32_t)(rx_csi_rs_signal[k].i)*rx_csi_rs_signal[k].i)); + + meas_count++; + #ifdef NR_CSIRS_DEBUG int dataF_offset = proc->nr_slot_rx*ue->frame_parms.samples_per_slot_wCP; uint16_t port_tx = s+j_cdm[cdm_id]*CDM_group_size; @@ -237,6 +249,15 @@ int nr_get_csi_rs_signal(const PHY_VARS_NR_UE *ue, } } + + *rsrp = rsrp_sum/meas_count; + *rsrp_dBm = dB_fixed(*rsrp) + 30 - pow_2_30_dB + - ((int)openair0_cfg[0].rx_gain[0] - (int)openair0_cfg[0].rx_gain_offset[0]) - dB_fixed(ue->frame_parms.ofdm_symbol_size); + +#ifdef NR_CSIRS_DEBUG + LOG_I(NR_PHY, "RSRP = %i (%i dBm)\n", *rsrp, *rsrp_dBm); +#endif + return 0; } @@ -839,6 +860,8 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t uint8_t l_overline[16]; int16_t log2_re = 0; int16_t log2_maxh = 0; + uint32_t rsrp = 0; + int rsrp_dBm = 0; uint32_t noise_power = 0; uint8_t rank_indicator = 0; uint32_t precoded_sinr_dB = 0; @@ -875,7 +898,9 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t j_cdm, k_overline, l_overline, - csi_rs_received_signal); + csi_rs_received_signal, + &rsrp, + &rsrp_dBm); nr_csi_rs_channel_estimation(ue, proc, @@ -919,11 +944,13 @@ int nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t nr_csi_rs_cqi_estimation(precoded_sinr_dB, &cqi); - LOG_I(NR_PHY, "RI = %i, i1 = %i.%i.%i, i2 = %i, SINR = %i dB, CQI = %i\n", - rank_indicator+1, i1[0], i1[1], i1[2], i2[0], precoded_sinr_dB, cqi); + LOG_I(NR_PHY, "RSRP = %i dBm, RI = %i, i1 = %i.%i.%i, i2 = %i, SINR = %i dB, CQI = %i\n", + rsrp_dBm, rank_indicator+1, i1[0], i1[1], i1[2], i2[0], precoded_sinr_dB, cqi); // Send CSI measurements to MAC fapi_nr_csirs_measurements_t csirs_measurements; + csirs_measurements.rsrp = rsrp; + csirs_measurements.rsrp_dBm = rsrp_dBm; csirs_measurements.rank_indicator = rank_indicator; csirs_measurements.i1 = *i1; csirs_measurements.i2 = *i2; From 3ca83257cc1e8f675b9ebc1d0cf39d63db4db4b6 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 26 Jul 2022 15:45:11 +0100 Subject: [PATCH 227/267] UE sends the report with the RSRP based on CSI-RS to gNB --- openair2/LAYER2/NR_MAC_UE/mac_proto.h | 6 ++ openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 65 ++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index d5174b3a44..6bb833be31 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -220,6 +220,12 @@ uint8_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, NR_CSI_ResourceConfigId_t csi_ResourceConfigId, NR_CSI_MeasConfig_t *csi_MeasConfig); +uint8_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac, + PUCCH_sched_t *pucch, + struct NR_CSI_ReportConfig *csi_reportconfig, + NR_CSI_ResourceConfigId_t csi_ResourceConfigId, + NR_CSI_MeasConfig_t *csi_MeasConfig); + uint8_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac, PUCCH_sched_t *pucch, int csi_report_id, diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 67331c1865..bf6e0c4b02 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2572,6 +2572,8 @@ uint8_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac, n_csi_bits = get_csirs_RI_PMI_CQI_payload(mac,pucch,csi_reportconfig,csi_ResourceConfigId,csi_MeasConfig); break; case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP: + n_csi_bits = get_csirs_RSRP_payload(mac,pucch,csi_reportconfig,csi_ResourceConfigId,csi_MeasConfig); + break; case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1: case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI: case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI: @@ -2709,6 +2711,9 @@ uint8_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, LOG_D(NR_MAC, "cqi_bitlen = %d\n", cqi_bitlen); LOG_D(NR_MAC, "csi_part1_payload = 0x%x\n", temp_payload); + LOG_D(NR_MAC, "n_bits = %d\n", n_bits); + LOG_D(NR_MAC, "csi_part1_payload = 0x%x\n", temp_payload); + break; } } @@ -2718,6 +2723,66 @@ uint8_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, return n_bits; } +uint8_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac, + PUCCH_sched_t *pucch, + struct NR_CSI_ReportConfig *csi_reportconfig, + NR_CSI_ResourceConfigId_t csi_ResourceConfigId, + NR_CSI_MeasConfig_t *csi_MeasConfig) { + + int n_bits = 0; + uint32_t temp_payload = 0; + + for (int csi_resourceidx = 0; csi_resourceidx < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_resourceidx++) { + + struct NR_CSI_ResourceConfig *csi_resourceconfig = csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx]; + if (csi_resourceconfig->csi_ResourceConfigId == csi_ResourceConfigId) { + + for (int csi_idx = 0; csi_idx < csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList->list.count; csi_idx++) { + if (csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList->list.array[csi_idx]->nzp_CSI_ResourceSetId == + *(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.array[0])) { + + nr_csi_report_t *csi_report = &mac->csi_report_template[csi_reportconfig->reportConfigId]; + compute_csi_bitlen(csi_MeasConfig, mac->csi_report_template); + n_bits = nr_get_csi_bitlen(mac->csi_report_template, csi_reportconfig->reportConfigId); + + int cri_ssbri_bitlen = csi_report->CSI_report_bitlen.cri_ssbri_bitlen; + int rsrp_bitlen = csi_report->CSI_report_bitlen.rsrp_bitlen; + int diff_rsrp_bitlen = csi_report->CSI_report_bitlen.diff_rsrp_bitlen; + + if (cri_ssbri_bitlen > 0) { + LOG_E(NR_MAC, "Implementation for cri_ssbri_bitlen>0 is not supported yet!\n");; + } + + // TODO: Improvements will be needed to cri_ssbri_bitlen>0 + // TS 38.133 - Table 10.1.6.1-1 + int rsrp_dBm = mac->csirs_measurements.rsrp_dBm; + if (rsrp_dBm < -139) { + temp_payload = 17; + } else if (rsrp_dBm > -45) { + temp_payload = 112; + } else { + temp_payload = mac->csirs_measurements.rsrp_dBm + 157; + } + + reverse_n_bits((uint8_t *)&temp_payload, n_bits); + + LOG_D(NR_MAC, "cri_ssbri_bitlen = %d\n", cri_ssbri_bitlen); + LOG_D(NR_MAC, "rsrp_bitlen = %d\n", rsrp_bitlen); + LOG_D(NR_MAC, "diff_rsrp_bitlen = %d\n", diff_rsrp_bitlen); + + LOG_D(NR_MAC, "n_bits = %d\n", n_bits); + LOG_D(NR_MAC, "csi_part1_payload = 0x%x\n", temp_payload); + + break; + } + } + } + } + + pucch->csi_part1_payload = temp_payload; + return n_bits; +} + // returns index from RSRP // according to Table 10.1.6.1-1 in 38.133 From b4331bf7f43588fadc90e9504de3894872f14145 Mon Sep 17 00:00:00 2001 From: laurent Date: Thu, 30 Jun 2022 17:57:47 +0200 Subject: [PATCH 228/267] code maintenance: old errors --- executables/nr-softmodem.h | 3 - openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c | 21 ++- openair1/SCHED/ru_procedures.c | 14 +- openair1/SCHED/sched_common_extern.h | 2 + openair1/SIMULATION/LTE_PHY/dlsim.c | 8 +- .../LAYER2/MAC/eNB_scheduler_primitives.c | 16 --- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 12 +- openair2/LAYER2/MAC/mac.h | 10 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 11 +- openair2/RRC/LTE/rrc_eNB.c | 124 +++++------------- targets/RT/USER/lte-ru.c | 6 +- targets/RT/USER/lte-softmodem.h | 17 ++- targets/RT/USER/lte-uesoftmodem.c | 1 - 13 files changed, 90 insertions(+), 155 deletions(-) diff --git a/executables/nr-softmodem.h b/executables/nr-softmodem.h index 7d2184f01b..98087ea2bb 100644 --- a/executables/nr-softmodem.h +++ b/executables/nr-softmodem.h @@ -59,9 +59,6 @@ extern void set_function_spec_param(RU_t *ru); extern void reset_opp_meas(void); extern void print_opp_meas(void); - -extern void init_fep_thread(PHY_VARS_gNB *); - void init_gNB_afterRU(void); extern int stop_L1L2(module_id_t gnb_id); diff --git a/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c b/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c index 088e2c0a5e..b5e5b490a3 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c @@ -64,6 +64,12 @@ extern uint16_t beta_cqi[16]; extern uint16_t beta_ri[16]; extern uint16_t beta_ack[16]; +static int errorRB(int rb, char * table, int line) { + LOG_E(PHY,"Received %d rb, impossble in table %s, at line %d\n", rb, table, line); + return 0; +} + +#define rbAllocCheck(RBalL, TabLe) (RBalL) > sizeof(TabLe)/sizeof(*TabLe) ? errorRB(RBalL, #TabLe, __LINE__) : TabLe[RBalL] void extract_dci1A_info(uint8_t N_RB_DL, frame_type_t frame_type, void *dci_pdu, DCI_INFO_EXTRACTED_t *pdci_info_extarcted) { uint8_t harq_pid=0; @@ -974,28 +980,28 @@ int check_dci_format1_1a_coherency(DCI_format_t dci_format, { switch (N_RB_DL) { case 6: - NPRB = RIV2nb_rb_LUT6[rballoc];//NPRB; + NPRB = rbAllocCheck(rballoc, RIV2nb_rb_LUT6); if(rah) RIV_max = RIV_max6; else RIV_max = 0x3F; break; case 25: - NPRB = RIV2nb_rb_LUT25[rballoc];//NPRB; + NPRB = rbAllocCheck(rballoc,RIV2nb_rb_LUT25); if(rah) RIV_max = RIV_max25; else RIV_max = 0x1FFF; break; case 50: - NPRB = RIV2nb_rb_LUT50[rballoc];//NPRB; + NPRB = rbAllocCheck(rballoc,RIV2nb_rb_LUT50); if(rah) RIV_max = RIV_max50; else RIV_max = 0x1FFFF; break; case 100: - NPRB = RIV2nb_rb_LUT100[rballoc];//NPRB; + NPRB = rbAllocCheck(rballoc,RIV2nb_rb_LUT100); if(rah) RIV_max = RIV_max100; else @@ -1034,9 +1040,14 @@ int check_dci_format1_1a_coherency(DCI_format_t dci_format, // this is an eNB issue // retransmisison but old and new TBS are different !!! // work around, consider it as a new transmission - LOG_E(PHY,"Format1A Retransmission but TBS are different: consider it as new transmission !!! \n"); + LOG_E(PHY, + "Format1A Retransmission but TBS are different: consider it as new transmission !!!, round %d, mcs 1 %d, NPRB %d \n", + pdlsch0_harq->round, + mcs1, + NPRB); pdlsch0_harq->round = 0; //return(0); // ?? to cross check + return(0); // ?? to cross check } } diff --git a/openair1/SCHED/ru_procedures.c b/openair1/SCHED/ru_procedures.c index dc84279a96..443b1c7989 100644 --- a/openair1/SCHED/ru_procedures.c +++ b/openair1/SCHED/ru_procedures.c @@ -71,9 +71,9 @@ #include "common/utils/system.h" #include - -extern int oai_exit; - +#include "openair1/SCHED/sched_common_extern.h" +#include "targets/RT/USER/lte-softmodem.h" +#include "common/ran_context.h" void feptx0(RU_t *ru, int slot) @@ -616,9 +616,11 @@ void init_fep_thread(RU_t *ru, } -extern void kill_fep_thread(RU_t *ru) +void kill_fep_thread(RU_t *ru) { RU_proc_t *proc = &ru->proc; + if (proc->pthread_fep == 0) + return; pthread_mutex_lock( &proc->mutex_fep ); proc->instance_cnt_fep = 0; pthread_cond_signal(&proc->cond_fep); @@ -630,9 +632,11 @@ extern void kill_fep_thread(RU_t *ru) } -extern void kill_feptx_thread(RU_t *ru) +void kill_feptx_thread(RU_t *ru) { RU_proc_t *proc = &ru->proc; + if (proc->pthread_feptx == 0) + return; pthread_mutex_lock( &proc->mutex_feptx ); proc->instance_cnt_feptx = 0; pthread_cond_signal(&proc->cond_feptx); diff --git a/openair1/SCHED/sched_common_extern.h b/openair1/SCHED/sched_common_extern.h index b5edc6f38e..2236c5f31d 100644 --- a/openair1/SCHED/sched_common_extern.h +++ b/openair1/SCHED/sched_common_extern.h @@ -29,4 +29,6 @@ extern int16_t hundred_times_delta_TF[100]; extern uint16_t hundred_times_log10_NPRB[100]; +void kill_fep_thread(RU_t *ru); + #endif /*__SCHED_EXTERN_H__ */ diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 231d63cf04..e5e97733e5 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -514,10 +514,10 @@ int main(int argc, char **argv) { LTE_DL_FRAME_PARMS *frame_parms; double s_re0[30720*2],s_im0[30720*2],r_re0[30720*2],r_im0[30720*2]; double s_re1[30720*2],s_im1[30720*2],r_re1[30720*2],r_im1[30720*2]; - double *s_re[2]= {s_re0,s_re1}; - double *s_im[2]= {s_im0,s_im1}; - double *r_re[2]= {r_re0,r_re1}; - double *r_im[2]= {r_im0,r_im1}; + double *s_re[NB_ANTENNAS_TX]= {s_re0,s_re1}; + double *s_im[NB_ANTENNAS_TX]= {s_im0,s_im1}; + double *r_re[NB_ANTENNAS_RX]= {r_re0,r_re1}; + double *r_im[NB_ANTENNAS_RX]= {r_im0,r_im1}; uint8_t transmission_mode=1,n_tx_port=1,n_tx_phy=1,n_rx=2; int eNB_id = 0; unsigned char round; diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 4469d0a3f9..58abbd7a47 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -2366,22 +2366,6 @@ rrc_mac_remove_ue(module_id_t mod_idP, return 0; } -//------------------------------------------------------------------------------ -/* - * Returns the previous UE_id in the scheduling list in UL or DL - */ -inline int prev(UE_list_t *listP, int nodeP) { - if (nodeP == listP->head) - return -1; /* there is no previous of the head */ - - for (int j = listP->head; j >= 0; j = listP->next[j]) - if (listP->next[j] == nodeP) - return j; - - LOG_E(MAC, "%s(): could not find previous to %d in UE_list\n", __func__, nodeP); - dump_ue_list(listP); - return -1; -} // This has to be updated to include BSR information //------------------------------------------------------------------------------ diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index a31b8bdd03..f9218d8511 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -329,17 +329,7 @@ rx_sdu(const module_id_t enb_mod_idP, if (ra->msg3_round >= mac->common_channels[CC_idP].radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx - 1) { // Release RNTI of LTE PHY when RA does not succeed - UE_free_list_t *free_list = NULL; - pthread_mutex_lock(&lock_ue_freelist); - free_list = &mac->UE_free_list; - free_list->UE_free_ctrl[free_list->tail_freelist].rnti = current_rnti; - free_list->UE_free_ctrl[free_list->tail_freelist].removeContextFlg = 1; - free_list->UE_free_ctrl[free_list->tail_freelist].raFlag = 1; - free_list->num_UEs++; - mac->UE_release_req.ue_release_request_body.ue_release_request_TLVs_list[mac->UE_release_req.ue_release_request_body.number_of_TLVs].rnti = current_rnti; - mac->UE_release_req.ue_release_request_body.number_of_TLVs++; - free_list->tail_freelist = (free_list->tail_freelist + 1) % (NUMBER_OF_UE_MAX+1); - pthread_mutex_unlock(&lock_ue_freelist); + put_UE_in_freelist(enb_mod_idP, current_rnti, true); cancel_ra_proc(enb_mod_idP, CC_idP, frameP, current_rnti); nfapi_hi_dci0_request_t *hi_dci0_req = NULL; diff --git a/openair2/LAYER2/MAC/mac.h b/openair2/LAYER2/MAC/mac.h index 2392c8506b..1fd7182c6f 100644 --- a/openair2/LAYER2/MAC/mac.h +++ b/openair2/LAYER2/MAC/mac.h @@ -1195,14 +1195,6 @@ typedef struct { ///remove RA flag bool raFlag; } UE_free_ctrl_t; -/*! \brief REMOVE UE list used by eNB to order UEs/CC for deleting*/ -typedef struct { - /// deleting control info - UE_free_ctrl_t UE_free_ctrl[NUMBER_OF_UE_MAX+1]; - int num_UEs; - int head_freelist; ///the head position of the delete list - int tail_freelist; ///the tail position of the delete list -} UE_free_list_t; /** * describes contiguous RBs @@ -1443,7 +1435,7 @@ typedef struct eNB_MAC_INST_s { /// processing time of eNB PCH scheduler time_stats_t schedule_pch; - UE_free_list_t UE_free_list; + UE_free_ctrl_t UE_free_ctrl[NUMBER_OF_UE_MAX+1]; /// for scheduling selection SCHEDULER_MODES scheduler_mode; /// Default scheduler: Pre-processor implementation. Algorithms for UL/DL diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 9941437e13..01a574f83c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2437,16 +2437,15 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf sched_ctrl->next_dl_bwp_id = -1; sched_ctrl->next_ul_bwp_id = -1; const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig ? servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList : NULL; - if (ubwpList) - AssertFatal(ubwpList->list.count <= NR_MAX_NUM_BWP, - "uplinkBWP_ToAddModList has %d BWP!\n", - ubwpList->list.count); + AssertFatal(ubwpList == NULL || ubwpList->list.count <= NR_MAX_NUM_BWP, + "uplinkBWP_ToAddModList has %d BWP!\n", + ubwpList->list.count); const int ul_bwp_id = servingCellConfig ? *servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id : 0; sched_ctrl->active_ubwp = ubwpList && ul_bwp_id > 0 ? ubwpList->list.array[ul_bwp_id - 1] : NULL; /* get Number of HARQ processes for this UE */ - if (servingCellConfig) - AssertFatal(servingCellConfig->pdsch_ServingCellConfig->present == NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup, + AssertFatal(servingCellConfig == NULL + || servingCellConfig->pdsch_ServingCellConfig->present == NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup, "no pdsch-ServingCellConfig found for UE %04x\n", UE->rnti); const NR_PDSCH_ServingCellConfig_t *pdsch = servingCellConfig ? servingCellConfig->pdsch_ServingCellConfig->choice.setup : NULL; diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c index a5d938cdf6..8be30175e1 100644 --- a/openair2/RRC/LTE/rrc_eNB.c +++ b/openair2/RRC/LTE/rrc_eNB.c @@ -976,28 +976,24 @@ rrc_eNB_free_UE( put_UE_in_freelist(enb_mod_idP, rnti, 1); } -void remove_UE_from_freelist(module_id_t mod_id, rnti_t rnti) { - eNB_MAC_INST *eNB_MAC = RC.mac[mod_id]; - pthread_mutex_lock(&lock_ue_freelist); - UE_free_list_t *free_list = &eNB_MAC->UE_free_list; - free_list->UE_free_ctrl[free_list->head_freelist].rnti = 0; - free_list->head_freelist = (free_list->head_freelist + 1) % (NUMBER_OF_UE_MAX+1); - free_list->num_UEs--; - pthread_mutex_unlock(&lock_ue_freelist); -} - void put_UE_in_freelist(module_id_t mod_id, rnti_t rnti, bool removeFlag) { - UE_free_list_t *free_list = NULL; eNB_MAC_INST *eNB_MAC = RC.mac[mod_id]; pthread_mutex_lock(&lock_ue_freelist); - free_list = &eNB_MAC->UE_free_list; - free_list->UE_free_ctrl[free_list->tail_freelist].rnti = rnti; - free_list->UE_free_ctrl[free_list->tail_freelist].removeContextFlg = removeFlag; - free_list->UE_free_ctrl[free_list->tail_freelist].raFlag = 0; - free_list->num_UEs++; + LOG_I(PHY,"add ue %d in fre list, context flag: %d\n", rnti, removeFlag); + int i; + for (i=0; i < sizeofArray(eNB_MAC->UE_free_ctrl); i++) + if (eNB_MAC->UE_free_ctrl[i].rnti == 0) + break; + if (i==sizeofArray(eNB_MAC->UE_free_ctrl)) { + LOG_E(PHY,"List of UE to free is full\n"); + pthread_mutex_unlock(&lock_ue_freelist); + return; + } + eNB_MAC->UE_free_ctrl[i].rnti = rnti; + eNB_MAC->UE_free_ctrl[i].removeContextFlg = removeFlag; + eNB_MAC->UE_free_ctrl[i].raFlag = 0; eNB_MAC->UE_release_req.ue_release_request_body.ue_release_request_TLVs_list[eNB_MAC->UE_release_req.ue_release_request_body.number_of_TLVs].rnti = rnti; eNB_MAC->UE_release_req.ue_release_request_body.number_of_TLVs++; - free_list->tail_freelist = (free_list->tail_freelist + 1) % (NUMBER_OF_UE_MAX+1); pthread_mutex_unlock(&lock_ue_freelist); } @@ -1007,104 +1003,47 @@ extern void clean_eNb_ulsch(LTE_eNB_ULSCH_t *ulsch); extern void clean_eNb_dlsch(LTE_eNB_DLSCH_t *dlsch); void release_UE_in_freeList(module_id_t mod_id) { - int i, j, CC_id, pdu_number; - protocol_ctxt_t ctxt; - nfapi_ul_config_request_body_t *ul_req_tmp = NULL; PHY_VARS_eNB *eNB_PHY = NULL; - struct rrc_eNB_ue_context_s *ue_context_pP = NULL; eNB_MAC_INST *eNB_MAC = RC.mac[mod_id]; - bool remove_UEContext; - rnti_t rnti; - int head, tail, ue_num; pthread_mutex_lock(&lock_ue_freelist); - head = eNB_MAC->UE_free_list.head_freelist; - tail = eNB_MAC->UE_free_list.tail_freelist; - if(head == tail) { - pthread_mutex_unlock(&lock_ue_freelist); - return; - } - - if(tail < head) { - tail = head + eNB_MAC->UE_free_list.num_UEs; - } - - pthread_mutex_unlock(&lock_ue_freelist); - - for(ue_num = head; ue_num < tail; ue_num++) { - ue_num = ue_num % (NUMBER_OF_UE_MAX+1); - rnti = eNB_MAC->UE_free_list.UE_free_ctrl[ue_num].rnti; + for(int ue_num = 0; ue_num < sizeofArray(eNB_MAC->UE_free_ctrl) ; ue_num++) { + rnti_t rnti = eNB_MAC->UE_free_ctrl[ue_num].rnti; if(rnti != 0) { - remove_UEContext = eNB_MAC->UE_free_list.UE_free_ctrl[ue_num].removeContextFlg; + protocol_ctxt_t ctxt; PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, mod_id, ENB_FLAG_YES, rnti, 0, 0,mod_id); - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { eNB_PHY = RC.eNB[mod_id][CC_id]; int id; // clean ULSCH entries for rnti - id = find_ulsch(rnti,eNB_PHY,eNB_MAC->UE_free_list.UE_free_ctrl[ue_num].raFlag ? SEARCH_EXIST_RA : SEARCH_EXIST); + id = find_ulsch(rnti,eNB_PHY,eNB_MAC->UE_free_ctrl[ue_num].raFlag ? SEARCH_EXIST_RA : SEARCH_EXIST); if (id>=0) clean_eNb_ulsch(eNB_PHY->ulsch[id]); // clean DLSCH entries for rnti - id = find_dlsch(rnti,eNB_PHY,eNB_MAC->UE_free_list.UE_free_ctrl[ue_num].raFlag ? SEARCH_EXIST_RA : SEARCH_EXIST); + id = find_dlsch(rnti,eNB_PHY,eNB_MAC->UE_free_ctrl[ue_num].raFlag ? SEARCH_EXIST_RA : SEARCH_EXIST); if (id>=0) clean_eNb_dlsch(eNB_PHY->dlsch[id][0]); // clean UCI entries for rnti - for (i=0; iuci_vars[i].rnti == rnti) { LOG_I(MAC, "clean eNb uci_vars[%d] UE %x \n",i, rnti); memset(&eNB_PHY->uci_vars[i],0,sizeof(LTE_eNB_UCI)); } } - /* - for (i=0; iulsch[i]; - - if((ulsch != NULL) && (ulsch->rnti == rnti)) { - void clean_eNb_ulsch(LTE_eNB_ULSCH_t *ulsch); - LOG_I(RRC, "clean_eNb_ulsch ulsch[%d] UE %x\n", i, rnti); - clean_eNb_ulsch(ulsch); - } - - dlsch = eNB_PHY->dlsch[i][0]; - - if((dlsch != NULL) && (dlsch->rnti == rnti)) { - void clean_eNb_dlsch(LTE_eNB_DLSCH_t *dlsch); - LOG_I(RRC, "clean_eNb_dlsch dlsch[%d] UE %x \n", i, rnti); - clean_eNb_dlsch(dlsch); - } - } - - ulsch = eNB_PHY->ulsch[i]; - - if((ulsch != NULL) && (ulsch->rnti == rnti)) { - void clean_eNb_ulsch(LTE_eNB_ULSCH_t *ulsch); - LOG_I(RRC, "clean_eNb_ulsch ulsch[%d] UE %x\n", i, rnti); - clean_eNb_ulsch(ulsch); - } - - for (i=0; iuci_vars[i].rnti == rnti) { - LOG_I(MAC, "clean eNb uci_vars[%d] UE %x \n",i, rnti); - memset(&eNB_PHY->uci_vars[i],0,sizeof(LTE_eNB_UCI)); - } - } - */ - if (flexran_agent_get_rrc_xface(mod_id)) { - flexran_agent_get_rrc_xface(mod_id)->flexran_agent_notify_ue_state_change( - mod_id, rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); + flexran_agent_get_rrc_xface(mod_id)->flexran_agent_notify_ue_state_change( mod_id, rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); } - for(j = 0; j < 10; j++) { - ul_req_tmp = &eNB_MAC->UL_req_tmp[CC_id][j].ul_config_request_body; + for(int j = 0; j < 10; j++) { + nfapi_ul_config_request_body_t *ul_req_tmp = &eNB_MAC->UL_req_tmp[CC_id][j].ul_config_request_body; if(ul_req_tmp) { - pdu_number = ul_req_tmp->number_of_pdus; + int pdu_number = ul_req_tmp->number_of_pdus; for(int pdu_index = pdu_number-1; pdu_index >= 0; pdu_index--) { if((ul_req_tmp->ul_config_pdu_list[pdu_index].ulsch_pdu.ulsch_pdu_rel8.rnti == rnti) || @@ -1126,7 +1065,8 @@ void release_UE_in_freeList(module_id_t mod_id) { } if (!NODE_IS_CU(RC.rrc[mod_id]->node_type)) { - rrc_mac_remove_ue(mod_id,rnti); + if (!eNB_MAC->UE_free_ctrl[ue_num].raFlag) + rrc_mac_remove_ue(mod_id,rnti); rrc_rlc_remove_ue(&ctxt); pdcp_remove_UE(&ctxt); } else { @@ -1139,19 +1079,20 @@ void release_UE_in_freeList(module_id_t mod_id) { itti_send_msg_to_task(TASK_CU_F1, mod_id, m); } - if(remove_UEContext) { - ue_context_pP = rrc_eNB_get_ue_context(RC.rrc[mod_id],rnti); - + if(eNB_MAC->UE_free_ctrl[ue_num].removeContextFlg) { + struct rrc_eNB_ue_context_s *ue_context_pP = rrc_eNB_get_ue_context(RC.rrc[mod_id],rnti); if(ue_context_pP) { + LOG_I(PHY, "remove RNTI %04x\n", rnti); rrc_eNB_remove_ue_context(&ctxt,RC.rrc[mod_id], (struct rrc_eNB_ue_context_s *) ue_context_pP); } } - LOG_I(RRC, "[release_UE_in_freeList] remove UE %x from freeList\n", rnti); - remove_UE_from_freelist(mod_id, rnti); + LOG_I(RRC, "[release_UE_in_freeList] remove UE %x from freeList ra context: %d\n", rnti, eNB_MAC->UE_free_ctrl[ue_num].raFlag); + eNB_MAC->UE_free_ctrl[ue_num].rnti = 0; } } + pthread_mutex_unlock(&lock_ue_freelist); } int rrc_eNB_previous_SRB2(rrc_eNB_ue_context_t *ue_context_pP) { @@ -7246,6 +7187,7 @@ rrc_eNB_decode_ccch( LOG_I(RRC," S-TMSI exists, ue_context_p %p, old rnti %x => %x\n",ue_context_p,ue_context_p->ue_context.rnti,ctxt_pP->rnti); if (!NODE_IS_CU(RC.rrc[ctxt_pP->module_id]->node_type)) { + LOG_I(PHY, "remove RNTI %04x\n", ue_context_p->ue_context.rnti); rrc_mac_remove_ue(ctxt_pP->module_id, ue_context_p->ue_context.rnti); } else { MessageDef *m = itti_alloc_new_message(TASK_RRC_ENB, 0, F1AP_UE_CONTEXT_RELEASE_CMD); diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index a7a0d2de32..1d464cb90c 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -89,7 +89,7 @@ void prach_procedures(PHY_VARS_eNB *eNB,int br_flag); void stop_RU(RU_t **rup,int nb_ru); -void do_ru_synch(RU_t *ru); +static void do_ru_synch(RU_t *ru); void configure_ru(int idx, void *arg); @@ -1059,7 +1059,7 @@ int wakeup_synch(RU_t *ru) { } -void do_ru_synch(RU_t *ru) { +static void do_ru_synch(RU_t *ru) { LTE_DL_FRAME_PARMS *fp = ru->frame_parms; RU_proc_t *proc = &ru->proc; int rxs, ic, ret, i; @@ -1924,7 +1924,7 @@ static void *ru_thread( void *param ) { // This thread run the initial synchronization like a UE -void *ru_thread_synch(void *arg) { +static void *ru_thread_synch(void *arg) { RU_t *ru = (RU_t *)arg; __attribute__((unused)) LTE_DL_FRAME_PARMS *fp = ru->frame_parms; diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h index 1c887dd3c8..38b71238b8 100644 --- a/targets/RT/USER/lte-softmodem.h +++ b/targets/RT/USER/lte-softmodem.h @@ -29,6 +29,7 @@ #include "flexran_agent.h" #include "s1ap_eNB.h" #include "SIMULATION/ETH_TRANSPORT/proto.h" +#include "targets/ARCH/COMMON/common_lib.h" #include "executables/softmodem-common.h" @@ -213,5 +214,19 @@ extern void init_UE_standalone_thread(int ue_idx); extern PHY_VARS_UE *init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms, uint8_t UE_id, uint8_t abstraction_flag); extern void init_bler_table(void); - +void feptx_ofdm_2thread(RU_t *ru, + int frame, + int subframe); +void* ru_thread_control( void* param ); +void wait_eNBs(void); +void kill_feptx_thread(RU_t *ru); +void init_fep_thread(RU_t *ru, pthread_attr_t *attr_fep); +void init_feptx_thread(RU_t *ru, pthread_attr_t *attr_feptx); +void fep_full(RU_t *ru, int subframe); +void configure_ru(int, void *arg); +void configure_rru(int, void *arg); +void ru_fep_full_2thread(RU_t *ru,int subframe); +void feptx_ofdm(RU_t*ru, int frame_tx, int tti_tx); +void feptx_prec(struct RU_t_s *ru, int frame_tx, int tti_tx); +void fill_rf_config(RU_t *ru, char *rf_config_file); #endif diff --git a/targets/RT/USER/lte-uesoftmodem.c b/targets/RT/USER/lte-uesoftmodem.c index 678b6e0401..05602b63da 100644 --- a/targets/RT/USER/lte-uesoftmodem.c +++ b/targets/RT/USER/lte-uesoftmodem.c @@ -176,7 +176,6 @@ extern char uecap_xer[1024]; char uecap_xer_in=0; int oaisim_flag=0; -//threads_t threads= {-1,-1,-1,-1,-1,-1,-1,-1}; /* see file openair2/LAYER2/MAC/main.c for why abstraction_flag is needed * this is very hackish - find a proper solution From 8cd87999813f836830db9ba9c29c819abca7ab24 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 27 Jul 2022 18:43:47 +0100 Subject: [PATCH 229/267] Update range for reported RSRP --- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index bf6e0c4b02..aade58421a 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2756,10 +2756,10 @@ uint8_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac, // TODO: Improvements will be needed to cri_ssbri_bitlen>0 // TS 38.133 - Table 10.1.6.1-1 int rsrp_dBm = mac->csirs_measurements.rsrp_dBm; - if (rsrp_dBm < -139) { - temp_payload = 17; - } else if (rsrp_dBm > -45) { - temp_payload = 112; + if (rsrp_dBm < -140) { + temp_payload = 16; + } else if (rsrp_dBm > -44) { + temp_payload = 113; } else { temp_payload = mac->csirs_measurements.rsrp_dBm + 157; } From 970bfc92f02e71ecfc3cd6a63920f9986d599617 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Thu, 28 Jul 2022 07:20:31 +0100 Subject: [PATCH 230/267] Fix a segmentation fault when there is no spCellConfigDedicated with maxMIMO_Layers parameter --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index d9a0a50b7e..a4c034bb8f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1120,9 +1120,8 @@ void nr_schedule_ue_spec(module_id_t module_id, csi_report->codebook_mode); } // TBS_LBRM according to section 5.4.2.1 of 38.212 - long *maxMIMO_Layers = cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers; - AssertFatal (maxMIMO_Layers != NULL,"Option with max MIMO layers not configured is not supported\n"); - int nl_tbslbrm = *maxMIMO_Layers < 4 ? *maxMIMO_Layers : 4; + long maxMIMO_Layers = cg && cg->spCellConfig && cg->spCellConfig->spCellConfigDedicated ? *cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers : 1; + int nl_tbslbrm = maxMIMO_Layers < 4 ? maxMIMO_Layers : 4; // Maximum number of PRBs across all configured DL BWPs int bw_tbslbrm = get_bw_tbslbrm(genericParameters, cg); pdsch_pdu->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(ps->mcsTableIdx, From 1a77e9ba37dd86e7f3a1c3041580df822ab9fd48 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Mon, 20 Jun 2022 14:08:43 +0100 Subject: [PATCH 231/267] Schedule BWP switching to the first active BWP (previous active BWP before RA with Msg3 carrying DCCH or DTCH message) --- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 44 ++++++++++++++++--- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 01a574f83c..842a3521cb 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2957,6 +2957,10 @@ void nr_mac_update_timers(module_id_t module_id, LOG_I(NR_MAC, "(%d.%d) Switching to initialUplinkBWP\n", frame, slot); } UE->Msg3_dcch_dtch = false; + + // Schedule BWP switching to the first active BWP (previous active BWP before RA with Msg3 carrying DCCH or DTCH message) + sched_ctrl->next_dl_bwp_id = current_bwp_id; + sched_ctrl->next_ul_bwp_id = current_ubwp_id; } else if (spCellConfigDedicated && spCellConfigDedicated->downlinkBWP_ToAddModList && spCellConfigDedicated->uplinkConfig && @@ -2969,6 +2973,19 @@ void nr_mac_update_timers(module_id_t module_id, if (*spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id != current_ubwp_id) { LOG_I(NR_MAC, "(%d.%d) Switching to UL-BWP %li\n", frame, slot, sched_ctrl->active_ubwp->bwp_Id); } + + // Update next_dl_bwp_id to not trigger BWP switching, UE should be already on active_bwp + sched_ctrl->next_dl_bwp_id = sched_ctrl->active_bwp->bwp_Id; + // Update next_ul_bwp_id to not trigger BWP switching, UE should be already on active_ubwp + sched_ctrl->next_ul_bwp_id = sched_ctrl->active_ubwp->bwp_Id; + } else { + sched_ctrl->active_bwp = NULL; + sched_ctrl->active_ubwp = NULL; + + // Update next_dl_bwp_id to not trigger BWP switching, UE should be already on Initial BWP + sched_ctrl->next_dl_bwp_id = 0; + // Update next_ul_bwp_id to not trigger BWP switching, UE should be already on Initial BWP + sched_ctrl->next_ul_bwp_id = 0; } // Update coreset/searchspace @@ -3062,14 +3079,27 @@ void schedule_nr_bwp_switch(module_id_t module_id, UE_iterator(UE_info->list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - if (sched_ctrl->rrc_processing_timer == 0 && - UE->Msg4_ACKed && - ((sched_ctrl->next_dl_bwp_id >= 0 && sched_ctrl->active_bwp && sched_ctrl->active_bwp->bwp_Id != sched_ctrl->next_dl_bwp_id) || - (sched_ctrl->next_ul_bwp_id >= 0 && sched_ctrl->active_ubwp && sched_ctrl->active_ubwp->bwp_Id != sched_ctrl->next_ul_bwp_id))) { + if (sched_ctrl->rrc_processing_timer == 0 && UE->Msg4_ACKed && sched_ctrl->next_dl_bwp_id >= 0) { - LOG_W(NR_MAC,"%4d.%2d UE %04x Schedule BWP switch from dl_bwp_id %ld to %ld and from ul_bwp_id %ld to %ld\n", - frame, slot, UE->rnti, sched_ctrl->active_bwp->bwp_Id, sched_ctrl->next_dl_bwp_id, sched_ctrl->active_ubwp->bwp_Id, sched_ctrl->next_ul_bwp_id); - nr_mac_rrc_bwp_switch_req(module_id, frame, slot, UE->rnti, sched_ctrl->next_dl_bwp_id, sched_ctrl->next_ul_bwp_id); + int schedule_bwp_switching = false; + if (sched_ctrl->active_bwp == NULL) { + // Switching from Initial BWP to Dedicated BWP + if (sched_ctrl->next_dl_bwp_id > 0 && sched_ctrl->next_ul_bwp_id > 0) { + schedule_bwp_switching = true; + LOG_W(NR_MAC,"%4d.%2d UE %04x Schedule BWP switch from Initial DL BWP to %ld and from Initial UL BWP to %ld\n", + frame, slot, UE->rnti, sched_ctrl->next_dl_bwp_id, sched_ctrl->next_ul_bwp_id); + } + } else if (sched_ctrl->active_bwp->bwp_Id != sched_ctrl->next_dl_bwp_id && sched_ctrl->active_ubwp->bwp_Id != sched_ctrl->next_ul_bwp_id) { + // Switching between Dedicated BWPs + schedule_bwp_switching = true; + LOG_W(NR_MAC,"%4d.%2d UE %04x Schedule BWP switch from dl_bwp_id %ld to %ld and from ul_bwp_id %ld to %ld\n", + frame, slot, UE->rnti, sched_ctrl->active_bwp->bwp_Id, sched_ctrl->next_dl_bwp_id, sched_ctrl->active_ubwp->bwp_Id, sched_ctrl->next_ul_bwp_id); + } + + if (schedule_bwp_switching) { + AssertFatal(sched_ctrl->next_dl_bwp_id > 0 && sched_ctrl->next_ul_bwp_id > 0, "BWP switching from a Dedicated BWP to the Initial BWP not handled yet!"); + nr_mac_rrc_bwp_switch_req(module_id, frame, slot, UE->rnti, sched_ctrl->next_dl_bwp_id, sched_ctrl->next_ul_bwp_id); + } } } } From 069bebfa480aa8989eb033cfe294b5bd1b3b1363 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Fri, 29 Jul 2022 10:05:34 +0100 Subject: [PATCH 232/267] Fix floating point --- openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c | 5 +++++ openair1/SCHED_NR/phy_procedures_nr_gNB.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 00b053e3ff..e2e9500162 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -1141,6 +1141,11 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, if (count_estimates == n_noise_estimates) { noise_power_per_rb[rb] = sum_re2/n_noise_estimates - (sum_re/n_noise_estimates)*(sum_re/n_noise_estimates) + sum_im2/n_noise_estimates - (sum_im/n_noise_estimates)*(sum_im/n_noise_estimates); + + if (noise_power_per_rb[rb] == 0) { + noise_power_per_rb[rb] = 1; + } + snr_per_rb[rb] = dB_fixed((int32_t)((*signal_power<num_symbols; int32_t srs_received_signal[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size*N_symb_SRS]; int32_t srs_ls_estimated_channel[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size*N_symb_SRS]; - int32_t srs_estimated_channel_freq[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size*N_symb_SRS]; - int32_t srs_estimated_channel_time[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size]; + int32_t srs_estimated_channel_freq[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size*N_symb_SRS] __attribute__ ((aligned(32))); + int32_t srs_estimated_channel_time[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size] __attribute__ ((aligned(32))); int32_t srs_estimated_channel_time_shifted[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size]; uint32_t noise_power_per_rb[srs_pdu->bwp_size]; int8_t snr_per_rb[srs_pdu->bwp_size]; From 6f67792993077e318976e858eecd224e9c505f33 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Fri, 29 Jul 2022 10:42:55 +0100 Subject: [PATCH 233/267] Variable rename --- .../PHY/NR_ESTIMATION/nr_ul_channel_estimation.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index e2e9500162..e5c1ca37d8 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -1115,7 +1115,7 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, const uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start*12; const uint8_t srs_symbols_per_rb = srs_pdu->comb_size == 0 ? 6 : 3; - const uint8_t n_noise_estimates = frame_parms->nb_antennas_rx*srs_symbols_per_rb; + const uint8_t n_noise_est = frame_parms->nb_antennas_rx * srs_symbols_per_rb; uint8_t count_estimates = 0; uint64_t sum_re = 0; uint64_t sum_re2 = 0; @@ -1138,14 +1138,9 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, sum_im2 = sum_im2 + noise_imag[ant*nr_srs_info->sc_list_length+sc_idx]*noise_imag[ant*nr_srs_info->sc_list_length+sc_idx]; count_estimates++; - if (count_estimates == n_noise_estimates) { - noise_power_per_rb[rb] = sum_re2/n_noise_estimates - (sum_re/n_noise_estimates)*(sum_re/n_noise_estimates) + - sum_im2/n_noise_estimates - (sum_im/n_noise_estimates)*(sum_im/n_noise_estimates); - - if (noise_power_per_rb[rb] == 0) { - noise_power_per_rb[rb] = 1; - } - + if (count_estimates == n_noise_est) { + noise_power_per_rb[rb] = max(sum_re2 / n_noise_est - (sum_re / n_noise_est) * (sum_re / n_noise_est) + + sum_im2 / n_noise_est - (sum_im / n_noise_est) * (sum_im / n_noise_est), 1); snr_per_rb[rb] = dB_fixed((int32_t)((*signal_power< Date: Mon, 1 Aug 2022 10:26:14 +0100 Subject: [PATCH 234/267] Remove unused code --- openair2/RRC/NR/L2_nr_interface.c | 104 ------------------------------ 1 file changed, 104 deletions(-) diff --git a/openair2/RRC/NR/L2_nr_interface.c b/openair2/RRC/NR/L2_nr_interface.c index 6fc0566cbd..ab9e3984d8 100644 --- a/openair2/RRC/NR/L2_nr_interface.c +++ b/openair2/RRC/NR/L2_nr_interface.c @@ -49,102 +49,6 @@ extern RAN_CONTEXT_t RC; -int generate_pdcch_ConfigSIB1(NR_PDCCH_ConfigSIB1_t *pdcch_ConfigSIB1, - long ssbSubcarrierSpacing, - long subCarrierSpacingCommon, - channel_bandwidth_t min_channel_bw) { - - nr_ssb_and_cset_mux_pattern_type_t mux_pattern = 0; - - switch (ssbSubcarrierSpacing) { - - case NR_SubcarrierSpacing_kHz15: - if (subCarrierSpacingCommon == NR_SubcarrierSpacing_kHz15) { - pdcch_ConfigSIB1->controlResourceSetZero = rand() % TABLE_38213_13_1_NUM_INDEXES; - mux_pattern = table_38213_13_1_c1[pdcch_ConfigSIB1->controlResourceSetZero]; - } else if (subCarrierSpacingCommon == NR_SubcarrierSpacing_kHz30) { - pdcch_ConfigSIB1->controlResourceSetZero = rand() % TABLE_38213_13_2_NUM_INDEXES; - mux_pattern = table_38213_13_2_c1[pdcch_ConfigSIB1->controlResourceSetZero]; - } else { - AssertFatal(true,"Invalid subCarrierSpacingCommon\n"); - } - break; - - case NR_SubcarrierSpacing_kHz30: - if (subCarrierSpacingCommon == NR_SubcarrierSpacing_kHz15) { - - if ( (min_channel_bw == bw_5MHz) || (min_channel_bw == bw_10MHz) ) { - pdcch_ConfigSIB1->controlResourceSetZero = rand() % TABLE_38213_13_3_NUM_INDEXES; - mux_pattern = table_38213_13_3_c1[pdcch_ConfigSIB1->controlResourceSetZero]; - } else if (min_channel_bw == bw_40MHz) { - pdcch_ConfigSIB1->controlResourceSetZero = rand() % TABLE_38213_13_5_NUM_INDEXES; - mux_pattern = table_38213_13_5_c1[pdcch_ConfigSIB1->controlResourceSetZero]; - } else { - AssertFatal(true,"Invalid min_bandwidth\n"); - } - - } else if (subCarrierSpacingCommon == NR_SubcarrierSpacing_kHz30) { - - if ( (min_channel_bw == bw_5MHz) || (min_channel_bw == bw_10MHz) ) { - pdcch_ConfigSIB1->controlResourceSetZero = rand() % TABLE_38213_13_4_NUM_INDEXES; - mux_pattern = table_38213_13_4_c1[pdcch_ConfigSIB1->controlResourceSetZero]; - } else if (min_channel_bw == bw_40MHz) { - pdcch_ConfigSIB1->controlResourceSetZero = rand() % TABLE_38213_13_6_NUM_INDEXES; - mux_pattern = table_38213_13_6_c1[pdcch_ConfigSIB1->controlResourceSetZero]; - } else { - AssertFatal(true,"Invalid min_bandwidth\n"); - } - - } else { - AssertFatal(true,"Invalid subCarrierSpacingCommon\n"); - } - break; - - case NR_SubcarrierSpacing_kHz120: - if (subCarrierSpacingCommon == NR_SubcarrierSpacing_kHz60) { - pdcch_ConfigSIB1->controlResourceSetZero = rand() % TABLE_38213_13_7_NUM_INDEXES; - mux_pattern = table_38213_13_7_c1[pdcch_ConfigSIB1->controlResourceSetZero]; - } else if (subCarrierSpacingCommon == NR_SubcarrierSpacing_kHz120) { - pdcch_ConfigSIB1->controlResourceSetZero = rand() % TABLE_38213_13_8_NUM_INDEXES; - mux_pattern = table_38213_13_8_c1[pdcch_ConfigSIB1->controlResourceSetZero]; - } else { - AssertFatal(true,"Invalid subCarrierSpacingCommon\n"); - } - break; - - case NR_SubcarrierSpacing_kHz240: - if (subCarrierSpacingCommon == NR_SubcarrierSpacing_kHz60) { - pdcch_ConfigSIB1->controlResourceSetZero = rand() % TABLE_38213_13_9_NUM_INDEXES; - mux_pattern = table_38213_13_9_c1[pdcch_ConfigSIB1->controlResourceSetZero]; - } else if (subCarrierSpacingCommon == NR_SubcarrierSpacing_kHz120) { - pdcch_ConfigSIB1->controlResourceSetZero = rand() % TABLE_38213_13_10_NUM_INDEXES; - mux_pattern = table_38213_13_10_c1[pdcch_ConfigSIB1->controlResourceSetZero]; - } else { - AssertFatal(true,"Invalid subCarrierSpacingCommon\n"); - } - break; - - default: - AssertFatal(true,"Invalid ssbSubcarrierSpacing\n"); - break; - } - - - frequency_range_t frequency_range = FR1; - if(ssbSubcarrierSpacing>=60) { - frequency_range = FR2; - } - - pdcch_ConfigSIB1->searchSpaceZero = 0; - if(mux_pattern == NR_SSB_AND_CSET_MUX_PATTERN_TYPE1 && frequency_range == FR1){ - pdcch_ConfigSIB1->searchSpaceZero = rand() % TABLE_38213_13_11_NUM_INDEXES; - } - if(mux_pattern == NR_SSB_AND_CSET_MUX_PATTERN_TYPE1 && frequency_range == FR2){ - pdcch_ConfigSIB1->searchSpaceZero = rand() % TABLE_38213_13_12_NUM_INDEXES; - } - - return 0; -} int nr_rrc_mac_remove_ue(module_id_t mod_idP, @@ -227,14 +131,6 @@ uint16_t mac_rrc_nr_data_req(const module_id_t Mod_idP, rrc_gNB_carrier_data_t *carrier = &RC.nrrrc[Mod_idP]->carrier; NR_BCCH_BCH_Message_t *mib = &carrier->mib; - // Currently we are getting the pdcch_ConfigSIB1 from the configuration file. - // Uncomment this function for a dynamic pdcch_ConfigSIB1. - //channel_bandwidth_t min_channel_bw = bw_10MHz; // Must be obtained based on TS 38.101-1 Table 5.3.5-1 - //generate_pdcch_ConfigSIB1(carrier->pdcch_ConfigSIB1, - // *carrier->servingcellconfigcommon->ssbSubcarrierSpacing, - // carrier->mib.message.choice.mib->subCarrierSpacingCommon, - // min_channel_bw); - mib->message.choice.mib->pdcch_ConfigSIB1.controlResourceSetZero = carrier->pdcch_ConfigSIB1->controlResourceSetZero; mib->message.choice.mib->pdcch_ConfigSIB1.searchSpaceZero = carrier->pdcch_ConfigSIB1->searchSpaceZero; From 47d604b41f4800af71ade6caa883e78a0bfa71b8 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Mon, 1 Aug 2022 10:35:08 +0100 Subject: [PATCH 235/267] Improve SIB1 length to support maximum value specified in 3GPP TS 38.331 section 5.2.1 The physical layer imposes a limit to the maximum size a SIB can take. The maximum SIB1 or SI message size is 2976 bits. --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 7 ++++--- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 2 +- openair2/RRC/NR/MESSAGES/asn1_msg.c | 12 ++++-------- openair2/RRC/NR/MESSAGES/asn1_msg.h | 4 +--- openair2/RRC/NR/nr_rrc_defs.h | 2 +- 5 files changed, 11 insertions(+), 16 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index 828cb2b880..b26e89624c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -285,7 +285,7 @@ uint32_t schedule_control_sib1(module_id_t module_id, int nrOfSymbols, uint16_t dlDmrsSymbPos, uint8_t candidate_idx, - int num_total_bytes) { + uint16_t num_total_bytes) { gNB_MAC_INST *gNB_mac = RC.nrmac[module_id]; NR_COMMON_channels_t *cc = &gNB_mac->common_channels[CC_id]; @@ -570,7 +570,7 @@ void schedule_nr_sib1(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) // Get SIB1 uint8_t sib1_payload[NR_MAX_SIB_LENGTH/8]; - uint8_t sib1_sdu_length = mac_rrc_nr_data_req(module_idP, CC_id, frameP, BCCH, SI_RNTI, 1, sib1_payload); + uint16_t sib1_sdu_length = mac_rrc_nr_data_req(module_idP, CC_id, frameP, BCCH, SI_RNTI, 1, sib1_payload); LOG_D(NR_MAC,"sib1_sdu_length = %i\n", sib1_sdu_length); LOG_D(NR_MAC,"SIB1: \n"); for (int k=0;kDL_req[CC_id].dl_tti_request_body; int pdu_index = gNB_mac->pdu_index[0]++; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 83097ae260..49c6909a4c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -93,7 +93,7 @@ uint32_t schedule_control_sib1(module_id_t module_id, int nrOfSymbols, uint16_t dlDmrsSymbPos, uint8_t candidate_idx, - int num_total_bytes); + uint16_t num_total_bytes); /* \brief default FR1 DL preprocessor init routine, returns preprocessor to call */ nr_pp_impl_dl nr_init_fr1_dlsch_preprocessor(module_id_t module_id, int CC_id); diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index ff139c9895..687784cafc 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -306,9 +306,8 @@ uint8_t do_MIB_NR(gNB_RRC_INST *rrc,uint32_t frame) { return((enc_rval.encoded+7)/8); } -uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier, - gNB_RrcConfigurationReq *configuration - ) { +uint16_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier, gNB_RrcConfigurationReq *configuration) { + asn_enc_rval_t enc_rval; NR_BCCH_DL_SCH_Message_t *sib1_message = CALLOC(1,sizeof(NR_BCCH_DL_SCH_Message_t)); @@ -661,12 +660,9 @@ uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier, (void *)sib1_message, carrier->SIB1, NR_MAX_SIB_LENGTH/8); - AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", + AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded); - - if (enc_rval.encoded==-1) { - return(-1); - } + AssertFatal(enc_rval.encoded <= NR_MAX_SIB_LENGTH, "ASN1 encoded length %zd bits. 3GPP TS 38.331 section 5.2.1 - The physical layer imposes a limit to the maximum size a SIB can take. The maximum SIB1 or SI message size is 2976 bits.\n", enc_rval.encoded); return((enc_rval.encoded+7)/8); } diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 7dfbabf6bb..ea4b185f6b 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -73,9 +73,7 @@ uint8_t do_MIB_NR(gNB_RRC_INST *rrc, @param carrier pointer to Carrier information @param configuration Pointer Configuration Request structure @return size of encoded bit stream in bytes*/ -uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier, - gNB_RrcConfigurationReq *configuration - ); +uint16_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier, gNB_RrcConfigurationReq *configuration); uint8_t do_SIB23_NR(rrc_gNB_carrier_data_t *carrier, gNB_RrcConfigurationReq *configuration); diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 1b322ed925..b6a92db7a8 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -435,7 +435,7 @@ typedef struct { uint8_t sizeof_MIB; uint8_t *SIB1; - uint8_t sizeof_SIB1; + uint16_t sizeof_SIB1; uint8_t *SIB23; uint8_t sizeof_SIB23; From 48019c33f4b772ef99dd5f8cf317e383bbeb6a5c Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Mon, 1 Aug 2022 11:20:55 +0100 Subject: [PATCH 236/267] Minor optimization in function init_symbol_rotation --- openair1/PHY/MODULATION/nr_modulation.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/openair1/PHY/MODULATION/nr_modulation.c b/openair1/PHY/MODULATION/nr_modulation.c index 1b5c4f4af0..979a31c504 100644 --- a/openair1/PHY/MODULATION/nr_modulation.c +++ b/openair1/PHY/MODULATION/nr_modulation.c @@ -618,32 +618,23 @@ void init_symbol_rotation(NR_DL_FRAME_PARMS *fp) { for (uint8_t ll = 0; ll < 2; ll++){ double f0 = f[ll]; - double Ncpm1 = Ncp0; + LOG_I(PHY, "Doing symbol rotation calculation for gNB TX/RX, f0 %f Hz, Nsymb %d\n", f0, nsymb); c16_t *symbol_rotation = fp->symbol_rotation[ll]; - double tl = 0; - double poff = 2 * M_PI * ((Ncp0 * Tc)) * f0; - double exp_re = cos(poff); - double exp_im = sin(-poff); - symbol_rotation[0].r = (int16_t)floor(exp_re * 32767); - symbol_rotation[0].i = (int16_t)floor(exp_im * 32767); - LOG_I(PHY, "Doing symbol rotation calculation for gNB TX/RX, f0 %f Hz, Nsymb %d\n", f0, nsymb); - LOG_I(PHY, "Symbol rotation %d/%d => (%d,%d)\n", - 0, - nsymb, - symbol_rotation[0].r, - symbol_rotation[0].i); + double tl = 0.0; + double poff = 0.0; + double exp_re = 0.0; + double exp_im = 0.0; - for (int l = 1; l < nsymb; l++) { + for (int l = 0; l < nsymb; l++) { double Ncp; - if (l == (7 * (1 << fp->numerology_index))) { + if (l == 0 || l == (7 * (1 << fp->numerology_index))) { Ncp = Ncp0; } else { Ncp = Ncp1; } - tl += (Nu + Ncpm1) * Tc; poff = 2 * M_PI * (tl + (Ncp * Tc)) * f0; exp_re = cos(poff); exp_im = sin(-poff); @@ -658,7 +649,7 @@ void init_symbol_rotation(NR_DL_FRAME_PARMS *fp) { symbol_rotation[l].i, (poff / 2 / M_PI) - floor(poff / 2 / M_PI)); - Ncpm1 = Ncp; + tl += (Nu + Ncp) * Tc; } } From 9e5a77e6e363318a911c3e1e975fa7cbc1588438 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 1 Aug 2022 15:59:16 +0200 Subject: [PATCH 237/267] Remove max number of HARQ rounds from L1 Contributors: francescomani Rodolphe Bertolini --- openair1/PHY/INIT/nr_init_ue.c | 13 ------------- openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c | 1 - openair1/PHY/NR_TRANSPORT/nr_ulsch.c | 18 +++++++++++++----- openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c | 3 --- .../PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c | 9 --------- openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h | 12 ++---------- openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c | 4 ---- openair1/PHY/defs_gNB.h | 6 ------ openair1/PHY/defs_nr_UE.h | 4 ++-- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 18 +----------------- openair1/SCHED_NR_UE/harq_nr.c | 13 ++++++------- 11 files changed, 24 insertions(+), 77 deletions(-) diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index a332c2067c..7691ca592e 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -34,19 +34,6 @@ #include "PHY/NR_REFSIG/nr_refsig.h" #include "PHY/MODULATION/nr_modulation.h" -#if 0 -void phy_config_harq_ue(module_id_t Mod_id, - int CC_id, - uint8_t gNB_id, - uint16_t max_harq_tx) { - int num_of_threads,num_of_code_words; - PHY_VARS_NR_UE *phy_vars_ue = PHY_vars_UE_g[Mod_id][CC_id]; - - for (num_of_threads=0; num_of_threadsulsch[num_of_threads][gNB_id][num_of_code_words]->Mlimit = max_harq_tx; -} -#endif extern uint16_t beta_cqi[16]; diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index f0f9f4fe34..8672f3ae29 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -123,7 +123,6 @@ NR_gNB_DLSCH_t *new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, bzero(dlsch,sizeof(NR_gNB_DLSCH_t)); dlsch->Kmimo = Kmimo; dlsch->Mdlharq = Mdlharq; - dlsch->Mlimit = 4; dlsch->Nsoft = Nsoft; int txdataf_size = frame_parms->N_RB_DL*NR_SYMBOLS_PER_SLOT*NR_NB_SC_PER_RB*8; // max pdsch encoded length for each layer diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c index 5c6839366c..e56a4607e2 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c @@ -68,12 +68,20 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, ulsch->rnti = ulsch_pdu->rnti; //ulsch->rnti_type; ulsch->harq_mask |= 1<harq_process_id[slot] = harq_pid; - ulsch->harq_processes[harq_pid]->frame=frame; - ulsch->harq_processes[harq_pid]->slot=slot; - ulsch->harq_processes[harq_pid]->handled= 0; - ulsch->harq_processes[harq_pid]->status= NR_ACTIVE; + NR_UL_gNB_HARQ_t *harq = ulsch->harq_processes[harq_pid]; + harq->frame=frame; + harq->slot=slot; + harq->handled = 0; + harq->status= NR_ACTIVE; + harq->new_rx = harq->ndi != ulsch_pdu->pusch_data.new_data_indicator; + if (harq->new_rx) { + harq->ndi = ulsch_pdu->pusch_data.new_data_indicator; + harq->round = 0; + } else { + harq->round++; + } + memcpy((void*)&ulsch->harq_processes[harq_pid]->ulsch_pdu, (void*)ulsch_pdu, sizeof(nfapi_nr_pusch_pdu_t)); LOG_D(PHY,"Initializing nFAPI for ULSCH, UE %d, harq_pid %d\n",ulsch_id,harq_pid); diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c index b9a1430be6..ef5c0c069e 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c @@ -101,7 +101,6 @@ NR_gNB_ULSCH_t *new_gNB_ulsch(uint8_t max_ldpc_iterations, uint16_t N_RB_UL) ulsch = (NR_gNB_ULSCH_t *)malloc16_clear(sizeof(NR_gNB_ULSCH_t)); ulsch->max_ldpc_iterations = max_ldpc_iterations; - ulsch->Mlimit = 4; for (i=0; irnti_type = 0; ulsch->cyclicShift = 0; ulsch->cooperation_flag = 0; - ulsch->Mlimit = 0; ulsch->max_ldpc_iterations = 0; ulsch->last_iteration_cnt = 0; - for (i=0;iharq_process_id[i] = 0; for (i=0; iharq_processes[i]){ diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c index 403f016e79..1635c8bba9 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c @@ -140,7 +140,6 @@ NR_UE_DLSCH_t *new_nr_ue_dlsch(uint8_t Kmimo,uint8_t Mdlharq,uint32_t Nsoft,uint dlsch->Mdlharq = Mdlharq; dlsch->number_harq_processes_for_pdsch = Mdlharq; dlsch->Nsoft = Nsoft; - dlsch->Mlimit = 4; dlsch->max_ldpc_iterations = max_ldpc_iterations; for (int i=0; iround %d\n", // phy_vars_ue->Mod_id,nr_slot_rx,harq_process->TBS,harq_process->mcs,harq_process->nb_rb, harq_process->round); harq_process->status = SCH_IDLE; - harq_process->DLround = 0; harq_process->ack = 1; //LOG_D(PHY,"[UE %d] DLSCH: Setting ACK for SFN/SF %d/%d (pid %d, status %d, round %d, TBS %d, mcs %d)\n", @@ -237,11 +235,6 @@ bool nr_ue_postDecode(PHY_VARS_NR_UE *phy_vars_ue, notifiedFIFO_elt_t *req, bool //LOG_D(PHY,"[UE %d] DLSCH: Setting NAK for SFN/SF %d/%d (pid %d, status %d, round %d, TBS %d, mcs %d) Kr %d r %d harq_process->round %d\n", // phy_vars_ue->Mod_id, frame, nr_slot_rx, harq_pid,harq_process->status, harq_process->round,harq_process->TBS,harq_process->mcs,Kr,r,harq_process->round); harq_process->ack = 0; - if (harq_process->DLround >= dlsch->Mlimit) { - harq_process->status = SCH_IDLE; - harq_process->DLround = 0; - phy_vars_ue->dl_stats[4]++; - } //if(is_crnti) { // LOG_D(PHY,"[UE %d] DLSCH: Setting NACK for nr_slot_rx %d (pid %d, pid status %d, round %d/Max %d, TBS %d)\n", @@ -496,8 +489,6 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, } */ nb_rb = harq_process->nb_rb; - harq_process->trials[harq_process->DLround]++; - A = harq_process->TBS; ret = dlsch->max_ldpc_iterations + 1; dlsch->last_iteration_cnt = ret; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h index fd8eada245..96f31a1624 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h @@ -161,15 +161,13 @@ typedef struct { //uint8_t num_cba_dci[10]; /// allocated CBA RNTI //uint16_t cba_rnti[4];//NUM_MAX_CBA_GROUP]; - /// UL max-harq-retransmission - uint16_t Mlimit; } NR_UE_ULSCH_t; typedef struct { /// Indicator of first reception uint8_t first_rx; /// Last Ndi received for this process on DCI (used for C-RNTI only) - uint8_t DCINdi; + uint8_t Ndi; /// DLSCH status flag indicating SCH_status_t status; /// Transport block size @@ -241,10 +239,6 @@ typedef struct { vrb_t vrb_type; /// downlink power offset field uint8_t dl_power_off; - /// trials per round statistics - uint32_t trials[8]; - /// error statistics per round - uint32_t errors[8]; /// codeword this transport block is mapped to uint8_t codeword; /// HARQ-ACKs @@ -311,9 +305,7 @@ typedef struct { /// Maximum number of LDPC iterations uint8_t max_ldpc_iterations; /// number of iterations used in last turbo decoding - uint8_t last_iteration_cnt; - /// Maximum number of HARQ rounds - uint8_t Mlimit; + uint8_t last_iteration_cnt; } NR_UE_DLSCH_t; typedef enum {format0_0, diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c index d09f2554cc..ef952b0152 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c @@ -130,10 +130,6 @@ NR_UE_ULSCH_t *new_nr_ue_ulsch(uint16_t N_RB_UL, int number_of_harq_pids, NR_DL_ memset(ulsch, 0, sizeof(*ulsch)); ulsch->number_harq_processes_for_pusch = NR_MAX_ULSCH_HARQ_PROCESSES; - ulsch->Mlimit = 4; // maximum harq retransmissions - - //for (i=0; i<10; i++) - //ulsch->harq_ids[i] = 0; for (int i = 0; i < number_of_harq_pids; i++) { diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 9ed6f50616..32c9af84cf 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -188,8 +188,6 @@ typedef struct { uint8_t codebook_index; /// Maximum number of HARQ processes uint8_t Mdlharq; - /// Maximum number of HARQ rounds - uint8_t Mlimit; /// MIMO transmission mode indicator for this sub-frame uint8_t Kmimo; /// Nsoft parameter related to UE Category @@ -345,8 +343,6 @@ typedef struct { typedef struct { /// Pointers to 16 HARQ processes for the ULSCH NR_UL_gNB_HARQ_t *harq_processes[NR_MAX_ULSCH_HARQ_PROCESSES]; - /// Current HARQ process id - int harq_process_id[NR_MAX_SLOTS_PER_FRAME]; /// HARQ process mask, indicates which processes are currently active uint16_t harq_mask; /// ACK/NAK Bundling flag @@ -373,8 +369,6 @@ typedef struct { uint8_t cyclicShift; /// for cooperative communication uint8_t cooperation_flag; - /// Maximum number of HARQ rounds - uint8_t Mlimit; /// Maximum number of LDPC iterations uint8_t max_ldpc_iterations; /// number of iterations used in last LDPC decoding diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index bd6808c54d..890e4e2ed0 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -978,8 +978,8 @@ typedef struct { SLIST_HEAD(ral_thresholds_gen_poll_s, ral_threshold_phy_t) ral_thresholds_gen_polled[RAL_LINK_PARAM_GEN_MAX]; SLIST_HEAD(ral_thresholds_lte_poll_s, ral_threshold_phy_t) ral_thresholds_lte_polled[RAL_LINK_PARAM_LTE_MAX]; #endif - - int dl_stats[5]; + int dl_errors; + int dl_stats[8]; void* scopeData; } PHY_VARS_NR_UE; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index ca0cd380d2..6d833a530a 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -242,13 +242,6 @@ void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req) { ulsch_harq->ulsch_pdu.rb_size, ulsch_harq->TBS, r); - ulsch_harq->round++; - if (ulsch_harq->round >= ulsch->Mlimit) { - ulsch_harq->status = SCH_IDLE; - ulsch_harq->round = 0; - ulsch_harq->handled = 0; - ulsch->harq_mask &= ~(1 << rdata->harq_pid); - } ulsch_harq->handled = 1; LOG_D(PHY, "ULSCH %d in error\n",rdata->ulsch_id); @@ -413,17 +406,8 @@ void nr_fill_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int ULSCH_id, if (timing_advance_update > 63) timing_advance_update = 63; if (crc_flag == 0) LOG_D(PHY, "%d.%d : Received PUSCH : Estimated timing advance PUSCH is = %d, timing_advance_update is %d \n", frame,slot_rx,sync_pos,timing_advance_update); - else if (harq_process->round>0 || dtx_flag == 0) { // increment round if crc_flag == 1 and not(dtx_flag ==1 and round==0) - harq_process->round++; - if (harq_process->round >= ulsch->Mlimit) { - harq_process->status = SCH_IDLE; - harq_process->round = 0; - harq_process->handled = 0; - ulsch->harq_mask &= ~(1 << harq_pid); - } - } - // estimate UL_CQI for MAC + // estimate UL_CQI for MAC int SNRtimes10 = dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_power_tot) - dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot); diff --git a/openair1/SCHED_NR_UE/harq_nr.c b/openair1/SCHED_NR_UE/harq_nr.c index a9ff01d78a..795cea5dfa 100644 --- a/openair1/SCHED_NR_UE/harq_nr.c +++ b/openair1/SCHED_NR_UE/harq_nr.c @@ -308,7 +308,7 @@ void init_downlink_harq_status(NR_DL_UE_HARQ_t *dl_harq) dl_harq->status = SCH_IDLE; dl_harq->first_rx = 1; dl_harq->DLround = 0; - dl_harq->DCINdi = 1; + dl_harq->Ndi = 1; dl_harq->ack = DL_ACKNACK_NO_SET; } @@ -329,7 +329,7 @@ void init_downlink_harq_status(NR_DL_UE_HARQ_t *dl_harq) * *********************************************************************/ -void downlink_harq_process(NR_DL_UE_HARQ_t *dl_harq, int harq_pid, int ndi, int rv, uint8_t rnti_type) { +void downlink_harq_process(NR_DL_UE_HARQ_t *dl_harq, int harq_pid, int dci_ndi, int rv, uint8_t rnti_type) { if (rnti_type == _SI_RNTI_ || rnti_type == _P_RNTI_ || @@ -339,10 +339,9 @@ void downlink_harq_process(NR_DL_UE_HARQ_t *dl_harq, int harq_pid, int ndi, int dl_harq->first_rx = 1; } else { LOG_D(PHY,"receive harq process: %p harqPid=%d, rv=%d, ndi=%d, rntiType=%d new transmission= %s\n", - dl_harq, harq_pid, rv, ndi, rnti_type, dl_harq->DCINdi != ndi ? "yes":"no"); + dl_harq, harq_pid, rv, dci_ndi, rnti_type, dl_harq->Ndi != dci_ndi ? "yes":"no"); AssertFatal(rv<4 && rv>=0, "invalid redondancy version %d\n", rv); - - if (ndi!=dl_harq->DCINdi) { + if (dci_ndi!=dl_harq->Ndi) { if (dl_harq->ack == DL_NACK) LOG_D(PHY,"New transmission on a harq pid (%d) never acknowledged\n", harq_pid); else @@ -354,7 +353,7 @@ void downlink_harq_process(NR_DL_UE_HARQ_t *dl_harq, int harq_pid, int ndi, int LOG_D(PHY,"Starting retransmission on a harq pid (%d), rv (%d)\n", harq_pid, rv); } - if (ndi!=dl_harq->DCINdi) { + if (dci_ndi!=dl_harq->Ndi) { dl_harq->first_rx = true; dl_harq->DLround = 0; } else { @@ -364,7 +363,7 @@ void downlink_harq_process(NR_DL_UE_HARQ_t *dl_harq, int harq_pid, int ndi, int dl_harq->status = ACTIVE; - dl_harq->DCINdi = ndi; + dl_harq->Ndi = dci_ndi; //dl_harq->status = SCH_IDLE; } } From 989c22a46c311e51cfca30c7c697da8ff89f8dd7 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 1 Aug 2022 16:05:26 +0200 Subject: [PATCH 238/267] Limit RV to interval of 0..3 Contributors francescomani Rodolphe Bertolini --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 9 ++++++--- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 6 +++--- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 6 +++--- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 6daa68afed..ef7c91151b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1090,13 +1090,16 @@ void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, pusch_pdu->vrb_to_prb_mapping = 0; pusch_pdu->frequency_hopping = fh; - //pusch_pdu->tx_direct_current_location;//The uplink Tx Direct Current location for the carrier. Only values in the value range of this field between 0 and 3299, which indicate the subcarrier index within the carrier corresponding 1o the numerology of the corresponding uplink BWP and value 3300, which indicates "Outside the carrier" and value 3301, which indicates "Undetermined position within the carrier" are used. [TS38.331, UplinkTxDirectCurrentBWP IE] + //pusch_pdu->tx_direct_current_location; + //The uplink Tx Direct Current location for the carrier. Only values in the value range of this field between 0 and 3299, + //which indicate the subcarrier index within the carrier corresponding 1o the numerology of the corresponding uplink BWP and value 3300, + //which indicates "Outside the carrier" and value 3301, which indicates "Undetermined position within the carrier" are used. [TS38.331, UplinkTxDirectCurrentBWP IE] pusch_pdu->uplink_frequency_shift_7p5khz = 0; //Resource Allocation in time domain pusch_pdu->start_symbol_index = start_symbol_index; pusch_pdu->nr_of_symbols = nr_of_symbols; //Optional Data only included if indicated in pduBitmap - pusch_pdu->pusch_data.rv_index = nr_rv_round_map[round]; + pusch_pdu->pusch_data.rv_index = nr_rv_round_map[round%4]; pusch_pdu->pusch_data.harq_process_id = 0; pusch_pdu->pusch_data.new_data_indicator = 1; pusch_pdu->pusch_data.num_cb = 0; @@ -1804,7 +1807,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra pdsch_pdu_rel15->qamModOrder[0] = 2; pdsch_pdu_rel15->mcsIndex[0] = mcsIndex; pdsch_pdu_rel15->mcsTable[0] = mcsTableIdx; - pdsch_pdu_rel15->rvIndex[0] = nr_rv_round_map[harq->round]; + pdsch_pdu_rel15->rvIndex[0] = nr_rv_round_map[harq->round%4]; pdsch_pdu_rel15->dataScramblingId = *scc->physCellId; pdsch_pdu_rel15->nrOfLayers = 1; pdsch_pdu_rel15->transmissionScheme = 0; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index 828cb2b880..398f19d43a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -437,7 +437,7 @@ void nr_fill_nfapi_dl_sib1_pdu(int Mod_idP, pdsch_pdu_rel15->qamModOrder[0] = 2; pdsch_pdu_rel15->mcsIndex[0] = gNB_mac->sched_ctrlCommon->sched_pdsch.mcs; pdsch_pdu_rel15->mcsTable[0] = 0; - pdsch_pdu_rel15->rvIndex[0] = nr_rv_round_map[0]; + pdsch_pdu_rel15->rvIndex[0] = 0; pdsch_pdu_rel15->dataScramblingId = *scc->physCellId; pdsch_pdu_rel15->nrOfLayers = 1; pdsch_pdu_rel15->transmissionScheme = 0; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index d32709e731..c055638bf5 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1017,7 +1017,7 @@ void nr_schedule_ue_spec(module_id_t module_id, TBS, current_harq_pid, harq->round, - nr_rv_round_map[harq->round], + nr_rv_round_map[harq->round%4], harq->ndi, pucch->timing_indicator, pucch->frame, @@ -1085,8 +1085,8 @@ void nr_schedule_ue_spec(module_id_t module_id, pdsch_pdu->mcsIndex[0] = sched_pdsch->mcs; pdsch_pdu->mcsTable[0] = ps->mcsTableIdx; AssertFatal(harq!=NULL,"harq is null\n"); - AssertFatal(harq->round<4,"%d",harq->round); - pdsch_pdu->rvIndex[0] = nr_rv_round_map[harq->round]; + AssertFatal(harq->roundharq_round_max,"%d",harq->round); + pdsch_pdu->rvIndex[0] = nr_rv_round_map[harq->round%4]; pdsch_pdu->TBSize[0] = TBS; pdsch_pdu->dataScramblingId = *scc->physCellId; pdsch_pdu->nrOfLayers = nrOfLayers; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index f654e8e1a6..def298cad0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1672,7 +1672,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) sched_pusch->tb_size, harq_id, cur_harq->round, - nr_rv_round_map[cur_harq->round], + nr_rv_round_map[cur_harq->round%4], cur_harq->ndi, sched_ctrl->estimated_ul_buffer, sched_ctrl->sched_ul_bytes, @@ -1768,8 +1768,8 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) pusch_pdu->nr_of_symbols = ps->nrOfSymbols; /* PUSCH PDU */ - AssertFatal(cur_harq->round < 4, "Indexing nr_rv_round_map[%d] is out of bounds\n", cur_harq->round); - pusch_pdu->pusch_data.rv_index = nr_rv_round_map[cur_harq->round]; + AssertFatal(cur_harq->round < nr_mac->harq_round_max, "Indexing nr_rv_round_map[%d] is out of bounds\n", cur_harq->round%4); + pusch_pdu->pusch_data.rv_index = nr_rv_round_map[cur_harq->round%4]; pusch_pdu->pusch_data.harq_process_id = harq_id; pusch_pdu->pusch_data.new_data_indicator = cur_harq->ndi; pusch_pdu->pusch_data.tb_size = sched_pusch->tb_size; From 4ad4edb8715871ece417dc902b641818ee7cfebd Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 1 Aug 2022 16:03:17 +0200 Subject: [PATCH 239/267] Log arbitrary number of HARQ rounds Contributors francescomani Robert Schmidt --- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 12 +++++- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 2 +- openair2/LAYER2/NR_MAC_gNB/main.c | 42 ++++++++++++-------- 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 38fa3880bb..c431c6653c 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -1476,7 +1476,17 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue, if ((frame_rx%64 == 0) && (nr_slot_rx==0)) { LOG_I(NR_PHY,"============================================\n"); - LOG_I(NR_PHY,"Harq round stats for Downlink: %d/%d/%d/%d DLSCH errors: %d\n",ue->dl_stats[0],ue->dl_stats[1],ue->dl_stats[2],ue->dl_stats[3],ue->dl_stats[4]); + // fixed text + 8 HARQs rounds à 10 ("999999999/") + NULL + // if we use 999999999 HARQs, that should be sufficient for at least 138 hours + const size_t harq_output_len = 31 + 10 * 8 + 1; + char output[harq_output_len]; + char *p = output; + const char *end = output + harq_output_len; + p += snprintf(p, end - p, "Harq round stats for Downlink: %d", ue->dl_stats[0]); + for (int round = 1; round < 16 && (round < 3 || ue->dl_stats[round] != 0); ++round) + p += snprintf(p, end - p,"/%d", ue->dl_stats[round]); + LOG_I(NR_PHY,"%s/0\n", output); + LOG_I(NR_PHY,"============================================\n"); } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index ccb1b4e72a..1759f55995 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -3586,7 +3586,7 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info, #endif */ - LOG_I(NR_MAC, "[%d.%d] Received TA_COMMAND %u TAGID %u CC_id %d\n", frameP, slot, ul_time_alignment->ta_command, ul_time_alignment->tag_id, CC_id); + LOG_I(NR_MAC, "[%d.%d] Received TA_COMMAND %u TAGID %u CC_id %d\n", frameP, slot, ul_time_alignment->ta_command, ul_time_alignment->tag_id, CC_id); break; case DL_SCH_LCID_CON_RES_ID: diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 45df6291f4..50434b26b3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -105,17 +105,21 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset end - output, "UE %04x: CQI %d, RI %d, PMI (%d,%d)\n", UE->rnti, - UE->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb, - UE->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.ri+1, - UE->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1, - UE->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2); + sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb, + sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.ri+1, + sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1, + sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2); output += snprintf(output, end - output, - "UE %04x: dlsch_rounds %"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64", dlsch_errors %"PRIu64", pucch0_DTX %d, BLER %.5f MCS %d\n", - UE->rnti, - stats->dl.rounds[0], stats->dl.rounds[1], - stats->dl.rounds[2], stats->dl.rounds[3], + "UE %04x: dlsch_rounds ", UE->rnti); + output += snprintf(output, end - output, "%"PRIu64, stats->dl.rounds[0]); + for (int i = 1; i < gNB->harq_round_max; i++) + output += snprintf(output, end - output, "/%"PRIu64, stats->dl.rounds[i]); + + output += snprintf(output, + end - output, + ", dlsch_errors %"PRIu64", pucch0_DTX %d, BLER %.5f MCS %d\n", stats->dl.errors, stats->pucch0_DTX, sched_ctrl->dl_bler_stats.bler, @@ -127,23 +131,27 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset output += snprintf(output, end - output, "UE %04x: dlsch_total_bytes %"PRIu64"\n", - UE->rnti, - stats->dl.total_bytes); + UE->rnti, stats->dl.total_bytes); output += snprintf(output, end - output, - "UE %04x: ulsch_rounds %"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64", ulsch_DTX %d, ulsch_errors %"PRIu64", BLER %.5f MCS %d\n", - UE->rnti, - stats->ul.rounds[0], stats->ul.rounds[1], - stats->ul.rounds[2], stats->ul.rounds[3], + "UE %04x: ulsch_rounds ", UE->rnti); + output += snprintf(output, end - output, "%"PRIu64, stats->ul.rounds[0]); + for (int i = 1; i < gNB->harq_round_max; i++) + output += snprintf(output, end - output, "/%"PRIu64, stats->ul.rounds[i]); + + output += snprintf(output, + end - output, + ", ulsch_DTX %d, ulsch_errors %"PRIu64", BLER %.5f MCS %d\n", stats->ulsch_DTX, stats->ul.errors, sched_ctrl->ul_bler_stats.bler, sched_ctrl->ul_bler_stats.mcs); output += snprintf(output, end - output, - "UE %04x: ulsch_total_bytes_scheduled %"PRIu64", ulsch_total_bytes_received %"PRIu64"\n", - UE->rnti, - stats->ulsch_total_bytes_scheduled, stats->ul.total_bytes); + "UE %04x: ulsch_total_bytes_scheduled %"PRIu64", ulsch_total_bytes_received %"PRIu64"\n", + UE->rnti, + stats->ulsch_total_bytes_scheduled, stats->ul.total_bytes); + for (int lc_id = 0; lc_id < 63; lc_id++) { if (stats->dl.lc_bytes[lc_id] > 0) output += snprintf(output, From 840cf403db721ce4f6c7c68d64e1dd9327f9968c Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 1 Aug 2022 16:06:52 +0200 Subject: [PATCH 240/267] Make max num of HARQ tx configurable per UL/DL Contributors francescomani Robert Schmidt --- openair1/SIMULATION/NR_PHY/dlsim.c | 2 + openair2/GNB_APP/MACRLC_nr_paramdef.h | 53 ++++++++++++++++--- openair2/GNB_APP/gnb_config.c | 7 ++- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 7 ++- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 8 +-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 17 +++--- openair2/LAYER2/NR_MAC_gNB/main.c | 4 +- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 3 +- 8 files changed, 76 insertions(+), 25 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 8500749fe2..6ebdc203c4 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -761,6 +761,8 @@ int main(int argc, char **argv) gNB_RRC_INST rrc; memset((void*)&rrc,0,sizeof(rrc)); + gNB_mac->dl_bler.harq_round_max = num_rounds; + /* // read in SCGroupConfig AssertFatal(scg_fd != NULL,"no reconfig.raw file\n"); diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index 4359cb0c86..0a50d19e13 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -67,7 +67,8 @@ #define CONFIG_STRING_MACRLC_UL_BLER_TARGET_UPPER "ul_bler_target_upper" #define CONFIG_STRING_MACRLC_UL_BLER_TARGET_LOWER "ul_bler_target_lower" #define CONFIG_STRING_MACRLC_UL_MAX_MCS "ul_max_mcs" -#define CONFIG_STRING_MACRLC_HARQ_ROUND_MAX "harq_round_max" +#define CONFIG_STRING_MACRLC_DL_HARQ_ROUND_MAX "dl_harq_round_max" +#define CONFIG_STRING_MACRLC_UL_HARQ_ROUND_MAX "ul_harq_round_max" #define CONFIG_STRING_MACRLC_MIN_GRANT_PRB "min_grant_prb" #define CONFIG_STRING_MACRLC_MIN_GRANT_MCS "min_grant_mcs" @@ -97,7 +98,7 @@ {CONFIG_STRING_MACRLC_ULSCH_MAX_FRAME_INACTIVITY, NULL, 0, uptr:NULL, defintval:10, TYPE_UINT, 0}, \ {CONFIG_STRING_MACRLC_PUSCHTARGETSNRX10, NULL, 0, iptr:NULL, defintval:200, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUCCHTARGETSNRX10, NULL, 0, iptr:NULL, defintval:150, TYPE_INT, 0}, \ -{CONFIG_STRING_MACRLC_UL_PRBBLACK_SNR_THRESHOLD, "SNR threshold to decide whether a PRB will be blacklisted or not", 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ +{CONFIG_STRING_MACRLC_UL_PRBBLACK_SNR_THRESHOLD, "SNR threshold to decide whether a PRB will be blacklisted or not", 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUCCHFAILURETHRES, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUSCHFAILURETHRES, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_DL_BLER_TARGET_UPPER, "Upper threshold of BLER to decrease DL MCS", 0, dblptr:NULL, defdblval:0.15, TYPE_DOUBLE, 0}, \ @@ -106,9 +107,10 @@ {CONFIG_STRING_MACRLC_UL_BLER_TARGET_UPPER, "Upper threshold of BLER to decrease UL MCS", 0, dblptr:NULL, defdblval:0.15, TYPE_DOUBLE, 0}, \ {CONFIG_STRING_MACRLC_UL_BLER_TARGET_LOWER, "Lower threshold of BLER to increase UL MCS", 0, dblptr:NULL, defdblval:0.05, TYPE_DOUBLE, 0}, \ {CONFIG_STRING_MACRLC_UL_MAX_MCS, "Maximum UL MCS that should be used", 0, u8ptr:NULL, defintval:9, TYPE_UINT8, 0}, \ -{CONFIG_STRING_MACRLC_HARQ_ROUND_MAX, "Maximum number of HARQ rounds", 0, u8ptr:NULL, defintval:4, TYPE_UINT8, 0}, \ +{CONFIG_STRING_MACRLC_DL_HARQ_ROUND_MAX, "Maximum number of DL HARQ rounds", 0, u8ptr:NULL, defintval:4, TYPE_UINT8, 0}, \ +{CONFIG_STRING_MACRLC_UL_HARQ_ROUND_MAX, "Maximum number of UL HARQ rounds", 0, u8ptr:NULL, defintval:4, TYPE_UINT8, 0}, \ {CONFIG_STRING_MACRLC_MIN_GRANT_PRB, "Minimal Periodic ULSCH Grant PRBs", 0, u8ptr:NULL, defintval:5, TYPE_UINT8, 0}, \ -{CONFIG_STRING_MACRLC_MIN_GRANT_MCS, "Minimal Periodic ULSCH Grant MCS", 0, u8ptr:NULL, defintval:9, TYPE_UINT8, 0} \ +{CONFIG_STRING_MACRLC_MIN_GRANT_MCS, "Minimal Periodic ULSCH Grant MCS", 0, u8ptr:NULL, defintval:9, TYPE_UINT8, 0}, \ } #define MACRLC_CC_IDX 0 #define MACRLC_TRANSPORT_N_PREFERENCE_IDX 1 @@ -139,9 +141,46 @@ #define MACRLC_UL_BLER_TARGET_UPPER_IDX 26 #define MACRLC_UL_BLER_TARGET_LOWER_IDX 27 #define MACRLC_UL_MAX_MCS_IDX 28 -#define MACRLC_HARQ_ROUND_MAX_IDX 29 -#define MACRLC_MIN_GRANT_PRB_IDX 30 -#define MACRLC_MIN_GRANT_MCS_IDX 31 +#define MACRLC_DL_HARQ_ROUND_MAX_IDX 29 +#define MACRLC_UL_HARQ_ROUND_MAX_IDX 30 +#define MACRLC_MIN_GRANT_PRB_IDX 31 +#define MACRLC_MIN_GRANT_MCS_IDX 32 + +#define MACRLCPARAMS_CHECK { \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s2 = { config_check_intrange, {1, 8} } }, /* DL max HARQ rounds */ \ + { .s2 = { config_check_intrange, {1, 8} } }, /* UL max HARQ rounds */ \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ +} /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ #endif diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 76b3772307..225daec37b 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -816,6 +816,10 @@ void RCconfig_nr_macrlc() { } paramdef_t MacRLC_Params[] = MACRLCPARAMS_DESC; paramlist_def_t MacRLC_ParamList = {CONFIG_STRING_MACRLC_LIST,NULL,0}; + /* map parameter checking array instances to parameter definition array instances */ + checkedparam_t config_check_MacRLCParams [] = MACRLCPARAMS_CHECK; + for (int i = 0; i < sizeof(MacRLC_Params) / sizeof(paramdef_t); ++i) + MacRLC_Params[i].chkPptr = &(config_check_MacRLCParams[i]); config_getlist( &MacRLC_ParamList,MacRLC_Params,sizeof(MacRLC_Params)/sizeof(paramdef_t), NULL); if ( MacRLC_ParamList.numelt > 0) { @@ -887,11 +891,12 @@ void RCconfig_nr_macrlc() { dl_bler_options->upper = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_BLER_TARGET_UPPER_IDX].dblptr); dl_bler_options->lower = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_BLER_TARGET_LOWER_IDX].dblptr); dl_bler_options->max_mcs = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_MAX_MCS_IDX].u8ptr); + dl_bler_options->harq_round_max = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_HARQ_ROUND_MAX_IDX].u8ptr); NR_bler_options_t *ul_bler_options = &RC.nrmac[j]->ul_bler; ul_bler_options->upper = *(MacRLC_ParamList.paramarray[j][MACRLC_UL_BLER_TARGET_UPPER_IDX].dblptr); ul_bler_options->lower = *(MacRLC_ParamList.paramarray[j][MACRLC_UL_BLER_TARGET_LOWER_IDX].dblptr); ul_bler_options->max_mcs = *(MacRLC_ParamList.paramarray[j][MACRLC_UL_MAX_MCS_IDX].u8ptr); - RC.nrmac[j]->harq_round_max = *(MacRLC_ParamList.paramarray[j][MACRLC_HARQ_ROUND_MAX_IDX].u8ptr); + ul_bler_options->harq_round_max = *(MacRLC_ParamList.paramarray[j][MACRLC_UL_HARQ_ROUND_MAX_IDX].u8ptr); RC.nrmac[j]->min_grant_prb = *(MacRLC_ParamList.paramarray[j][MACRLC_MIN_GRANT_PRB_IDX].u8ptr); RC.nrmac[j]->min_grant_mcs = *(MacRLC_ParamList.paramarray[j][MACRLC_MIN_GRANT_MCS_IDX].u8ptr); RC.nrmac[j]->num_ulprbbl = num_prbbl; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index c055638bf5..5027a77de8 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -643,7 +643,10 @@ void pf_dl(module_id_t module_id, const NR_bler_options_t *bo = &mac->dl_bler; const int max_mcs_table = ps->mcsTableIdx == 1 ? 27 : 28; const int max_mcs = min(sched_ctrl->dl_max_mcs, max_mcs_table); - sched_pdsch->mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->dl_bler_stats, max_mcs, frame); + if (bo->harq_round_max == 1) + sched_pdsch->mcs = max_mcs; + else + sched_pdsch->mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->dl_bler_stats, max_mcs, frame); UE->layers = set_dl_nrOfLayers(sched_ctrl); const uint8_t Qm = nr_get_Qm_dl(sched_pdsch->mcs, ps->mcsTableIdx); const uint16_t R = nr_get_code_rate_dl(sched_pdsch->mcs, ps->mcsTableIdx); @@ -1085,7 +1088,7 @@ void nr_schedule_ue_spec(module_id_t module_id, pdsch_pdu->mcsIndex[0] = sched_pdsch->mcs; pdsch_pdu->mcsTable[0] = ps->mcsTableIdx; AssertFatal(harq!=NULL,"harq is null\n"); - AssertFatal(harq->roundharq_round_max,"%d",harq->round); + AssertFatal(harq->rounddl_bler.harq_round_max,"%d",harq->round); pdsch_pdu->rvIndex[0] = nr_rv_round_map[harq->round%4]; pdsch_pdu->TBSize[0] = TBS; pdsch_pdu->dataScramblingId = *scc->physCellId; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index a57b04668b..4df0566c66 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -1456,7 +1456,7 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, for (int harq_bit = 0; harq_bit < uci_01->harq->num_harq; harq_bit++) { const uint8_t harq_value = uci_01->harq->harq_list[harq_bit].harq_value; const uint8_t harq_confidence = uci_01->harq->harq_confidence_level; - NR_UE_harq_t *harq = find_harq(frame, slot, UE, RC.nrmac[mod_id]->harq_round_max); + NR_UE_harq_t *harq = find_harq(frame, slot, UE, RC.nrmac[mod_id]->dl_bler.harq_round_max); if (!harq) { LOG_E(NR_MAC, "Oh no! Could not find a harq in %s!\n", __FUNCTION__); break; @@ -1465,7 +1465,7 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, const int8_t pid = sched_ctrl->feedback_dl_harq.head; remove_front_nr_list(&sched_ctrl->feedback_dl_harq); LOG_D(NR_MAC,"%4d.%2d bit %d pid %d ack/nack %d\n",frame, slot, harq_bit,pid,harq_value); - handle_dl_harq(UE, pid, harq_value == 0 && harq_confidence == 0, RC.nrmac[mod_id]->harq_round_max); + handle_dl_harq(UE, pid, harq_value == 0 && harq_confidence == 0, RC.nrmac[mod_id]->dl_bler.harq_round_max); if (harq_confidence == 1) UE->mac_stats.pucch0_DTX++; } } @@ -1518,13 +1518,13 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, // iterate over received harq bits for (int harq_bit = 0; harq_bit < uci_234->harq.harq_bit_len; harq_bit++) { const int acknack = ((uci_234->harq.harq_payload[harq_bit >> 3]) >> harq_bit) & 0x01; - NR_UE_harq_t *harq = find_harq(frame, slot, UE, RC.nrmac[mod_id]->harq_round_max); + NR_UE_harq_t *harq = find_harq(frame, slot, UE, RC.nrmac[mod_id]->dl_bler.harq_round_max); if (!harq) break; DevAssert(harq->is_waiting); const int8_t pid = sched_ctrl->feedback_dl_harq.head; remove_front_nr_list(&sched_ctrl->feedback_dl_harq); - handle_dl_harq(UE, pid, uci_234->harq.harq_crc != 1 && acknack, RC.nrmac[mod_id]->harq_round_max); + handle_dl_harq(UE, pid, uci_234->harq.harq_crc != 1 && acknack, RC.nrmac[mod_id]->dl_bler.harq_round_max); } } if ((uci_234->pduBitmap >> 2) & 0x01) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index def298cad0..fddfe6e76f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -452,7 +452,7 @@ void handle_nr_ul_harq(const int CC_idP, remove_front_nr_list(&sched_ctrl->feedback_ul_harq); sched_ctrl->ul_harq_processes[harq_pid].is_waiting = false; - if(sched_ctrl->ul_harq_processes[harq_pid].round >= RC.nrmac[mod_id]->harq_round_max - 1) { + if(sched_ctrl->ul_harq_processes[harq_pid].round >= RC.nrmac[mod_id]->ul_bler.harq_round_max - 1) { abort_nr_ul_harq(UE, harq_pid); } else { sched_ctrl->ul_harq_processes[harq_pid].round++; @@ -473,7 +473,7 @@ void handle_nr_ul_harq(const int CC_idP, harq_pid, crc_pdu->rnti); add_tail_nr_list(&sched_ctrl->available_ul_harq, harq_pid); - } else if (harq->round >= RC.nrmac[mod_id]->harq_round_max - 1) { + } else if (harq->round >= RC.nrmac[mod_id]->ul_bler.harq_round_max - 1) { abort_nr_ul_harq(UE, harq_pid); LOG_D(NR_MAC, "RNTI %04x: Ulharq id %d crc failed in all rounds\n", @@ -749,8 +749,8 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, return; } - if (ra->msg3_round >= MAX_HARQ_ROUNDS - 1) { - LOG_D(NR_MAC, "Random Access %i failed at state %i (Reached msg3 max harq rounds)\n", i, ra->state); + if (ra->msg3_round >= gNB_mac->ul_bler.harq_round_max - 1) { + LOG_W(NR_MAC, "Random Access %i failed at state %i (Reached msg3 max harq rounds)\n", i, ra->state); nr_mac_remove_ra_rnti(gnb_mod_idP, ra->rnti); nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra); return; @@ -1148,7 +1148,10 @@ void pf_ul(module_id_t module_id, const NR_bler_options_t *bo = &nrmac->ul_bler; const int max_mcs = bo->max_mcs; /* no per-user maximum MCS yet */ - sched_pusch->mcs = get_mcs_from_bler(bo, stats, &UE->UE_sched_ctrl.ul_bler_stats, max_mcs, frame); + if (bo->harq_round_max == 1) + sched_pusch->mcs = max_mcs; + else + sched_pusch->mcs = get_mcs_from_bler(bo, stats, &UE->UE_sched_ctrl.ul_bler_stats, max_mcs, frame); /* Schedule UE on SR or UL inactivity and no data (otherwise, will be scheduled * based on data to transmit) */ @@ -1626,7 +1629,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; /* Statistics */ - AssertFatal(cur_harq->round < 8, "Indexing ulsch_rounds[%d] is out of bounds\n", cur_harq->round); + AssertFatal(cur_harq->round < nr_mac->ul_bler.harq_round_max, "Indexing ulsch_rounds[%d] is out of bounds\n", cur_harq->round); UE->mac_stats.ul.rounds[cur_harq->round]++; if (cur_harq->round == 0) { UE->mac_stats.ulsch_total_bytes_scheduled += sched_pusch->tb_size; @@ -1768,7 +1771,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) pusch_pdu->nr_of_symbols = ps->nrOfSymbols; /* PUSCH PDU */ - AssertFatal(cur_harq->round < nr_mac->harq_round_max, "Indexing nr_rv_round_map[%d] is out of bounds\n", cur_harq->round%4); + AssertFatal(cur_harq->round < nr_mac->ul_bler.harq_round_max, "Indexing nr_rv_round_map[%d] is out of bounds\n", cur_harq->round%4); pusch_pdu->pusch_data.rv_index = nr_rv_round_map[cur_harq->round%4]; pusch_pdu->pusch_data.harq_process_id = harq_id; pusch_pdu->pusch_data.new_data_indicator = cur_harq->ndi; diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 50434b26b3..12c9846037 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -114,7 +114,7 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset end - output, "UE %04x: dlsch_rounds ", UE->rnti); output += snprintf(output, end - output, "%"PRIu64, stats->dl.rounds[0]); - for (int i = 1; i < gNB->harq_round_max; i++) + for (int i = 1; i < gNB->dl_bler.harq_round_max; i++) output += snprintf(output, end - output, "/%"PRIu64, stats->dl.rounds[i]); output += snprintf(output, @@ -136,7 +136,7 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset end - output, "UE %04x: ulsch_rounds ", UE->rnti); output += snprintf(output, end - output, "%"PRIu64, stats->ul.rounds[0]); - for (int i = 1; i < gNB->harq_round_max; i++) + for (int i = 1; i < gNB->ul_bler.harq_round_max; i++) output += snprintf(output, end - output, "/%"PRIu64, stats->ul.rounds[i]); output += snprintf(output, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 1ae8767d10..d8f2a79b07 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -75,7 +75,6 @@ #define MAX_NUM_BWP 5 #define MAX_NUM_CORESET 12 #define MAX_NUM_CCE 90 -#define MAX_HARQ_ROUNDS 4 /*!\brief Maximum number of random access process */ #define NR_NB_RA_PROC_MAX 4 #define MAX_NUM_OF_SSB 64 @@ -700,6 +699,7 @@ typedef struct NR_bler_options { double upper; double lower; uint8_t max_mcs; + uint8_t harq_round_max; } NR_bler_options_t; /*! \brief UE list used by gNB to order UEs/CC for scheduling*/ @@ -854,7 +854,6 @@ typedef struct gNB_MAC_INST_s { bool first_MIB; NR_bler_options_t dl_bler; NR_bler_options_t ul_bler; - uint8_t harq_round_max; uint8_t min_grant_prb; uint8_t min_grant_mcs; } gNB_MAC_INST; From fdd79391e9290250a63032dc9668b4beec20cc14 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Mon, 1 Aug 2022 17:28:15 +0100 Subject: [PATCH 241/267] Call function nr_mac_update_timers when there is a Msg3 carrying a DCCH message --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 89495139da..fa3b79d478 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1834,11 +1834,8 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra harq->round = 0; harq->ndi ^= 1; - configure_UE_BWP(nr_mac, - scc, - sched_ctrl, - NULL, - UE); + sched_ctrl->rrc_processing_timer = 1; // No need to wait at this point in time, setting it to 1 just to enter in function nr_mac_update_timers + LOG_I(NR_MAC, "(%d.%d) Activating RRC processing timer for UE %04x with %d ms\n", frameP, slotP, UE->rnti, 1); // Reset uplink failure flags/counters/timers at MAC so gNB will resume again scheduling resources for this UE UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt = 0; From 7a6f9659bcddfa8b11d5701ca586e50f2c70cd24 Mon Sep 17 00:00:00 2001 From: laurent Date: Fri, 29 Jul 2022 14:00:37 +0200 Subject: [PATCH 242/267] gtp-u pdu session extension header implementation, this extension header is mantadory in 5G --- openair1/SIMULATION/NR_PHY/dlsim.c | 14 +- openair1/SIMULATION/NR_PHY/prachsim.c | 14 +- openair1/SIMULATION/NR_PHY/ulsim.c | 14 +- openair2/COMMON/gtpv1_u_messages_types.h | 1 + openair2/F1AP/f1ap_cu_ue_context_management.c | 38 +-- openair2/F1AP/f1ap_du_ue_context_management.c | 36 +-- openair2/RRC/NR/rrc_gNB.c | 43 ++-- openair2/RRC/NR/rrc_gNB_NGAP.c | 6 +- openair3/ocp-gtpu/gtp_itf.cpp | 223 ++++++++++-------- openair3/ocp-gtpu/gtp_itf.h | 12 +- 10 files changed, 238 insertions(+), 163 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 8500749fe2..5abda203f2 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -100,9 +100,17 @@ nfapi_ue_release_request_body_t release_rntis; //Fixme: Uniq dirty DU instance, by global var, datamodel need better management instance_t DUuniqInstance=0; instance_t CUuniqInstance=0; -teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer_id, int outgoing_bearer_id, teid_t outgoing_teid, - transport_layer_addr_t remoteAddr, int port, gtpCallback callBack) { -return 0; +teid_t newGtpuCreateTunnel(instance_t instance, + rnti_t rnti, + int incoming_bearer_id, + int outgoing_bearer_id, + teid_t outgoing_teid, + int qfi, + transport_layer_addr_t remoteAddr, + int port, + gtpCallback callBack, + gtpCallbackSDAP callBackSDAP) { + return 0; } int newGtpuDeleteAllTunnels(instance_t instance, rnti_t rnti) { diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index 33717c944d..76776ce110 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -92,9 +92,17 @@ int oai_nfapi_nr_rach_indication(nfapi_nr_rach_indication_t *ind) { return(0); //Fixme: Uniq dirty DU instance, by global var, datamodel need better management instance_t DUuniqInstance=0; instance_t CUuniqInstance=0; -teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer_id, int outgoing_bearer_id, teid_t outgoing_teid, - transport_layer_addr_t remoteAddr, int port, gtpCallback callBack) { -return 0; +teid_t newGtpuCreateTunnel(instance_t instance, + rnti_t rnti, + int incoming_bearer_id, + int outgoing_bearer_id, + teid_t outgoing_teid, + int qfi, + transport_layer_addr_t remoteAddr, + int port, + gtpCallback callBack, + gtpCallbackSDAP callBackSDAP) { + return 0; } int newGtpuDeleteAllTunnels(instance_t instance, rnti_t rnti) { diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index ffb168fd68..5df89283a8 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -95,9 +95,17 @@ nfapi_ue_release_request_body_t release_rntis; //Fixme: Uniq dirty DU instance, by global var, datamodel need better management instance_t DUuniqInstance=0; instance_t CUuniqInstance=0; -teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer_id, int outgoing_bearer_id, teid_t outgoing_teid, - transport_layer_addr_t remoteAddr, int port, gtpCallback callBack) { -return 0; +teid_t newGtpuCreateTunnel(instance_t instance, + rnti_t rnti, + int incoming_bearer_id, + int outgoing_bearer_id, + teid_t outgoing_teid, + int qfi, + transport_layer_addr_t remoteAddr, + int port, + gtpCallback callBack, + gtpCallbackSDAP callBackSDAP) { + return 0; } int newGtpuDeleteAllTunnels(instance_t instance, rnti_t rnti) { diff --git a/openair2/COMMON/gtpv1_u_messages_types.h b/openair2/COMMON/gtpv1_u_messages_types.h index 4111b00024..7758395ee4 100644 --- a/openair2/COMMON/gtpv1_u_messages_types.h +++ b/openair2/COMMON/gtpv1_u_messages_types.h @@ -181,6 +181,7 @@ typedef struct gtpv1u_gnb_create_tunnel_req_s { int num_tunnels; //teid_t upf_NGu_teid[NR_GTPV1U_MAX_BEARERS_PER_UE]; ///< Tunnel Endpoint Identifier teid_t outgoing_teid[NR_GTPV1U_MAX_BEARERS_PER_UE]; + int outgoing_qfi[NR_GTPV1U_MAX_BEARERS_PER_UE]; pdusessionid_t pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; ebi_t incoming_rb_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; //ebi_t outgoing_rb_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index 859a9f5e0d..0f3959d4ad 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -515,15 +515,16 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(instance_t instance, int sz=sizeof(f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_dl_tnl[0].tl_address); memcpy(addr.buffer,&f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_dl_tnl[0].tl_address, sz); addr.length = sz*8; - f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl[j].teid= - newGtpuCreateTunnel(getCxt(CUtype, instance)->gtpInst, - f1ap_ue_context_setup_req->rnti, - f1ap_ue_context_setup_req->drbs_to_be_setup[i].drb_id, - f1ap_ue_context_setup_req->drbs_to_be_setup[i].drb_id, - 0xFFFF, // We will set the right value from DU answer - addr, - f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_dl_tnl[0].port, - cu_f1u_data_req); + f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl[j].teid = newGtpuCreateTunnel(getCxt(CUtype, instance)->gtpInst, + f1ap_ue_context_setup_req->rnti, + f1ap_ue_context_setup_req->drbs_to_be_setup[i].drb_id, + f1ap_ue_context_setup_req->drbs_to_be_setup[i].drb_id, + 0xFFFF, // We will set the right value from DU answer + -1, // no qfi + addr, + f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_dl_tnl[0].port, + cu_f1u_data_req, + NULL); /* 12.3.1 ULTunnels_ToBeSetup_Item */ asn1cSequenceAdd(drbs_toBeSetup_item->uLUPTNLInformation_ToBeSetup_List.list, F1AP_ULUPTNLInformation_ToBeSetup_Item_t, uLUPTNLInformation_ToBeSetup_Item); @@ -1491,15 +1492,16 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, f1ap_ue_context memcpy(addr.buffer,&f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_dl_tnl[0].tl_address, sz); addr.length = sz*8; - f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl[j].teid= - newGtpuCreateTunnel(getCxt(CUtype, instance)->gtpInst, - f1ap_ue_context_modification_req->rnti, - f1ap_ue_context_modification_req->drbs_to_be_setup[i].drb_id, - f1ap_ue_context_modification_req->drbs_to_be_setup[i].drb_id, - 0xFFFF, // We will set the right value from DU answer - addr, - f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_dl_tnl[0].port, - cu_f1u_data_req); + f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl[j].teid = newGtpuCreateTunnel(getCxt(CUtype, instance)->gtpInst, + f1ap_ue_context_modification_req->rnti, + f1ap_ue_context_modification_req->drbs_to_be_setup[i].drb_id, + f1ap_ue_context_modification_req->drbs_to_be_setup[i].drb_id, + 0xFFFF, // We will set the right value from DU answer + -1, // no qfi + addr, + f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_dl_tnl[0].port, + cu_f1u_data_req, + NULL); /* 12.3.1 ULTunnels_ToBeSetup_Item */ asn1cSequenceAdd(drbs_toBeSetupMod_item->uLUPTNLInformation_ToBeSetup_List.list, F1AP_ULUPTNLInformation_ToBeSetup_Item_t, uLUPTNLInformation_ToBeSetup_Item); diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index 74e0200f09..cb15862921 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -187,14 +187,16 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, transport_layer_addr_t addr; memcpy(addr.buffer, &drb_p->up_ul_tnl[0].tl_address, sizeof(drb_p->up_ul_tnl[0].tl_address)); addr.length=sizeof(drb_p->up_ul_tnl[0].tl_address)*8; - drb_p->up_dl_tnl[0].teid=newGtpuCreateTunnel(INSTANCE_DEFAULT, - f1ap_ue_context_setup_req->rnti, - drb_p->drb_id, - drb_p->drb_id, - drb_p->up_ul_tnl[0].teid, - addr, - drb_p->up_ul_tnl[0].port, - lteDURecvCb); + drb_p->up_dl_tnl[0].teid = newGtpuCreateTunnel(INSTANCE_DEFAULT, + f1ap_ue_context_setup_req->rnti, + drb_p->drb_id, + drb_p->drb_id, + drb_p->up_ul_tnl[0].teid, + -1, // no qfi + addr, + drb_p->up_ul_tnl[0].port, + lteDURecvCb, + NULL); drb_p->up_dl_tnl_length++; } } @@ -1171,14 +1173,16 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, transport_layer_addr_t addr; memcpy(addr.buffer, &drb_p->up_ul_tnl[0].tl_address, sizeof(drb_p->up_ul_tnl[0].tl_address)); addr.length=sizeof(drb_p->up_ul_tnl[0].tl_address)*8; - drb_p->up_dl_tnl[0].teid=newGtpuCreateTunnel(INSTANCE_DEFAULT, - f1ap_ue_context_modification_req->rnti, - drb_p->drb_id, - drb_p->drb_id, - drb_p->up_ul_tnl[0].teid, - addr, - drb_p->up_ul_tnl[0].port, - lteDURecvCb); + drb_p->up_dl_tnl[0].teid = newGtpuCreateTunnel(INSTANCE_DEFAULT, + f1ap_ue_context_modification_req->rnti, + drb_p->drb_id, + drb_p->drb_id, + drb_p->up_ul_tnl[0].teid, + -1, // no qfi + addr, + drb_p->up_ul_tnl[0].port, + lteDURecvCb, + NULL); drb_p->up_dl_tnl_length++; } } diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 648df1a306..8c6c583289 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1767,15 +1767,16 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete( } } - gtpv1u_gnb_create_tunnel_req_t create_tunnel_req; + gtpv1u_gnb_create_tunnel_req_t create_tunnel_req={0}; /* Save e RAB information for later */ - memset(&create_tunnel_req, 0, sizeof(create_tunnel_req)); for ( j = 0, i = 0; i < NB_RB_MAX; i++) { if (ue_context_pP->ue_context.pduSession[i].status == PDU_SESSION_STATUS_ESTABLISHED || ue_context_pP->ue_context.pduSession[i].status == PDU_SESSION_STATUS_DONE) { create_tunnel_req.pdusession_id[j] = ue_context_pP->ue_context.pduSession[i].param.pdusession_id; create_tunnel_req.incoming_rb_id[j] = i+1; create_tunnel_req.outgoing_teid[j] = ue_context_pP->ue_context.pduSession[i].param.gtp_teid; + // to be developped, use the first QFI only + create_tunnel_req.outgoing_qfi[j] = ue_context_pP->ue_context.pduSession[i].param.qos[0].qfi; memcpy(create_tunnel_req.dst_addr[j].buffer, ue_context_pP->ue_context.pduSession[i].param.upf_addr.buffer, sizeof(uint8_t)*20); @@ -2805,8 +2806,6 @@ rrc_gNB_decode_dcch( SRBs[0].lcid = 2; /*Instruction towards the DU for DRB configuration and tunnel creation*/ - gtpv1u_gnb_create_tunnel_req_t create_tunnel_req; - memset(&create_tunnel_req, 0, sizeof(gtpv1u_gnb_create_tunnel_req_t)); req->drbs_to_be_setup = malloc(1*sizeof(f1ap_drb_to_be_setup_t)); req->drbs_to_be_setup_length = 1; f1ap_drb_to_be_setup_t *DRBs=req->drbs_to_be_setup; @@ -3433,14 +3432,16 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha addr.length=sizeof(drb_p.up_ul_tnl[0].tl_address)*8; extern instance_t DUuniqInstance; if (!drb_id_to_setup_start) drb_id_to_setup_start = drb_p.drb_id; - incoming_teid=newGtpuCreateTunnel(DUuniqInstance, - req->rnti, - drb_p.drb_id, - drb_p.drb_id, - drb_p.up_ul_tnl[0].teid, - addr, - drb_p.up_ul_tnl[0].port, - DURecvCb); + incoming_teid = newGtpuCreateTunnel(DUuniqInstance, + req->rnti, + drb_p.drb_id, + drb_p.drb_id, + drb_p.up_ul_tnl[0].teid, + -1, // no qfi + addr, + drb_p.up_ul_tnl[0].port, + DURecvCb, + NULL); } } @@ -3572,14 +3573,16 @@ static void rrc_DU_process_ue_context_modification_request(MessageDef *msg_p, co memcpy(addr.buffer, &drb_p.up_ul_tnl[0].tl_address, sizeof(drb_p.up_ul_tnl[0].tl_address)); addr.length=sizeof(drb_p.up_ul_tnl[0].tl_address)*8; extern instance_t DUuniqInstance; - incoming_teid=newGtpuCreateTunnel(DUuniqInstance, - req->rnti, - drb_p.drb_id, - drb_p.drb_id, - drb_p.up_ul_tnl[0].teid, - addr, - drb_p.up_ul_tnl[0].port, - DURecvCb); + incoming_teid = newGtpuCreateTunnel(DUuniqInstance, + req->rnti, + drb_p.drb_id, + drb_p.drb_id, + drb_p.up_ul_tnl[0].teid, + -1, // no qfi + addr, + drb_p.up_ul_tnl[0].port, + DURecvCb, + NULL); } } diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 6663ddea85..8e1975ea11 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -474,7 +474,6 @@ rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ( rrc_gNB_ue_context_t *ue_context_p = NULL; protocol_ctxt_t ctxt={0}; uint8_t pdu_sessions_done = 0; - gtpv1u_gnb_create_tunnel_req_t create_tunnel_req; gtpv1u_gnb_create_tunnel_resp_t create_tunnel_resp; uint8_t inde_list[NR_NB_RB_MAX - 3]= {0}; int ret = 0; @@ -503,7 +502,7 @@ rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ( uint8_t nb_pdusessions_tosetup = NGAP_INITIAL_CONTEXT_SETUP_REQ (msg_p).nb_of_pdusessions; if (nb_pdusessions_tosetup != 0) { - memset(&create_tunnel_req, 0, sizeof(gtpv1u_gnb_create_tunnel_req_t)); + gtpv1u_gnb_create_tunnel_req_t create_tunnel_req={0}; for (int i = 0; i < NR_NB_RB_MAX - 3; i++) { if(ue_context_p->ue_context.pduSession[i].status >= PDU_SESSION_STATUS_DONE) continue; @@ -512,6 +511,8 @@ rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ( create_tunnel_req.pdusession_id[pdu_sessions_done] = NGAP_INITIAL_CONTEXT_SETUP_REQ (msg_p).pdusession_param[pdu_sessions_done].pdusession_id; create_tunnel_req.incoming_rb_id[pdu_sessions_done] = i+1; create_tunnel_req.outgoing_teid[pdu_sessions_done] = NGAP_INITIAL_CONTEXT_SETUP_REQ (msg_p).pdusession_param[pdu_sessions_done].gtp_teid; + // To be developped: hardcoded first flow + create_tunnel_req.outgoing_qfi[pdu_sessions_done] = NGAP_INITIAL_CONTEXT_SETUP_REQ (msg_p).pdusession_param[pdu_sessions_done].qos[0].qfi; create_tunnel_req.dst_addr[pdu_sessions_done].length = NGAP_INITIAL_CONTEXT_SETUP_REQ (msg_p).pdusession_param[pdu_sessions_done].upf_addr.length; memcpy(create_tunnel_req.dst_addr[pdu_sessions_done].buffer, NGAP_INITIAL_CONTEXT_SETUP_REQ (msg_p).pdusession_param[pdu_sessions_done].upf_addr.buffer, @@ -1003,6 +1004,7 @@ rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ( create_tunnel_req.pdusession_id[pdu_sessions_done] = NGAP_PDUSESSION_SETUP_REQ(msg_p).pdusession_setup_params[pdu_sessions_done].pdusession_id; create_tunnel_req.incoming_rb_id[pdu_sessions_done]= i+1; create_tunnel_req.outgoing_teid[pdu_sessions_done] = NGAP_PDUSESSION_SETUP_REQ(msg_p).pdusession_setup_params[pdu_sessions_done].gtp_teid; + create_tunnel_req.outgoing_qfi[pdu_sessions_done] = NGAP_PDUSESSION_SETUP_REQ(msg_p).pdusession_setup_params[pdu_sessions_done].qos[0].qfi; memcpy(create_tunnel_req.dst_addr[pdu_sessions_done].buffer, NGAP_PDUSESSION_SETUP_REQ(msg_p).pdusession_setup_params[pdu_sessions_done].upf_addr.buffer, sizeof(uint8_t)*20); diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index 3626e0b8ed..e318f0cf95 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -21,8 +21,6 @@ extern "C" { #include "openair2/SDAP/nr_sdap/nr_sdap.h" //#include -static bool is_gnb = false; - #pragma pack(1) typedef struct Gtpv1uMsgHeader { @@ -60,18 +58,21 @@ typedef struct Gtpv1uMsgHeaderOptFields { uint8_t NextExtHeaderType; } __attribute__((packed)) Gtpv1uMsgHeaderOptFieldsT; -typedef struct PDUSessionContainer { +#define DL_PDU_SESSION_INFORMATION 0 +#define UL_PDU_SESSION_INFORMATION 1 + + typedef struct PDUSessionContainer { uint8_t spare:4; uint8_t PDU_type:4; uint8_t QFI:6; - uint8_t RQI:1; - uint8_t PPP:1; + uint8_t Reflective_QoS_activation:1; + uint8_t Paging_Policy_Indicator:1; } __attribute__((packed)) PDUSessionContainerT; typedef struct Gtpv1uExtHeader { uint8_t ExtHeaderLen; PDUSessionContainerT pdusession_cntr; - //uint8_t NextExtHeaderType; + uint8_t NextExtHeaderType; }__attribute__((packed)) Gtpv1uExtHeaderT; #pragma pack() @@ -103,6 +104,7 @@ typedef struct gtpv1u_bearer_s { tcp_udp_port_t outgoing_port; uint16_t seqNum; uint8_t npduNum; + int outgoing_qfi; } gtpv1u_bearer_t; typedef struct { @@ -159,75 +161,80 @@ instance_t legacyInstanceMapping=0; #define GTPV1U_HEADER_SIZE (8) - - static int gtpv1uCreateAndSendMsg(int h, uint32_t peerIp, uint16_t peerPort, int msgType, teid_t teid, uint8_t *Msg,int msgLen, - bool seqNumFlag, bool npduNumFlag, bool extHdrFlag, int seqNum, int npduNum, int extHdrType, - uint8_t *extensionHeader_buffer, uint8_t extensionHeader_length) { + #define HDR_MAX 256 // 256 is supposed to be larger than any gtp header +static int gtpv1uCreateAndSendMsg(int h, + uint32_t peerIp, + uint16_t peerPort, + int msgType, + teid_t teid, + uint8_t *Msg, + int msgLen, + bool seqNumFlag, + bool npduNumFlag, + int seqNum, + int npduNum, + int extHdrType, + uint8_t *extensionHeader_buffer, + uint8_t extensionHeader_length) { LOG_D(GTPU, "Peer IP:%u peer port:%u outgoing teid:%u \n", peerIp, peerPort, teid); - int headerAdditional=0; - if ( seqNumFlag || npduNumFlag || extHdrFlag) - headerAdditional=4; - - int fullSize=GTPV1U_HEADER_SIZE+headerAdditional+msgLen+extensionHeader_length; - uint8_t buffer[fullSize]; + uint8_t buffer[msgLen+HDR_MAX]; + uint8_t *curPtr=buffer; Gtpv1uMsgHeaderT *msgHdr = (Gtpv1uMsgHeaderT *)buffer ; // N should be 0 for us (it was used only in 2G and 3G) msgHdr->PN=npduNumFlag; msgHdr->S=seqNumFlag; - msgHdr->E=extHdrFlag; + msgHdr->E = extHdrType; msgHdr->spare=0; //PT=0 is for GTP' TS 32.295 (charging) msgHdr->PT=1; msgHdr->version=1; msgHdr->msgType=msgType; - msgHdr->msgLength=htons(msgLen+extensionHeader_length); - - if ( seqNumFlag || extHdrFlag || npduNumFlag) - msgHdr->msgLength+=htons(4); - + msgHdr->msgLength = htons(msgLen + extensionHeader_length); msgHdr->teid=htonl(teid); - if(seqNumFlag || extHdrFlag || npduNumFlag) { - *((uint16_t *) (buffer+8)) = seqNumFlag ? seqNum : 0x0000; - *((uint8_t *) (buffer+10)) = npduNumFlag ? npduNum : 0x00; - *((uint8_t *) (buffer+11)) = extHdrFlag ? extHdrType : 0x00; + curPtr+=sizeof(Gtpv1uMsgHeaderT); - /**(buffer+8) = seqNumFlag ? htons(seqNum) : 0x0000; - *(buffer+10) = npduNumFlag ? htons(npduNum) : 0x00; - *(buffer+11) = extHdrFlag ? htons(extHdrType) : 0x00; - *(buffer+11) = extHdrType;*/ + if (seqNumFlag || (extHdrType != NO_MORE_EXT_HDRS) || npduNumFlag) { + msgHdr->msgLength += htons(4); + *(uint16_t *)curPtr = seqNumFlag ? seqNum : 0x0000; + curPtr+=sizeof(uint16_t); + *(uint8_t *)curPtr = npduNumFlag ? npduNum : 0x00; + curPtr++; + *(uint8_t *)curPtr = extHdrType; + curPtr++; } - if(extHdrFlag){ - while (extHdrType){ - if (extensionHeader_length > 0 && extHdrType == 0x84){ - memcpy(buffer+GTPV1U_HEADER_SIZE+headerAdditional, extensionHeader_buffer, extensionHeader_length); - LOG_D(GTPU, "Extension Header for DDD added. The length is: %d, extension header type is: %x \n", extensionHeader_length, *((uint8_t *) (buffer+11))); - extHdrType = extensionHeader_buffer[extensionHeader_length -1]; - LOG_D(GTPU, "Next extension header type is: %x \n", *((uint8_t *) (buffer+11))); - } - else { - LOG_W(GTPU, "Extension header type not supported, returning... \n"); - return GTPNOK; - } + // Bug: if there is more than one extension, infinite loop on extensionHeader_buffer + while (extHdrType != NO_MORE_EXT_HDRS) { + if (extensionHeader_length > 0) { + memcpy(curPtr, extensionHeader_buffer, extensionHeader_length); + curPtr += extensionHeader_length; + LOG_D(GTPU, "Extension Header for DDD added. The length is: %d, extension header type is: %x \n", extensionHeader_length, *((uint8_t *)(buffer + 11))); + extHdrType = extensionHeader_buffer[extensionHeader_length - 1]; + LOG_D(GTPU, "Next extension header type is: %x \n", *((uint8_t *)(buffer + 11))); + } else { + LOG_W(GTPU, "Extension header type not supported, returning... \n"); } } + if (Msg!= NULL){ - memcpy(buffer+GTPV1U_HEADER_SIZE+headerAdditional+extensionHeader_length, Msg, msgLen); + memcpy(curPtr, Msg, msgLen); + curPtr+=msgLen; } + AssertFatal(curPtr-(buffer+msgLen) < HDR_MAX, ""); // Fix me: add IPv6 support, using flag ipVersion static struct sockaddr_in to= {0}; to.sin_family = AF_INET; to.sin_port = htons(peerPort); to.sin_addr.s_addr = peerIp ; - LOG_D(GTPU,"sending packet size: %d to %s\n",fullSize, inet_ntoa(to.sin_addr) ); + LOG_D(GTPU,"sending packet size: %ld to %s\n",curPtr-buffer, inet_ntoa(to.sin_addr) ); int ret; - if ((ret=sendto(h, (void *)buffer, (size_t)fullSize, 0,(struct sockaddr *)&to, sizeof(to) )) != fullSize ) { - LOG_E(GTPU, "[SD %d] Failed to send data to " IPV4_ADDR " on port %d, buffer size %u, ret: %d, errno: %d\n", - h, IPV4_ADDR_FORMAT(peerIp), peerPort, fullSize, ret, errno); + if ((ret=sendto(h, (void *)buffer, curPtr-buffer, 0,(struct sockaddr *)&to, sizeof(to) )) != curPtr-buffer ) { + LOG_E(GTPU, "[SD %d] Failed to send data to " IPV4_ADDR " on port %d, buffer size %lu, ret: %d, errno: %d\n", + h, IPV4_ADDR_FORMAT(peerIp), peerPort, curPtr-buffer, ret, errno); return GTPNOK; } @@ -269,12 +276,8 @@ static void gtpv1uSend(instance_t instance, gtpv1u_enb_tunnel_data_req_t *req, b // copy to release the mutex gtpv1u_bearer_t tmp=ptr2->second; pthread_mutex_unlock(&globGtp.gtp_lock); - gtpv1uCreateAndSendMsg(compatInst(instance), - tmp.outgoing_ip_addr, - tmp.outgoing_port, - GTP_GPDU, - tmp.teid_outgoing, - buffer, length, seqNumFlag, npduNumFlag, false, tmp.seqNum, tmp.npduNum, 0, NULL, 0) ; + gtpv1uCreateAndSendMsg( + compatInst(instance), tmp.outgoing_ip_addr, tmp.outgoing_port, GTP_GPDU, tmp.teid_outgoing, buffer, length, seqNumFlag, npduNumFlag, tmp.seqNum, tmp.npduNum, NO_MORE_EXT_HDRS, NULL, 0); } static void gtpv1uSend2(instance_t instance, gtpv1u_gnb_tunnel_data_req_t *req, bool seqNumFlag, bool npduNumFlag) { @@ -312,12 +315,35 @@ static void gtpv1uSend2(instance_t instance, gtpv1u_gnb_tunnel_data_req_t *req, // copy to release the mutex gtpv1u_bearer_t tmp=ptr2->second; pthread_mutex_unlock(&globGtp.gtp_lock); - gtpv1uCreateAndSendMsg(compatInst(instance), - tmp.outgoing_ip_addr, - tmp.outgoing_port, - GTP_GPDU, - tmp.teid_outgoing, - buffer, length, seqNumFlag, npduNumFlag, false, tmp.seqNum, tmp.npduNum, 0, NULL, 0) ; + + if (tmp.outgoing_qfi != -1) { + Gtpv1uExtHeaderT ext = { 0 }; + ext.ExtHeaderLen = 1; // in quad bytes EXT_HDR_LNTH_OCTET_UNITS + ext.pdusession_cntr.spare = 0; + ext.pdusession_cntr.PDU_type = UL_PDU_SESSION_INFORMATION; + ext.pdusession_cntr.QFI = tmp.outgoing_qfi; + ext.pdusession_cntr.Reflective_QoS_activation = false; + ext.pdusession_cntr.Paging_Policy_Indicator = false; + ext.NextExtHeaderType = NO_MORE_EXT_HDRS; + + gtpv1uCreateAndSendMsg(compatInst(instance), + tmp.outgoing_ip_addr, + tmp.outgoing_port, + GTP_GPDU, + tmp.teid_outgoing, + buffer, + length, + seqNumFlag, + npduNumFlag, + tmp.seqNum, + tmp.npduNum, + PDU_SESSION_CONTAINER, + (uint8_t *)&ext, + sizeof(ext)); + } else { + gtpv1uCreateAndSendMsg( + compatInst(instance), tmp.outgoing_ip_addr, tmp.outgoing_port, GTP_GPDU, tmp.teid_outgoing, buffer, length, seqNumFlag, npduNumFlag, tmp.seqNum, tmp.npduNum, NO_MORE_EXT_HDRS, NULL, 0); + } } static void fillDlDeliveryStatusReport(extensionHeader_t *extensionHeader, uint32_t RLC_buffer_availability, uint32_t NR_PDCP_PDU_SN){ @@ -379,13 +405,8 @@ static void gtpv1uSendDlDeliveryStatus(instance_t instance, gtpv1u_DU_buffer_rep // copy to release the mutex gtpv1u_bearer_t tmp=ptr2->second; pthread_mutex_unlock(&globGtp.gtp_lock); - gtpv1uCreateAndSendMsg(compatInst(instance), - tmp.outgoing_ip_addr, - tmp.outgoing_port, - GTP_GPDU, - tmp.teid_outgoing, - NULL, 0, false, false, true, 0, 0, 0x84, extensionHeader->buffer, extensionHeader->length) ; - + gtpv1uCreateAndSendMsg( + compatInst(instance), tmp.outgoing_ip_addr, tmp.outgoing_port, GTP_GPDU, tmp.teid_outgoing, NULL, 0, false, false, 0, 0, NR_RAN_CONTAINER, extensionHeader->buffer, extensionHeader->length); } static void gtpv1uEndTunnel(instance_t instance, gtpv1u_enb_tunnel_data_req_t *req) { @@ -567,8 +588,16 @@ void GtpuUpdateTunnelOutgoingTeid(instance_t instance, rnti_t rnti, ebi_t bearer return; } -teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer_id, int outgoing_bearer_id, teid_t outgoing_teid, - transport_layer_addr_t remoteAddr, int port, gtpCallback callBack) { +teid_t newGtpuCreateTunnel(instance_t instance, + rnti_t rnti, + int incoming_bearer_id, + int outgoing_bearer_id, + teid_t outgoing_teid, + int outgoing_qfi, + transport_layer_addr_t remoteAddr, + int port, + gtpCallback callBack, + gtpCallbackSDAP callBackSDAP) { pthread_mutex_lock(&globGtp.gtp_lock); instance=compatInst(instance); auto inst=&globGtp.instances[instance]; @@ -593,8 +622,8 @@ teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer inst->te2ue_mapping[incoming_teid].outgoing_teid= outgoing_teid; inst->te2ue_mapping[incoming_teid].callBack=callBack; - - inst->te2ue_mapping[incoming_teid].callBackSDAP = sdap_data_req; + + inst->te2ue_mapping[incoming_teid].callBackSDAP = callBackSDAP; inst->te2ue_mapping[incoming_teid].pdusession_id = (uint8_t)outgoing_bearer_id; @@ -625,6 +654,7 @@ teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer tmp->teid_incoming = incoming_teid; tmp->outgoing_port=port; tmp->teid_outgoing= outgoing_teid; + tmp->outgoing_qfi=outgoing_qfi; pthread_mutex_unlock(&globGtp.gtp_lock); char ip4[INET_ADDRSTRLEN]; char ip6[INET6_ADDRSTRLEN]; @@ -653,12 +683,16 @@ int gtpv1u_create_s1u_tunnel(instance_t instance, "From legacy code not clear, seems impossible (bearer=%d)\n", create_tunnel_req->eps_bearer_id[i]); int incoming_rb_id=create_tunnel_req->eps_bearer_id[i]-4; - teid_t teid=newGtpuCreateTunnel(compatInst(instance), create_tunnel_req->rnti, - incoming_rb_id, - create_tunnel_req->eps_bearer_id[i], - create_tunnel_req->sgw_S1u_teid[i], - create_tunnel_req->sgw_addr[i], dstport, - pdcp_data_req); + teid_t teid = newGtpuCreateTunnel(compatInst(instance), + create_tunnel_req->rnti, + incoming_rb_id, + create_tunnel_req->eps_bearer_id[i], + create_tunnel_req->sgw_S1u_teid[i], + -1, // no pdu session in 4G + create_tunnel_req->sgw_addr[i], + dstport, + pdcp_data_req, + NULL); create_tunnel_resp->status=0; create_tunnel_resp->rnti=create_tunnel_req->rnti; create_tunnel_resp->num_tunnels=create_tunnel_req->num_tunnels; @@ -715,15 +749,18 @@ int gtpv1u_create_ngu_tunnel( const instance_t instance, create_tunnel_req->rnti, create_tunnel_req->num_tunnels, create_tunnel_req->outgoing_teid[0]); - tcp_udp_port_t dstport=globGtp.instances[compatInst(instance)].get_dstport(); - is_gnb = true; + tcp_udp_port_t dstport = globGtp.instances[compatInst(instance)].get_dstport(); for (int i = 0; i < create_tunnel_req->num_tunnels; i++) { - teid_t teid=newGtpuCreateTunnel(instance, create_tunnel_req->rnti, - create_tunnel_req->incoming_rb_id[i], - create_tunnel_req->pdusession_id[i], - create_tunnel_req->outgoing_teid[i], - create_tunnel_req->dst_addr[i], dstport, - pdcp_data_req); + teid_t teid = newGtpuCreateTunnel(instance, + create_tunnel_req->rnti, + create_tunnel_req->incoming_rb_id[i], + create_tunnel_req->pdusession_id[i], + create_tunnel_req->outgoing_teid[i], + create_tunnel_req->outgoing_qfi[i], + create_tunnel_req->dst_addr[i], + dstport, + pdcp_data_req, + sdap_data_req); create_tunnel_resp->status=0; create_tunnel_resp->rnti=create_tunnel_req->rnti; create_tunnel_resp->num_tunnels=create_tunnel_req->num_tunnels; @@ -853,9 +890,7 @@ static int Gtpv1uHandleEchoReq(int h, uint16_t seq=ntohs(*(uint16_t *)(msgHdr+1)); LOG_D(GTPU, "[%d] Received a echo request, TEID: %d, seq: %hu\n", h, msgHdr->teid, seq); uint8_t recovery[2]= {14,0}; - return gtpv1uCreateAndSendMsg(h, peerIp, peerPort, GTP_ECHO_RSP, ntohl(msgHdr->teid), - recovery, sizeof recovery, - 1, 0, 0, seq, 0, 0, NULL, 0); + return gtpv1uCreateAndSendMsg(h, peerIp, peerPort, GTP_ECHO_RSP, ntohl(msgHdr->teid), recovery, sizeof recovery, true, false, seq, 0, NO_MORE_EXT_HDRS, NULL, 0); } static int Gtpv1uHandleError(int h, @@ -968,7 +1003,7 @@ static int Gtpv1uHandleGpdu(int h, //Minimum length of GTP-U header if non of the optional fields are present int offset = sizeof(Gtpv1uMsgHeaderT); - uint8_t qfi = 0; + uint8_t qfi = -1; bool rqi = false; uint32_t NR_PDCP_PDU_SN = 0; @@ -986,7 +1021,7 @@ static int Gtpv1uHandleGpdu(int h, case PDU_SESSION_CONTAINER: { PDUSessionContainerT *pdusession_cntr = (PDUSessionContainerT *)(msgBuf + offset + 1); qfi = pdusession_cntr->QFI; - rqi = pdusession_cntr->RQI; + rqi = pdusession_cntr->Reflective_QoS_activation; break; } case NR_RAN_CONTAINER: { @@ -1047,7 +1082,7 @@ static int Gtpv1uHandleGpdu(int h, const uint32_t destinationL2Id=0; pthread_mutex_unlock(&globGtp.gtp_lock); - if(is_gnb && qfi){ + if (qfi != -1 && tunnel->second.callBackSDAP) { if ( !tunnel->second.callBackSDAP(&ctxt, srb_flag, rb_id, @@ -1106,12 +1141,8 @@ static int Gtpv1uHandleGpdu(int h, * 1 octet for padding + 1 octet for next extension header type, * according to TS 38.425: Fig. 5.5.2.2-1 and section 5.5.3.24*/ extensionHeader->length = 1+sizeof(DlDataDeliveryStatus_flagsT)+3+1+1; - gtpv1uCreateAndSendMsg(h, - peerIp, - peerPort, - GTP_GPDU, - inst->te2ue_mapping[ntohl(msgHdr->teid)].outgoing_teid, - NULL, 0, false, false, true, 0, 0, 0x84, extensionHeader->buffer, extensionHeader->length) ; + gtpv1uCreateAndSendMsg( + h, peerIp, peerPort, GTP_GPDU, inst->te2ue_mapping[ntohl(msgHdr->teid)].outgoing_teid, NULL, 0, false, false, 0, 0, NR_RAN_CONTAINER, extensionHeader->buffer, extensionHeader->length); } LOG_D(GTPU,"[%d] Received a %d bytes packet for: teid:%x\n", h, diff --git a/openair3/ocp-gtpu/gtp_itf.h b/openair3/ocp-gtpu/gtp_itf.h index 51a47e8c82..7951c4db09 100644 --- a/openair3/ocp-gtpu/gtp_itf.h +++ b/openair3/ocp-gtpu/gtp_itf.h @@ -66,8 +66,16 @@ int gtpv1u_create_x2u_tunnel( // New API -teid_t newGtpuCreateTunnel(instance_t instance, rnti_t rnti, int incoming_bearer_id, int outgoing_rb_id, teid_t teid, - transport_layer_addr_t remoteAddr, int port, gtpCallback callBack); +teid_t newGtpuCreateTunnel(instance_t instance, + rnti_t rnti, + int incoming_bearer_id, + int outgoing_rb_id, + teid_t teid, + int outgoing_qfi, + transport_layer_addr_t remoteAddr, + int port, + gtpCallback callBack, + gtpCallbackSDAP callBackSDAP); void GtpuUpdateTunnelOutgoingTeid(instance_t instance, rnti_t rnti, ebi_t bearer_id, teid_t newOutgoingTeid); int newGtpuDeleteAllTunnels(instance_t instance, rnti_t rnti); int newGtpuDeleteTunnels(instance_t instance, rnti_t rnti, int nbTunnels, pdusessionid_t *pdusession_id); From eb46f216b18e6055502bad7210681a4012dc6cdf Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 29 Jul 2022 18:44:00 +0200 Subject: [PATCH 243/267] Upgrade path to AS lteue after simulator upgrade --- ci-scripts/ci_ueinfra.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci-scripts/ci_ueinfra.yaml b/ci-scripts/ci_ueinfra.yaml index 51fc4a264e..76ebaf0f97 100644 --- a/ci-scripts/ci_ueinfra.yaml +++ b/ci-scripts/ci_ueinfra.yaml @@ -50,7 +50,7 @@ amarisoft_ue_1: WakeupScript : none DetachScript : none #end - Cmd : /root/NV17-12-21/ue/lteue + Cmd : /root/NV18-06-2022/ue/lteue Config : /root/NV17-12-21/ue/config/oaicicd-ue-Ping-SATest.cfg Duration : 60 Ping : /tmp/test_ue1.log @@ -71,7 +71,7 @@ amarisoft_ue_2: WakeupScript : none DetachScript : none #end - Cmd : /root/NV17-12-21/ue/lteue + Cmd : /root/NV18-06-2022/ue/lteue Config : /root/NV17-12-21/ue/config/xxxxxxx.cfg #to be updated for an other scenario Duration : 60 Ping : From 3d93d0dfc092404004f57ad57a137cce3c363eb8 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 26 Jul 2022 18:41:19 +0200 Subject: [PATCH 244/267] fix for pusch dtx in phytest mode --- openair1/PHY/NR_TRANSPORT/nr_transport_proto.h | 10 +++++----- openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c | 2 +- .../PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 12 +++++------- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 16 +++------------- 4 files changed, 14 insertions(+), 26 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 37c353e2d2..fd81d66002 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -121,11 +121,11 @@ void free_gNB_dlsch(NR_gNB_DLSCH_t **dlschptr, uint16_t N_RB, const NR_DL_FRAME_ @param slot Slot number @param harq_pid HARQ process ID */ -int nr_rx_pusch(PHY_VARS_gNB *gNB, - uint8_t UE_id, - uint32_t frame, - uint8_t slot, - unsigned char harq_pid); +void nr_rx_pusch(PHY_VARS_gNB *gNB, + uint8_t UE_id, + uint32_t frame, + uint8_t slot, + unsigned char harq_pid); /** \brief This function performs RB extraction (signal and channel estimates) (currently signal only until channel estimation and compensation are implemented) @param rxdataF pointer to the received frequency domain signal diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c index ef5c0c069e..6f49bcd053 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c @@ -412,7 +412,7 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, uint8_t n_layers = pusch_pdu->nrOfLayers; // ------------------------------------------------------------------ - if (!ulsch_llr) { + if (!ulsch_llr) { LOG_E(PHY,"ulsch_decoding.c: NULL ulsch_llr pointer\n"); return 1; } diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 4b8315e1ce..ac4c6f35e0 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -1891,11 +1891,11 @@ uint8_t nr_ulsch_zero_forcing_rx_2layers(int **rxdataF_comp, //============================================================================================== /* Main Function */ -int nr_rx_pusch(PHY_VARS_gNB *gNB, - uint8_t ulsch_id, - uint32_t frame, - uint8_t slot, - unsigned char harq_pid) +void nr_rx_pusch(PHY_VARS_gNB *gNB, + uint8_t ulsch_id, + uint32_t frame, + uint8_t slot, + unsigned char harq_pid) { uint8_t aarx, aatx; @@ -2149,6 +2149,4 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, rxdataF_ext_offset += gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[symbol]; } } // symbol loop - - return 0; } diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index fd718af95d..3d82840256 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -193,14 +193,12 @@ void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req) { NR_gNB_ULSCH_t *ulsch = rdata->ulsch; int r = rdata->segment_r; nfapi_nr_pusch_pdu_t *pusch_pdu = &gNB->ulsch[rdata->ulsch_id]->harq_processes[rdata->harq_pid]->ulsch_pdu; - bool decodeSuccess = (rdata->decodeIterations <= rdata->decoderParms.numMaxIter); ulsch_harq->processedSegments++; LOG_D(PHY, "processing result of segment: %d, processed %d/%d\n", rdata->segment_r, ulsch_harq->processedSegments, rdata->nbSegments); gNB->nbDecode--; LOG_D(PHY,"remain to decoded in subframe: %d\n", gNB->nbDecode); - if (decodeSuccess) { memcpy(ulsch_harq->b+rdata->offset, ulsch_harq->c[r], @@ -222,7 +220,7 @@ void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req) { //int dumpsig=0; // if all segments are done if (rdata->nbSegments == ulsch_harq->processedSegments) { - if (decodeSuccess) { + if (decodeSuccess && !gNB->pusch_vars[rdata->ulsch_id]->DTX) { LOG_D(PHY,"[gNB %d] ULSCH: Setting ACK for SFN/SF %d.%d (pid %d, ndi %d, status %d, round %d, TBS %d, Max interation (all seg) %d)\n", gNB->Mod_id,ulsch_harq->frame,ulsch_harq->slot,rdata->harq_pid,pusch_pdu->pusch_data.new_data_indicator,ulsch_harq->status,ulsch_harq->round,ulsch_harq->TBS,rdata->decodeIterations); ulsch_harq->status = SCH_IDLE; @@ -727,14 +725,12 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { for (int ULSCH_id=0;ULSCH_idnumber_of_nr_ulsch_max;ULSCH_id++) { NR_gNB_ULSCH_t *ulsch = gNB->ulsch[ULSCH_id]; - int harq_pid; - int no_sig; NR_UL_gNB_HARQ_t *ulsch_harq; if ((ulsch) && (ulsch->rnti > 0)) { // for for an active HARQ process - for (harq_pid=0;harq_pidharq_processes[harq_pid]; AssertFatal(ulsch_harq!=NULL,"harq_pid %d is not allocated\n",harq_pid); if ((ulsch_harq->status == NR_ACTIVE) && @@ -776,13 +772,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RX_PUSCH,1); start_meas(&gNB->rx_pusch_stats); - no_sig = nr_rx_pusch(gNB, ULSCH_id, frame_rx, slot_rx, harq_pid); - if (no_sig) { - LOG_D(PHY, "PUSCH not detected in frame %d, slot %d\n", frame_rx, slot_rx); - nr_fill_indication(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid, 1,1); - pusch_DTX++; - continue; - } + nr_rx_pusch(gNB, ULSCH_id, frame_rx, slot_rx, harq_pid); gNB->pusch_vars[ULSCH_id]->ulsch_power_tot=0; gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot=0; for (int aarx=0;aarxframe_parms.nb_antennas_rx;aarx++) { From 3155ec6df80b31eb235671e3577c88b548431e7f Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 3 Aug 2022 10:34:12 +0200 Subject: [PATCH 245/267] gtp: small fix: set E if there is an extension header --- openair3/ocp-gtpu/gtp_itf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index e318f0cf95..dc93960e5e 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -184,7 +184,7 @@ static int gtpv1uCreateAndSendMsg(int h, // N should be 0 for us (it was used only in 2G and 3G) msgHdr->PN=npduNumFlag; msgHdr->S=seqNumFlag; - msgHdr->E = extHdrType; + msgHdr->E = extHdrType != NO_MORE_EXT_HDRS; msgHdr->spare=0; //PT=0 is for GTP' TS 32.295 (charging) msgHdr->PT=1; From b64baf144d1bd111edba210594183bd14d5f187d Mon Sep 17 00:00:00 2001 From: Rohan Date: Wed, 3 Aug 2022 14:09:09 +0000 Subject: [PATCH 246/267] Resolve AMF ip address using FQDN --- docker/scripts/gnb_entrypoint.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker/scripts/gnb_entrypoint.sh b/docker/scripts/gnb_entrypoint.sh index ac0e0d4c88..6deff8da10 100755 --- a/docker/scripts/gnb_entrypoint.sh +++ b/docker/scripts/gnb_entrypoint.sh @@ -18,6 +18,10 @@ if [[ -v USE_SA_NFAPI_VNF ]]; then cp $PREFIX/etc/gnb.sa.nfapi.vnf.conf $PREFIX/ # Sometimes, the templates are not enough. We mount a conf file on $PREFIX/etc. It can be a template itself. if [[ -v USE_VOLUMED_CONF ]]; then cp $PREFIX/etc/mounted.conf $PREFIX/etc/gnb.conf; fi +# Resolve AMF FQDN +AMF_FQDN=${AMF_FQDN:-oai-amf-svc} +if ($USE_FQDN); then AMF_IP_ADDRESS=(`getent hosts $AMF_FQDN | awk '{print $1}'`); fi + # Only this template will be manipulated CONFIG_FILES=`ls $PREFIX/etc/gnb.conf || true` From 8c81c70de92dda95522abf7500a1d4f6dcc5c67b Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 26 Jul 2022 11:42:28 +0200 Subject: [PATCH 247/267] Fix AckNack and SR multiplexing in PUCCH2 - correctly reset HARQ structure for HARQ Ack/Nack/PUCCH0 - reduce max PUCCH2 bits to have room for SR --- openair1/PHY/NR_TRANSPORT/nr_transport_proto.h | 6 +----- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 7 +++++++ openair1/SCHED_NR/phy_procedures_nr_gNB.c | 1 + openair1/SIMULATION/NR_PHY/pucchsim.c | 2 +- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 6 ++---- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 9 ++++----- 6 files changed, 16 insertions(+), 15 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 37c353e2d2..f7b1a117b8 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -370,6 +370,7 @@ void nr_decode_pucch1(int32_t **rxdataF, uint8_t nr_bit); void nr_decode_pucch2(PHY_VARS_gNB *gNB, + int frame, int slot, nfapi_nr_uci_pucch_pdu_format_2_3_4_t* uci_pdu, nfapi_nr_pucch_pdu_t* pucch_pdu); @@ -380,10 +381,5 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, nfapi_nr_uci_pucch_pdu_format_0_1_t* uci_pdu, nfapi_nr_pucch_pdu_t* pucch_pdu); -void nr_decode_pucch2(PHY_VARS_gNB *gNB, - int slot, - nfapi_nr_uci_pucch_pdu_format_2_3_4_t* uci_pdu, - nfapi_nr_pucch_pdu_t* pucch_pdu); - #endif /*__NR_TRANSPORT__H__*/ diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index 85461df441..2f8a288c66 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -1136,6 +1136,7 @@ void init_pucch2_luts() { void nr_decode_pucch2(PHY_VARS_gNB *gNB, + int frame, int slot, nfapi_nr_uci_pucch_pdu_format_2_3_4_t* uci_pdu, nfapi_nr_pucch_pdu_t* pucch_pdu) { @@ -1720,13 +1721,19 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, uci_pdu->pduBitmap|=2; uci_pdu->harq.harq_payload = (uint8_t*)malloc(harq_bytes); uci_pdu->harq.harq_crc = decoderState; + LOG_D(PHY,"[DLSCH/PDSCH/PUCCH2] %d.%d HARQ bytes (%d) Decoder state %d\n", + frame,slot,harq_bytes,decoderState); int i=0; for (;iharq.harq_payload[i] = decodedPayload[0] & 255; + LOG_D(PHY,"[DLSCH/PDSCH/PUCCH2] %d.%d HARQ paylod (%d) = %d\n", + frame,slot,i,uci_pdu->harq.harq_payload[i]); decodedPayload[0]>>=8; } bit_left = pucch_pdu->bit_len_harq-((harq_bytes-1)<<3); uci_pdu->harq.harq_payload[i] = decodedPayload[0] & ((1<harq.harq_payload[i]); decodedPayload[0] >>= pucch_pdu->bit_len_harq; } diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index fd718af95d..1ebb2e9e02 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -711,6 +711,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { LOG_D(PHY,"%d.%d Calling nr_decode_pucch2\n",frame_rx,slot_rx); nr_decode_pucch2(gNB, + frame_rx, slot_rx, uci_pdu_format2, pucch_pdu); diff --git a/openair1/SIMULATION/NR_PHY/pucchsim.c b/openair1/SIMULATION/NR_PHY/pucchsim.c index 80a638db73..7cd836c8c6 100644 --- a/openair1/SIMULATION/NR_PHY/pucchsim.c +++ b/openair1/SIMULATION/NR_PHY/pucchsim.c @@ -705,7 +705,7 @@ int main(int argc, char **argv) pucch_pdu.second_hop_prb = N_RB_DL-1; } else pucch_pdu.freq_hop_flag = 0; - nr_decode_pucch2(gNB,nr_slot_tx,&uci_pdu,&pucch_pdu); + nr_decode_pucch2(gNB,nr_frame_tx,nr_slot_tx,&uci_pdu,&pucch_pdu); int csi_part1_bytes=pucch_pdu.bit_len_csi_part1>>3; if ((pucch_pdu.bit_len_csi_part1&7) > 0) csi_part1_bytes++; for (int i=0;ipayload = (pucch->sr_payload << O_ACK) | pucch->ack_payload; - } else if (pucch->pucch_resource != NULL) { @@ -1799,8 +1798,6 @@ void nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, default: AssertFatal(1==0,"Group hopping flag undefined (0,1,2) \n"); } - - } @@ -2195,7 +2192,8 @@ uint8_t get_downlink_ack(NR_UE_MAC_INST_t *mac, sched_frame = (sched_frame + 1) % 1024; } AssertFatal(sched_slot < slots_per_frame, "sched_slot was calculated incorrect %d\n", sched_slot); - LOG_D(PHY,"HARQ pid %d is active for %d.%d (dl_slot %d, feedback_to_ul %d, is_common %d\n",dl_harq_pid, sched_frame,sched_slot,current_harq->dl_slot,current_harq->feedback_to_ul,current_harq->is_common); + LOG_D(PHY,"HARQ pid %d is active for %d.%d (dl_slot %d, feedback_to_ul %d, is_common %d\n", + dl_harq_pid, sched_frame,sched_slot,current_harq->dl_slot,current_harq->feedback_to_ul,current_harq->is_common); /* check if current tx slot should transmit downlink acknowlegment */ if (sched_frame == frame && sched_slot == slot) { if (get_softmodem_params()->emulate_l1) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index b5e90a4dcc..0db821dd88 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -1306,9 +1306,10 @@ int nr_acknack_scheduling(int mod_id, csi_pucch->ul_slot == pucch->ul_slot) { // skip the CSI PUCCH if it is present and if in the next frame/slot // and if we don't multiplex - // FIXME currently we support at most 11 bits in pucch2 so skip also in that case + /* FIXME currently we support at most 11 bits in pucch2 so skip also in that case. + We need to set the limit to 10 because SR scheduling has been moved afterwards */ if(!csi_pucch->simultaneous_harqcsi - || ((csi_pucch->csi_bits + csi_pucch->dai_c) >= 11)) { + || ((csi_pucch->csi_bits + csi_pucch->dai_c) >= 10)) { LOG_D(NR_MAC,"Cannot multiplex csi_pucch %d +csi_pucch->dai_c %d for %d.%d\n",csi_pucch->csi_bits,csi_pucch->dai_c,csi_pucch->frame,csi_pucch->ul_slot); nr_fill_nfapi_pucch(RC.nrmac[mod_id], frame, slot, csi_pucch, UE); memset(csi_pucch, 0, sizeof(*csi_pucch)); @@ -1328,9 +1329,7 @@ int nr_acknack_scheduling(int mod_id, else { csi_pucch->timing_indicator = ind_found; csi_pucch->dai_c++; - // keep updating format 2 indicator - pucch->timing_indicator = ind_found; // index in the list of timing indicators - pucch->dai_c++; + memset(pucch,0,sizeof(*pucch)); LOG_D(NR_MAC,"multiplexing csi_pucch %d +csi_pucch->dai_c %d for %d.%d\n",csi_pucch->csi_bits,csi_pucch->dai_c,csi_pucch->frame,csi_pucch->ul_slot); return 1; From d908779c388fafa787618e4d8fb9cfccbf0bb82e Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 4 Aug 2022 11:34:25 +0200 Subject: [PATCH 248/267] lowercase bwp --- openair1/SIMULATION/NR_PHY/dlsim.c | 12 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 66 +++++----- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 42 +++--- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 34 ++--- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 120 ++++++++---------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 39 +++--- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 38 +++--- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 10 +- 8 files changed, 176 insertions(+), 185 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index e2449d21da..0fe5315d4e 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -280,7 +280,7 @@ void nr_dlsim_preprocessor(module_id_t module_id, NR_UE_info_t *UE_info = RC.nrmac[module_id]->UE_info.list[0]; AssertFatal(RC.nrmac[module_id]->UE_info.list[1]==NULL, "can have only a single UE\n"); NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl; - NR_UE_DL_BWP_t *BWP = &UE_info->current_DL_BWP; + NR_UE_DL_BWP_t *current_BWP = &UE_info->current_DL_BWP; NR_ServingCellConfigCommon_t *scc = RC.nrmac[0]->common_channels[0].ServingCellConfigCommon; uint8_t nr_of_candidates = 0; @@ -307,7 +307,7 @@ void nr_dlsim_preprocessor(module_id_t module_id, NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; - nr_set_pdsch_semi_static(BWP, + nr_set_pdsch_semi_static(current_BWP, scc, /* tda = */ 0, g_nrOfLayers, @@ -320,10 +320,10 @@ void nr_dlsim_preprocessor(module_id_t module_id, sched_pdsch->mcs = g_mcsIndex; /* the following might override the table that is mandated by RRC * configuration */ - BWP->mcsTableIdx = g_mcsTableIdx; + current_BWP->mcsTableIdx = g_mcsTableIdx; - sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, BWP->mcsTableIdx); - sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, BWP->mcsTableIdx); + sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, current_BWP->mcsTableIdx); + sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, current_BWP->mcsTableIdx); sched_pdsch->tb_size = nr_compute_tbs(sched_pdsch->Qm, sched_pdsch->R, sched_pdsch->rbSize, @@ -351,7 +351,7 @@ void nr_dlsim_preprocessor(module_id_t module_id, AssertFatal(sched_pdsch->rbStart >= 0, "invalid rbStart %d\n", sched_pdsch->rbStart); AssertFatal(sched_pdsch->rbSize > 0, "invalid rbSize %d\n", sched_pdsch->rbSize); AssertFatal(sched_pdsch->mcs >= 0, "invalid mcs %d\n", sched_pdsch->mcs); - AssertFatal(BWP->mcsTableIdx >= 0 && BWP->mcsTableIdx <= 2, "invalid mcsTableIdx %d\n", BWP->mcsTableIdx); + AssertFatal(current_BWP->mcsTableIdx >= 0 && current_BWP->mcsTableIdx <= 2, "invalid mcsTableIdx %d\n", current_BWP->mcsTableIdx); } typedef struct { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index cafa2c02d9..745fc1ae2b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -694,10 +694,10 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t gNB_MAC_INST *nr_mac = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - NR_UE_UL_BWP_t *UL_BWP = &ra->UL_BWP; + NR_UE_UL_BWP_t *ul_bwp = &ra->UL_BWP; - NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = UL_BWP->tdaList; - int mu = UL_BWP->scs; + NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = ul_bwp->tdaList; + int mu = ul_bwp->scs; uint8_t K2 = *pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->k2; const int sched_frame = frame + (slot + K2 >= nr_slots_per_frame[mu]); const int sched_slot = (slot + K2) % nr_slots_per_frame[mu]; @@ -841,7 +841,7 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t NR_UL_DCI_FORMAT_0_0, NR_RNTI_TC, pusch_pdu->bwp_size, - UL_BWP->bwp_id, + ul_bwp->bwp_id, coreset, nr_mac->cset0_bwp_size); @@ -878,16 +878,16 @@ void nr_get_Msg3alloc(module_id_t module_id, uint16_t msg3_nb_rb = 8; // sdu has 6 or 8 bytes frame_type_t frame_type = RC.nrmac[module_id]->common_channels->frame_type; - NR_UE_UL_BWP_t *UL_BWP = &ra->UL_BWP; + NR_UE_UL_BWP_t *ul_bwp = &ra->UL_BWP; - int mu = UL_BWP->scs; + int mu = ul_bwp->scs; int StartSymbolIndex = 0; int NrOfSymbols = 0; int startSymbolAndLength = 0; int temp_slot = 0; ra->Msg3_tda_id = 16; // initialization to a value above limit - NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = UL_BWP->tdaList; + NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = ul_bwp->tdaList; const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; const int n_slots_frame = nr_slots_per_frame[mu]; @@ -951,9 +951,9 @@ void nr_get_Msg3alloc(module_id_t module_id, int bwpSize = NRRIV2BW(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); int bwpStart = NRRIV2PRBOFFSET(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - if (bwpSize != UL_BWP->BWPSize || bwpStart != UL_BWP->BWPStart) { - int act_bwp_start = UL_BWP->BWPStart; - int act_bwp_size = UL_BWP->BWPSize; + if (bwpSize != ul_bwp->BWPSize || bwpStart != ul_bwp->BWPStart) { + int act_bwp_start = ul_bwp->BWPStart; + int act_bwp_size = ul_bwp->BWPSize; if (!((bwpStart >= act_bwp_start) && ((bwpStart+bwpSize) <= (act_bwp_start+act_bwp_size)))) bwpStart = act_bwp_start; } @@ -1065,7 +1065,7 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t gNB_MAC_INST *mac = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = &mac->common_channels[CC_id]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - NR_UE_UL_BWP_t *UL_BWP = &ra->UL_BWP; + NR_UE_UL_BWP_t *ul_bwp = &ra->UL_BWP; if (ra->state == RA_IDLE) { LOG_W(NR_MAC,"RA is not active for RA %X. skipping msg3 scheduling\n", ra->rnti); @@ -1098,11 +1098,11 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t nfapi_nr_pusch_pdu_t *pusch_pdu = &future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pusch_pdu; memset(pusch_pdu, 0, sizeof(nfapi_nr_pusch_pdu_t)); - int ibwp_size = NRRIV2BW(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - int scs = UL_BWP->scs; - int fh = (UL_BWP->pusch_Config && UL_BWP->pusch_Config->frequencyHopping) ? 1 : 0; - int startSymbolAndLength = UL_BWP->tdaList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; - int mappingtype = UL_BWP->tdaList->list.array[ra->Msg3_tda_id]->mappingType; + const int ibwp_size = NRRIV2BW(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + const int scs = ul_bwp->scs; + const int fh = (ul_bwp->pusch_Config && ul_bwp->pusch_Config->frequencyHopping) ? 1 : 0; + const int startSymbolAndLength = ul_bwp->tdaList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; + const int mappingtype = ul_bwp->tdaList->list.array[ra->Msg3_tda_id]->mappingType; LOG_D(NR_MAC, "Frame %d, Slot %d Adding Msg3 UL Config Request for (%d,%d) : (%d,%d,%d) for rnti: %d\n", frameP, @@ -1131,7 +1131,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra gNB_MAC_INST *nr_mac = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; - NR_UE_DL_BWP_t *DL_BWP = &ra->DL_BWP; + NR_UE_DL_BWP_t *dl_bwp = &ra->DL_BWP; if ((ra->Msg2_frame == frameP) && (ra->Msg2_slot == slotP)) { @@ -1142,13 +1142,13 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; NR_SearchSpace_t *ss = ra->ra_ss; - NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList = DL_BWP->tdaList; + NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList = dl_bwp->tdaList; long BWPStart = 0; long BWPSize = 0; NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config = NULL; if(*ss->controlResourceSetId!=0) { - BWPStart = DL_BWP->BWPStart; + BWPStart = dl_bwp->BWPStart; BWPSize = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); } else { type0_PDCCH_CSS_config = &nr_mac->type0_PDCCH_CSS_config[ra->beam_id]; @@ -1242,8 +1242,8 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra // information to data and is reset every slot. const int pduindex = nr_mac->pdu_index[CC_id]++; - NR_PDSCH_Config_t *pdsch_Config = DL_BWP->pdsch_Config; - uint8_t mcsTableIdx = DL_BWP->mcsTableIdx; + NR_PDSCH_Config_t *pdsch_Config = dl_bwp->pdsch_Config; + uint8_t mcsTableIdx = dl_bwp->mcsTableIdx; int dmrsConfigType=0; if (pdsch_Config && @@ -1257,7 +1257,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra pdsch_pdu_rel15->pduIndex = pduindex; pdsch_pdu_rel15->BWPSize = BWPSize; pdsch_pdu_rel15->BWPStart = BWPStart; - pdsch_pdu_rel15->SubcarrierSpacing = DL_BWP->scs; + pdsch_pdu_rel15->SubcarrierSpacing = dl_bwp->scs; pdsch_pdu_rel15->CyclicPrefix = 0; pdsch_pdu_rel15->NrOfCodewords = 1; pdsch_pdu_rel15->mcsTable[0] = mcsTableIdx; @@ -1370,13 +1370,13 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra fill_dci_pdu_rel15(scc, ra->CellGroup, - DL_BWP, + dl_bwp, &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci - 1], &dci_payload, NR_DL_DCI_FORMAT_1_0, NR_RNTI_RA, BWPSize, - DL_BWP->bwp_id, + dl_bwp->bwp_id, coreset, nr_mac->cset0_bwp_size); @@ -1422,7 +1422,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra gNB_MAC_INST *nr_mac = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; - NR_UE_DL_BWP_t *DL_BWP = &ra->DL_BWP; + NR_UE_DL_BWP_t *dl_bwp = &ra->DL_BWP; if (ra->Msg4_frame == frameP && ra->Msg4_slot == slotP ) { @@ -1433,7 +1433,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra NR_SearchSpace_t *ss = ra->ra_ss; NR_ControlResourceSet_t *coreset = ra->coreset; - NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList = DL_BWP->tdaList; + NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList = dl_bwp->tdaList; AssertFatal(coreset!=NULL,"Coreset cannot be null for RA-Msg4\n"); @@ -1456,8 +1456,8 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra long BWPSize = 0; NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config = NULL; if(*ss->controlResourceSetId!=0) { - BWPStart = DL_BWP->BWPStart; - BWPSize = DL_BWP->BWPSize; + BWPStart = dl_bwp->BWPStart; + BWPSize = dl_bwp->BWPSize; } else { type0_PDCCH_CSS_config = &nr_mac->type0_PDCCH_CSS_config[ra->beam_id]; BWPStart = type0_PDCCH_CSS_config->cset_start_rb; @@ -1567,7 +1567,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra uint16_t N_DMRS_SLOT = get_num_dmrs(dlDmrsSymbPos); - NR_PDSCH_Config_t *pdsch_Config = DL_BWP->pdsch_Config; + NR_PDSCH_Config_t *pdsch_Config = dl_bwp->pdsch_Config; int dmrsConfigType=0; if (pdsch_Config && pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA && @@ -1593,7 +1593,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra N_PRB_DMRS = nr_mac->sched_ctrlCommon->pdsch_semi_static.numDmrsCdmGrpsNoData * 4; } - uint8_t mcsTableIdx = DL_BWP->mcsTableIdx; + uint8_t mcsTableIdx = dl_bwp->mcsTableIdx; int rbStart = 0; int rbSize = 0; @@ -1669,7 +1669,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra pdsch_pdu_rel15->pduIndex = pduindex; pdsch_pdu_rel15->BWPSize = BWPSize; pdsch_pdu_rel15->BWPStart = BWPStart; - pdsch_pdu_rel15->SubcarrierSpacing = DL_BWP->scs; + pdsch_pdu_rel15->SubcarrierSpacing = dl_bwp->scs; pdsch_pdu_rel15->CyclicPrefix = 0; pdsch_pdu_rel15->NrOfCodewords = 1; int R = nr_get_code_rate_dl(mcsIndex,mcsTableIdx); @@ -1764,13 +1764,13 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra fill_dci_pdu_rel15(scc, ra->CellGroup, - DL_BWP, + dl_bwp, &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci - 1], &dci_payload, NR_DL_DCI_FORMAT_1_0, NR_RNTI_TC, pdsch_pdu_rel15->BWPSize, - DL_BWP->bwp_id, + dl_bwp->bwp_id, coreset, nr_mac->cset0_bwp_size); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 3e80fd104b..6aee81fa67 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -388,8 +388,8 @@ bool allocate_dl_retransmission(module_id_t module_id, gNB_MAC_INST *nr_mac = RC.nrmac[module_id]; const NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels->ServingCellConfigCommon; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_DL_BWP_t *BWP = &UE->current_DL_BWP; - NR_UE_UL_BWP_t *UBWP = &UE->current_UL_BWP; + NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; + NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; NR_sched_pdsch_t *retInfo = &sched_ctrl->harq_processes[current_harq_pid].sched_pdsch; NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; @@ -404,7 +404,7 @@ bool allocate_dl_retransmission(module_id_t module_id, } const int coresetid = sched_ctrl->coreset->controlResourceSetId; - const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : BWP->BWPSize; + const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : dl_bwp->BWPSize; int rbStart = 0; // start wrt BWPstart int rbSize = 0; @@ -435,7 +435,7 @@ bool allocate_dl_retransmission(module_id_t module_id, /* check whether we need to switch the TDA allocation since the last * (re-)transmission */ if (ps->time_domain_allocation != tda) { - nr_set_pdsch_semi_static(BWP, + nr_set_pdsch_semi_static(dl_bwp, scc, tda, ps->nrOfLayers, @@ -447,7 +447,7 @@ bool allocate_dl_retransmission(module_id_t module_id, * that we have enough resources */ NR_pdsch_semi_static_t temp_ps = *ps; - nr_set_pdsch_semi_static(BWP, + nr_set_pdsch_semi_static(dl_bwp, scc, tda, ps->nrOfLayers, @@ -519,7 +519,7 @@ bool allocate_dl_retransmission(module_id_t module_id, /* Find PUCCH occasion: if it fails, undo CCE allocation (undoing PUCCH * allocation after CCE alloc fail would be more complex) */ - int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, UBWP->pucch_Config, CCEIndex); + int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, ul_bwp->pucch_Config, CCEIndex); const int alloc = nr_acknack_scheduling(module_id, UE, frame, slot, r_pucch, 0); if (alloc<0) { LOG_D(MAC, @@ -579,7 +579,7 @@ void pf_dl(module_id_t module_id, continue; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_DL_BWP_t *BWP = &UE->current_DL_BWP; + NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP; if (sched_ctrl->ul_failure==1 && get_softmodem_params()->phy_test==0) continue; @@ -619,15 +619,15 @@ void pf_dl(module_id_t module_id, /* Calculate coeff */ const NR_bler_options_t *bo = &mac->dl_bler; - const int max_mcs_table = BWP->mcsTableIdx == 1 ? 27 : 28; + const int max_mcs_table = current_BWP->mcsTableIdx == 1 ? 27 : 28; const int max_mcs = min(sched_ctrl->dl_max_mcs, max_mcs_table); if (bo->harq_round_max == 1) sched_pdsch->mcs = max_mcs; else sched_pdsch->mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->dl_bler_stats, max_mcs, frame); UE->layers = set_dl_nrOfLayers(sched_ctrl); - const uint8_t Qm = nr_get_Qm_dl(sched_pdsch->mcs, BWP->mcsTableIdx); - const uint16_t R = nr_get_code_rate_dl(sched_pdsch->mcs, BWP->mcsTableIdx); + const uint8_t Qm = nr_get_Qm_dl(sched_pdsch->mcs, current_BWP->mcsTableIdx); + const uint16_t R = nr_get_code_rate_dl(sched_pdsch->mcs, current_BWP->mcsTableIdx); uint32_t tbs = nr_compute_tbs(Qm, R, 1, /* rbSize */ @@ -657,13 +657,13 @@ void pf_dl(module_id_t module_id, NR_UE_sched_ctrl_t *sched_ctrl = &iterator->UE->UE_sched_ctrl; const uint16_t rnti = iterator->UE->rnti; - NR_UE_DL_BWP_t *BWP = &iterator->UE->current_DL_BWP; - NR_UE_UL_BWP_t *UBWP = &iterator->UE->current_UL_BWP; + NR_UE_DL_BWP_t *dl_bwp = &iterator->UE->current_DL_BWP; + NR_UE_UL_BWP_t *ul_bwp = &iterator->UE->current_UL_BWP; const int coresetid = sched_ctrl->coreset->controlResourceSetId; const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : - BWP->BWPSize; + dl_bwp->BWPSize; int rbStart = 0; // start wrt BWPstart if (sched_ctrl->available_dl_harq.head < 0) { @@ -703,7 +703,7 @@ void pf_dl(module_id_t module_id, /* Find PUCCH occasion: if it fails, undo CCE allocation (undoing PUCCH * allocation after CCE alloc fail would be more complex) */ - int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, UBWP->pucch_Config, CCEIndex); + int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, ul_bwp->pucch_Config, CCEIndex); const int alloc = nr_acknack_scheduling(module_id, iterator->UE, frame, slot, r_pucch, 0); if (alloc<0) { @@ -730,7 +730,7 @@ void pf_dl(module_id_t module_id, NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; if (ps->nrOfLayers != iterator->UE->layers || ps->time_domain_allocation != tda ) { - nr_set_pdsch_semi_static(BWP, + nr_set_pdsch_semi_static(dl_bwp, scc, tda, iterator->UE->layers, @@ -749,8 +749,8 @@ void pf_dl(module_id_t module_id, while (rbStart + max_rbSize < bwpSize && (rballoc_mask[rbStart + max_rbSize] & slbitmap) == slbitmap) max_rbSize++; - sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, BWP->mcsTableIdx); - sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, BWP->mcsTableIdx); + sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx); + sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx); sched_pdsch->pucch_allocation = alloc; uint32_t TBS = 0; uint16_t rbSize; @@ -796,18 +796,18 @@ void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t /* This is temporary and it assumes all UEs have the same BWP and TDA*/ NR_UE_info_t *UE=UE_info->list[0]; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_DL_BWP_t *BWP = &UE->current_DL_BWP; + NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP; const int tda = get_dl_tda(RC.nrmac[module_id], scc, slot); int startSymbolIndex, nrOfSymbols; - const struct NR_PDSCH_TimeDomainResourceAllocationList *tdaList = BWP->tdaList; + const struct NR_PDSCH_TimeDomainResourceAllocationList *tdaList = current_BWP->tdaList; AssertFatal(tda < tdaList->list.count, "time_domain_allocation %d>=%d\n", tda, tdaList->list.count); const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength; SLIV2SL(startSymbolAndLength, &startSymbolIndex, &nrOfSymbols); const int coresetid = sched_ctrl->coreset->controlResourceSetId; - const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : BWP->BWPSize; - const uint16_t BWPStart = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_start : BWP->BWPStart; + const uint16_t bwpSize = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_size : current_BWP->BWPSize; + const uint16_t BWPStart = coresetid == 0 ? RC.nrmac[module_id]->cset0_bwp_start : current_BWP->BWPStart; const uint16_t slbitmap = SL_to_bitmap(startSymbolIndex, nrOfSymbols); uint16_t *vrb_map = RC.nrmac[module_id]->common_channels[CC_id].vrb_map; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index 5926b61f4c..e474315de7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -195,18 +195,18 @@ void nr_preprocessor_phytest(module_id_t module_id, NR_UE_info_t *UE = RC.nrmac[module_id]->UE_info.list[0]; NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_DL_BWP_t *BWP = &UE->current_DL_BWP; + NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; const int CC_id = 0; const int tda = get_dl_tda(RC.nrmac[module_id], scc, slot); NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; ps->nrOfLayers = target_dl_Nl; if (ps->time_domain_allocation != tda || ps->nrOfLayers != target_dl_Nl) - nr_set_pdsch_semi_static(BWP, scc, tda, target_dl_Nl,sched_ctrl , ps); + nr_set_pdsch_semi_static(dl_bwp, scc, tda, target_dl_Nl,sched_ctrl , ps); /* find largest unallocated chunk */ - const int bwpSize = BWP->BWPSize; - const int BWPStart = BWP->BWPStart; + const int bwpSize = dl_bwp->BWPSize; + const int BWPStart = dl_bwp->BWPStart; int rbStart = 0; int rbSize = 0; @@ -309,8 +309,8 @@ void nr_preprocessor_phytest(module_id_t module_id, sched_pdsch->rbSize = rbSize; sched_pdsch->mcs = target_dl_mcs; - sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, BWP->mcsTableIdx); - sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, BWP->mcsTableIdx); + sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx); + sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx); sched_ctrl->dl_bler_stats.mcs = target_dl_mcs; /* for logging output */ sched_pdsch->tb_size = nr_compute_tbs(sched_pdsch->Qm, sched_pdsch->R, @@ -351,10 +351,10 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ const int CC_id = 0; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; - const int mu = BWP->scs; + NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; + const int mu = ul_bwp->scs; - const struct NR_PUSCH_TimeDomainResourceAllocationList *tdaList = BWP->tdaList; + const struct NR_PUSCH_TimeDomainResourceAllocationList *tdaList = ul_bwp->tdaList; const int temp_tda = get_ul_tda(nr_mac, scc, slot); if (temp_tda < 0) return false; @@ -362,7 +362,7 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ "time domain assignment %d >= %d\n", temp_tda, tdaList->list.count); - int K2 = get_K2(BWP->tdaList, temp_tda, mu); + int K2 = get_K2(ul_bwp->tdaList, temp_tda, mu); const int sched_frame = frame + (slot + K2 >= nr_slots_per_frame[mu]); const int sched_slot = (slot + K2) % nr_slots_per_frame[mu]; const int tda = get_ul_tda(nr_mac, scc, sched_slot); @@ -384,13 +384,13 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; if (ps->time_domain_allocation != tda || ps->nrOfLayers != target_ul_Nl) - nr_set_pusch_semi_static(BWP, scc, tda, target_ul_Nl,ps); + nr_set_pusch_semi_static(ul_bwp, scc, tda, target_ul_Nl,ps); uint16_t rbStart = 0; uint16_t rbSize; - const int bw = BWP->BWPSize; - const int BWPStart = BWP->BWPStart; + const int bw = ul_bwp->BWPSize; + const int BWPStart = ul_bwp->BWPStart; if (target_ul_bw>bw) rbSize = bw; @@ -453,10 +453,10 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ /* Calculate TBS from MCS */ ps->nrOfLayers = target_ul_Nl; - sched_pusch->R = nr_get_code_rate_ul(mcs, BWP->mcs_table); - sched_pusch->Qm = nr_get_Qm_ul(mcs, BWP->mcs_table); - if (BWP->pusch_Config->tp_pi2BPSK - && ((BWP->mcs_table == 3 && mcs < 2) || (BWP->mcs_table == 4 && mcs < 6))) { + sched_pusch->R = nr_get_code_rate_ul(mcs, ul_bwp->mcs_table); + sched_pusch->Qm = nr_get_Qm_ul(mcs, ul_bwp->mcs_table); + if (ul_bwp->pusch_Config->tp_pi2BPSK + && ((ul_bwp->mcs_table == 3 && mcs < 2) || (ul_bwp->mcs_table == 4 && mcs < 6))) { sched_pusch->R >>= 1; sched_pusch->Qm <<= 1; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 1dafff4635..497546184f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -508,7 +508,7 @@ bool nr_find_nb_rb(uint16_t Qm, return *tbs >= bytes && *nb_rb <= nb_rb_max; } -void nr_set_pdsch_semi_static(const NR_UE_DL_BWP_t *BWP, +void nr_set_pdsch_semi_static(const NR_UE_DL_BWP_t *dl_bwp, const NR_ServingCellConfigCommon_t *scc, int tda, uint8_t layers, @@ -517,11 +517,11 @@ void nr_set_pdsch_semi_static(const NR_UE_DL_BWP_t *BWP, { bool reset_dmrs = false; - NR_PDSCH_Config_t *pdsch_Config = BWP->pdsch_Config; + NR_PDSCH_Config_t *pdsch_Config = dl_bwp->pdsch_Config; LOG_D(NR_MAC,"tda %d, ps->time_domain_allocation %d,layers %d, ps->nrOfLayers %d, pdsch_config %p\n",tda,ps->time_domain_allocation,layers,ps->nrOfLayers,pdsch_Config); reset_dmrs = true; ps->time_domain_allocation = tda; - NR_PDSCH_TimeDomainResourceAllocationList_t *tdaList = BWP->tdaList; + NR_PDSCH_TimeDomainResourceAllocationList_t *tdaList = dl_bwp->tdaList; AssertFatal(tda < tdaList->list.count, "time_domain_allocation %d>=%d\n", tda, tdaList->list.count); ps->mapping_type = tdaList->list.array[tda]->mappingType; if (pdsch_Config) { @@ -535,7 +535,7 @@ void nr_set_pdsch_semi_static(const NR_UE_DL_BWP_t *BWP, const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength; SLIV2SL(startSymbolAndLength, &ps->startSymbolIndex, &ps->nrOfSymbols); - if (BWP->dci_format == NR_DL_DCI_FORMAT_1_0) { + if (dl_bwp->dci_format == NR_DL_DCI_FORMAT_1_0) { if (ps->nrOfSymbols == 2) ps->numDmrsCdmGrpsNoData = 1; else @@ -562,7 +562,7 @@ void nr_set_pdsch_semi_static(const NR_UE_DL_BWP_t *BWP, LOG_D(NR_MAC,"Filling dmrs info, ps->N_PRB_DMRS %d, ps->dl_dmrs_symb_pos %x, ps->N_DMRS_SLOT %d\n",ps->N_PRB_DMRS,ps->dl_dmrs_symb_pos,ps->N_DMRS_SLOT); } -void nr_set_pusch_semi_static(const NR_UE_UL_BWP_t *BWP, +void nr_set_pusch_semi_static(const NR_UE_UL_BWP_t *ul_bwp, const NR_ServingCellConfigCommon_t *scc, int tda, uint8_t nrOfLayers, @@ -570,24 +570,24 @@ void nr_set_pusch_semi_static(const NR_UE_UL_BWP_t *BWP, ps->time_domain_allocation = tda; - const int startSymbolAndLength = BWP->tdaList->list.array[tda]->startSymbolAndLength; + const int startSymbolAndLength = ul_bwp->tdaList->list.array[tda]->startSymbolAndLength; SLIV2SL(startSymbolAndLength, &ps->startSymbolIndex, &ps->nrOfSymbols); ps->nrOfLayers = nrOfLayers; // TODO setting of cdm groups with no data to be redone for MIMO - if (BWP->transform_precoding || nrOfLayers<3) - ps->num_dmrs_cdm_grps_no_data = (BWP->dci_format == NR_UL_DCI_FORMAT_0_1) ? 1 : (ps->nrOfSymbols == 2 ? 1 : 2); + if (ul_bwp->transform_precoding || nrOfLayers<3) + ps->num_dmrs_cdm_grps_no_data = (ul_bwp->dci_format == NR_UL_DCI_FORMAT_0_1) ? 1 : (ps->nrOfSymbols == 2 ? 1 : 2); else ps->num_dmrs_cdm_grps_no_data = 2; /* DMRS calculations */ - ps->mapping_type = BWP->tdaList->list.array[tda]->mappingType; - ps->NR_DMRS_UplinkConfig = BWP->pusch_Config ? + ps->mapping_type = ul_bwp->tdaList->list.array[tda]->mappingType; + ps->NR_DMRS_UplinkConfig = ul_bwp->pusch_Config ? (ps->mapping_type == NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeA ? - BWP->pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup : - BWP->pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup) : NULL; + ul_bwp->pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup : + ul_bwp->pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup) : NULL; ps->dmrs_config_type = ps->NR_DMRS_UplinkConfig ? ((ps->NR_DMRS_UplinkConfig->dmrs_Type == NULL ? 0 : 1)) : 0; const pusch_dmrs_AdditionalPosition_t additional_pos = ps->NR_DMRS_UplinkConfig ? (ps->NR_DMRS_UplinkConfig->dmrs_AdditionalPosition == NULL @@ -882,13 +882,13 @@ void config_uldci(const NR_SIB1_t *sib1, dci_pdu_rel15_t *dci_pdu_rel15, int time_domain_assignment, uint8_t tpc, - NR_UE_UL_BWP_t *UBWP) { + NR_UE_UL_BWP_t *ul_bwp) { - int bwp_id = UBWP->bwp_id; - nr_dci_format_t dci_format = UBWP->dci_format; + int bwp_id = ul_bwp->bwp_id; + nr_dci_format_t dci_format = ul_bwp->dci_format; dci_pdu_rel15->frequency_domain_assignment.val = - PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size, pusch_pdu->rb_start, UBWP->BWPSize); + PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size, pusch_pdu->rb_start, ul_bwp->BWPSize); dci_pdu_rel15->time_domain_assignment.val = time_domain_assignment; dci_pdu_rel15->frequency_hopping_flag.val = pusch_pdu->frequency_hopping; dci_pdu_rel15->mcs = pusch_pdu->mcs_index; @@ -896,7 +896,7 @@ void config_uldci(const NR_SIB1_t *sib1, dci_pdu_rel15->rv = pusch_pdu->pusch_data.rv_index; dci_pdu_rel15->harq_pid = pusch_pdu->pusch_data.harq_process_id; dci_pdu_rel15->tpc = tpc; - NR_PUSCH_Config_t *pusch_Config = UBWP->pusch_Config; + NR_PUSCH_Config_t *pusch_Config = ul_bwp->pusch_Config; if (pusch_Config) AssertFatal(pusch_Config->resourceAllocation == NR_PUSCH_Config__resourceAllocation_resourceAllocationType1, "Only frequency resource allocation type 1 is currently supported\n"); @@ -908,7 +908,7 @@ void config_uldci(const NR_SIB1_t *sib1, LOG_D(NR_MAC,"Configuring DCI Format 0_1\n"); dci_pdu_rel15->dai[0].val = 0; //TODO // bwp indicator as per table 7.3.1.1.2-1 in 38.212 - dci_pdu_rel15->bwp_indicator.val = UBWP->n_ul_bwp < 4 ? bwp_id : bwp_id - 1; + dci_pdu_rel15->bwp_indicator.val = ul_bwp->n_ul_bwp < 4 ? bwp_id : bwp_id - 1; // SRS resource indicator if (pusch_Config && pusch_Config->txConfig != NULL) { @@ -1027,7 +1027,7 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, NR_PUCCH_ResourceSet_t *pucchresset; NR_PUCCH_FormatConfig_t *pucchfmt; NR_PUCCH_ResourceId_t *resource_id = NULL; - NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; + NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP; long *id0 = NULL; int n_list, n_set; @@ -1039,7 +1039,7 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, uint16_t O_uci = O_csi + O_ack; - NR_PUSCH_Config_t *pusch_Config = BWP->pusch_Config; + NR_PUSCH_Config_t *pusch_Config = current_BWP->pusch_Config; long *pusch_id = pusch_Config ? pusch_Config->dataScramblingIdentityPUSCH : NULL; @@ -1049,7 +1049,7 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, id0 = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->transformPrecodingDisabled->scramblingID0; else id0 = scc->physCellId; - NR_PUCCH_ConfigCommon_t *pucch_ConfigCommon = BWP->pucch_ConfigCommon; + NR_PUCCH_ConfigCommon_t *pucch_ConfigCommon = current_BWP->pucch_ConfigCommon; // hop flags and hopping id are valid for any BWP switch (pucch_ConfigCommon->pucch_GroupHopping){ @@ -1077,12 +1077,12 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, else pucch_pdu->hopping_id = *scc->physCellId; - pucch_pdu->bwp_size = BWP->BWPSize; - pucch_pdu->bwp_start = BWP->BWPStart; - pucch_pdu->subcarrier_spacing = BWP->scs; - pucch_pdu->cyclic_prefix = (BWP->cyclicprefix==NULL) ? 0 : *BWP->cyclicprefix; + pucch_pdu->bwp_size = current_BWP->BWPSize; + pucch_pdu->bwp_start = current_BWP->BWPStart; + pucch_pdu->subcarrier_spacing = current_BWP->scs; + pucch_pdu->cyclic_prefix = (current_BWP->cyclicprefix==NULL) ? 0 : *current_BWP->cyclicprefix; - NR_PUCCH_Config_t *pucch_Config = BWP->pucch_Config; + NR_PUCCH_Config_t *pucch_Config = current_BWP->pucch_Config; if (r_pucch<0 || pucch_Config){ LOG_D(NR_MAC,"pucch_acknak: Filling dedicated configuration for PUCCH\n"); @@ -1281,14 +1281,14 @@ void set_r_pucch_parms(int rsetindex, } void prepare_dci(const NR_CellGroupConfig_t *CellGroup, - const NR_UE_DL_BWP_t *BWP, + const NR_UE_DL_BWP_t *current_BWP, const NR_ControlResourceSet_t *coreset, dci_pdu_rel15_t *dci_pdu_rel15, nr_dci_format_t format) { AssertFatal(CellGroup!=NULL,"CellGroup shouldn't be null here\n"); - const NR_PDSCH_Config_t *pdsch_Config = BWP ? BWP->pdsch_Config : NULL; + const NR_PDSCH_Config_t *pdsch_Config = current_BWP ? current_BWP->pdsch_Config : NULL; switch(format) { case NR_UL_DCI_FORMAT_0_1: @@ -1350,8 +1350,8 @@ void prepare_dci(const NR_CellGroupConfig_t *CellGroup, else dci_pdu_rel15->srs_request.val = 0; // CBGTI and CBGFI - if (BWP->pdsch_servingcellconfig && - BWP->pdsch_servingcellconfig->codeBlockGroupTransmission != NULL) + if (current_BWP->pdsch_servingcellconfig && + current_BWP->pdsch_servingcellconfig->codeBlockGroupTransmission != NULL) AssertFatal(1==0,"CBG transmission currently not supported\n"); break; default : @@ -1362,7 +1362,7 @@ void prepare_dci(const NR_CellGroupConfig_t *CellGroup, void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, const NR_CellGroupConfig_t *CellGroup, - const NR_UE_DL_BWP_t *BWP, + const NR_UE_DL_BWP_t *current_BWP, nfapi_nr_dl_dci_pdu_t *pdcch_dci_pdu, dci_pdu_rel15_t *dci_pdu_rel15, int dci_format, @@ -1383,7 +1383,7 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, pdcch_dci_pdu->PayloadSizeBits = dci_size; AssertFatal(dci_size <= 64, "DCI sizes above 64 bits not yet supported"); if (dci_format == NR_DL_DCI_FORMAT_1_1 || dci_format == NR_UL_DCI_FORMAT_0_1) - prepare_dci(CellGroup, BWP, coreset, dci_pdu_rel15, dci_format); + prepare_dci(CellGroup, current_BWP, coreset, dci_pdu_rel15, dci_format); /// Payload generation switch (dci_format) { @@ -2251,7 +2251,7 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, if(ul_bwp->bwp_Id == UL_BWP->bwp_id) break; } - AssertFatal(ul_bwp!=NULL,"Couldn't find DLBWP corresponding to BWP ID %ld\n",UL_BWP->bwp_id); + AssertFatal(ul_bwp!=NULL,"Couldn't find ULBWP corresponding to BWP ID %ld\n",UL_BWP->bwp_id); } // selection of dedicated BWPs @@ -2447,23 +2447,15 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; memset(sched_ctrl, 0, sizeof(*sched_ctrl)); sched_ctrl->dl_max_mcs = 28; /* do not limit MCS for individual UEs */ - sched_ctrl->set_pmi = false; - sched_ctrl->ta_frame = 0; sched_ctrl->ta_update = 31; - sched_ctrl->ta_apply = false; - sched_ctrl->ul_rssi = 0; - sched_ctrl->pucch_consecutive_dtx_cnt = 0; - sched_ctrl->pusch_consecutive_dtx_cnt = 0; - sched_ctrl->ul_failure = 0; sched_ctrl->sched_srs.frame = -1; sched_ctrl->sched_srs.slot = -1; - sched_ctrl->sched_srs.srs_scheduled = false; // initialize UE BWP information - NR_UE_DL_BWP_t *DL_BWP = &UE->current_DL_BWP; - memset(DL_BWP, 0, sizeof(*DL_BWP)); - NR_UE_UL_BWP_t *UL_BWP = &UE->current_UL_BWP; - memset(UL_BWP, 0, sizeof(*UL_BWP)); + NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; + memset(dl_bwp, 0, sizeof(*dl_bwp)); + NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; + memset(ul_bwp, 0, sizeof(*ul_bwp)); configure_UE_BWP(nr_mac, scc, sched_ctrl, NULL, UE); /* set illegal time domain allocation to force recomputation of all fields */ @@ -2473,13 +2465,13 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf /* Set default BWPs */ sched_ctrl->next_dl_bwp_id = -1; sched_ctrl->next_ul_bwp_id = -1; - AssertFatal(UL_BWP->n_ul_bwp <= NR_MAX_NUM_BWP, + AssertFatal(ul_bwp->n_ul_bwp <= NR_MAX_NUM_BWP, "uplinkBWP_ToAddModList has %d BWP!\n", - UL_BWP->n_ul_bwp); + ul_bwp->n_ul_bwp); /* get Number of HARQ processes for this UE */ // pdsch_servingcellconfig == NULL in SA -> will create default (8) number of HARQ processes - create_dl_harq_list(sched_ctrl, DL_BWP->pdsch_servingcellconfig); + create_dl_harq_list(sched_ctrl, dl_bwp->pdsch_servingcellconfig); // add all available UL HARQ processes for this UE // nb of ul harq processes not configurable create_nr_list(&sched_ctrl->available_ul_harq, 16); @@ -2671,12 +2663,12 @@ void nr_csirs_scheduling(int Mod_idP, continue; } - NR_UE_DL_BWP_t *BWP = &UE->current_DL_BWP; - NR_UE_UL_BWP_t *UBWP = &UE->current_UL_BWP; + NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; + NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; - if (!UBWP->csi_MeasConfig) continue; + if (!ul_bwp->csi_MeasConfig) continue; - NR_CSI_MeasConfig_t *csi_measconfig = UBWP->csi_MeasConfig; + NR_CSI_MeasConfig_t *csi_measconfig = ul_bwp->csi_MeasConfig; if (csi_measconfig->nzp_CSI_RS_ResourceToAddModList != NULL) { @@ -2702,20 +2694,20 @@ void nr_csirs_scheduling(int Mod_idP, nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *csirs_pdu_rel15 = &dl_tti_csirs_pdu->csi_rs_pdu.csi_rs_pdu_rel15; - csirs_pdu_rel15->subcarrier_spacing = BWP->scs; - if (BWP->cyclicprefix) - csirs_pdu_rel15->cyclic_prefix = *BWP->cyclicprefix; + csirs_pdu_rel15->subcarrier_spacing = dl_bwp->scs; + if (dl_bwp->cyclicprefix) + csirs_pdu_rel15->cyclic_prefix = *dl_bwp->cyclicprefix; else csirs_pdu_rel15->cyclic_prefix = 0; // According to last paragraph of TS 38.214 5.2.2.3.1 - if (resourceMapping.freqBand.startingRB < BWP->BWPStart) { - csirs_pdu_rel15->start_rb = BWP->BWPStart; + if (resourceMapping.freqBand.startingRB < dl_bwp->BWPStart) { + csirs_pdu_rel15->start_rb = dl_bwp->BWPStart; } else { csirs_pdu_rel15->start_rb = resourceMapping.freqBand.startingRB; } - if (resourceMapping.freqBand.nrofRBs > (BWP->BWPStart + BWP->BWPSize - csirs_pdu_rel15->start_rb)) { - csirs_pdu_rel15->nr_of_rbs = BWP->BWPStart + BWP->BWPSize - csirs_pdu_rel15->start_rb; + if (resourceMapping.freqBand.nrofRBs > (dl_bwp->BWPStart + dl_bwp->BWPSize - csirs_pdu_rel15->start_rb)) { + csirs_pdu_rel15->nr_of_rbs = dl_bwp->BWPStart + dl_bwp->BWPSize - csirs_pdu_rel15->start_rb; } else { csirs_pdu_rel15->nr_of_rbs = resourceMapping.freqBand.nrofRBs; } @@ -2942,23 +2934,23 @@ void schedule_nr_bwp_switch(module_id_t module_id, UE_iterator(UE_info->list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_DL_BWP_t *DLBWP = &UE->current_DL_BWP; - NR_UE_UL_BWP_t *ULBWP = &UE->current_UL_BWP; + NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; + NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; if (sched_ctrl->rrc_processing_timer == 0 && UE->Msg4_ACKed && sched_ctrl->next_dl_bwp_id >= 0) { int schedule_bwp_switching = false; - if (DLBWP->bwp_id == 0) { + if (dl_bwp->bwp_id == 0) { // Switching from Initial BWP to Dedicated BWP if (sched_ctrl->next_dl_bwp_id > 0 && sched_ctrl->next_ul_bwp_id > 0) { schedule_bwp_switching = true; LOG_W(NR_MAC,"%4d.%2d UE %04x Schedule BWP switch from Initial DL BWP to %ld and from Initial UL BWP to %ld\n", frame, slot, UE->rnti, sched_ctrl->next_dl_bwp_id, sched_ctrl->next_ul_bwp_id); } - } else if (DLBWP->bwp_id != sched_ctrl->next_dl_bwp_id && ULBWP->bwp_id != sched_ctrl->next_ul_bwp_id) { + } else if (dl_bwp->bwp_id != sched_ctrl->next_dl_bwp_id && ul_bwp->bwp_id != sched_ctrl->next_ul_bwp_id) { // Switching between Dedicated BWPs schedule_bwp_switching = true; LOG_W(NR_MAC,"%4d.%2d UE %04x Schedule BWP switch from dl_bwp_id %ld to %ld and from ul_bwp_id %ld to %ld\n", - frame, slot, UE->rnti, DLBWP->bwp_id, sched_ctrl->next_dl_bwp_id, ULBWP->bwp_id, sched_ctrl->next_ul_bwp_id); + frame, slot, UE->rnti, dl_bwp->bwp_id, sched_ctrl->next_dl_bwp_id, ul_bwp->bwp_id, sched_ctrl->next_ul_bwp_id); } if (schedule_bwp_switching) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 7b1c2fe01d..9987feb558 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -165,16 +165,16 @@ void nr_csi_meas_reporting(int Mod_idP, UE_iterator(RC.nrmac[Mod_idP]->UE_info.list, UE ) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_UL_BWP_t *UL_BWP = &UE->current_UL_BWP; - const int n_slots_frame = nr_slots_per_frame[UL_BWP->scs]; + NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; + const int n_slots_frame = nr_slots_per_frame[ul_bwp->scs]; if ((sched_ctrl->rrc_processing_timer > 0) || (sched_ctrl->ul_failure==1 && get_softmodem_params()->phy_test==0)) { continue; } - const NR_CSI_MeasConfig_t *csi_measconfig = UL_BWP->csi_MeasConfig; + const NR_CSI_MeasConfig_t *csi_measconfig = ul_bwp->csi_MeasConfig; if (!csi_measconfig) continue; AssertFatal(csi_measconfig->csi_ReportConfigToAddModList->list.count > 0, "NO CSI report configuration available"); - NR_PUCCH_Config_t *pucch_Config = UL_BWP->pucch_Config; + NR_PUCCH_Config_t *pucch_Config = ul_bwp->pucch_Config; for (int csi_report_id = 0; csi_report_id < csi_measconfig->csi_ReportConfigToAddModList->list.count; csi_report_id++){ NR_CSI_ReportConfig_t *csirep = csi_measconfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; @@ -214,7 +214,7 @@ void nr_csi_meas_reporting(int Mod_idP, curr_pucch->resource_indicator = res_index; curr_pucch->csi_bits += nr_get_csi_bitlen(UE->csi_report_template, csi_report_id); - int bwp_start = UL_BWP->BWPStart; + int bwp_start = ul_bwp->BWPStart; // going through the list of PUCCH resources to find the one indexed by resource_id uint16_t *vrb_map_UL = &RC.nrmac[Mod_idP]->common_channels[0].vrb_map_UL[sched_slot * MAX_BWP_SIZE]; @@ -378,7 +378,7 @@ void tci_handling(NR_UE_info_t *UE, frame_t frame, slot_t slot) { int ssb_index[MAX_NUM_SSB] = {0}; int ssb_rsrp[MAX_NUM_SSB] = {0}; uint8_t idx = 0; - NR_UE_DL_BWP_t *BWP = &UE->current_DL_BWP; + NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; uint8_t nr_ssbri_cri = 0; @@ -388,8 +388,8 @@ void tci_handling(NR_UE_info_t *UE, frame_t frame, slot_t slot) { uint8_t i, j; //bwp indicator - int n_dl_bwp = BWP->n_dl_bwp; - const int bwp_id = BWP->bwp_id; + int n_dl_bwp = dl_bwp->n_dl_bwp; + const int bwp_id = dl_bwp->bwp_id; if (n_dl_bwp < 4) pdsch_bwp_id = bwp_id; else @@ -655,7 +655,6 @@ void evaluate_cqi_report(uint8_t *payload, long *cqi_Table){ NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_DL_BWP_t *BWP = &UE->current_DL_BWP; //TODO sub-band CQI report not yet implemented int cqi_bitlen = csi_report->csi_meas_bitlen.cqi_bitlen[ri]; @@ -679,7 +678,7 @@ void evaluate_cqi_report(uint8_t *payload, // TODO for wideband case and multiple TB const int cqi_idx = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb; - const int mcs_table = BWP->mcsTableIdx; + const int mcs_table = UE->current_DL_BWP.mcsTableIdx; const int cqi_table = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.cqi_table; sched_ctrl->dl_max_mcs = get_mcs_from_cqi(mcs_table, cqi_table, cqi_idx); } @@ -758,8 +757,8 @@ void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig, uint16_t bitlen = uci_pdu->csi_part1.csi_part1_bit_len; NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type = NR_CSI_ReportConfig__reportQuantity_PR_NOTHING; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; - const int n_slots_frame = nr_slots_per_frame[BWP->scs]; + NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; + const int n_slots_frame = nr_slots_per_frame[ul_bwp->scs]; int cumul_bits = 0; int r_index = -1; for (int csi_report_id = 0; csi_report_id < csi_MeasConfig->csi_ReportConfigToAddModList->list.count; csi_report_id++ ) { @@ -1043,8 +1042,8 @@ int nr_acknack_scheduling(int mod_id, const int CC_id = 0; const int minfbtime = RC.nrmac[mod_id]->minRXTXTIMEpdsch; const NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels[CC_id].ServingCellConfigCommon; - const NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; - const int n_slots_frame = nr_slots_per_frame[BWP->scs]; + const NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; + const int n_slots_frame = nr_slots_per_frame[ul_bwp->scs]; const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; AssertFatal(tdd || RC.nrmac[mod_id]->common_channels[CC_id].frame_type == FDD, "Dynamic TDD not handled yet\n"); const int nr_slots_period = tdd ? n_slots_frame / get_nb_periods_per_frame(tdd->dl_UL_TransmissionPeriodicity) : n_slots_frame; @@ -1059,10 +1058,10 @@ int nr_acknack_scheduling(int mod_id, * later) * * each UE has dedicated PUCCH Format 0 resources, and we use index 0! */ NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_PUCCH_Config_t *pucch_Config = BWP->pucch_Config; + NR_PUCCH_Config_t *pucch_Config = ul_bwp->pucch_Config; - int bwp_start = BWP->BWPStart; - int bwp_size = BWP->BWPSize; + int bwp_start = ul_bwp->BWPStart; + int bwp_size = ul_bwp->BWPSize; NR_sched_pucch_t *pucch = &sched_ctrl->sched_pucch[0]; LOG_D(NR_MAC, "In %s: %4d.%2d Trying to allocate pucch, current DAI %d\n", __FUNCTION__, frame, slot, pucch->dai_c); @@ -1308,10 +1307,10 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, sub_frame_t slot) UE_iterator(nrmac->UE_info.list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; - const int n_slots_frame = nr_slots_per_frame[BWP->scs]; + NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; + const int n_slots_frame = nr_slots_per_frame[ul_bwp->scs]; if (sched_ctrl->ul_failure==1 || sched_ctrl->rrc_processing_timer>0) continue; - NR_PUCCH_Config_t *pucch_Config = BWP->pucch_Config; + NR_PUCCH_Config_t *pucch_Config = ul_bwp->pucch_Config; if (!pucch_Config || !pucch_Config->schedulingRequestResourceToAddModList) continue; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 81d2e1e201..27af724c20 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1052,11 +1052,11 @@ void pf_ul(module_id_t module_id, LOG_D(NR_MAC,"pf_ul: preparing UL scheduling for UE %04x\n",UE->rnti); NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_UL_BWP_t *BWP = &UE->current_UL_BWP; + NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP; int rbStart = 0; // wrt BWP start - const uint16_t bwpSize = BWP->BWPSize; + const uint16_t bwpSize = current_BWP->BWPSize; NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; const NR_mac_dir_stats_t *stats = &UE->mac_stats.ul; @@ -1149,7 +1149,7 @@ void pf_ul(module_id_t module_id, const int tda = get_ul_tda(nrmac, scc, sched_pusch->slot); if (ps->time_domain_allocation != tda || ps->nrOfLayers != nrOfLayers) { - nr_set_pusch_semi_static(BWP, + nr_set_pusch_semi_static(current_BWP, scc, tda, nrOfLayers, @@ -1176,7 +1176,7 @@ void pf_ul(module_id_t module_id, NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; sched_pusch->mcs = min(nrmac->min_grant_mcs, sched_pusch->mcs); - update_ul_ue_R_Qm(sched_pusch, BWP->pusch_Config, BWP->mcs_table); + update_ul_ue_R_Qm(sched_pusch, current_BWP->pusch_Config, current_BWP->mcs_table); sched_pusch->rbStart = rbStart; sched_pusch->rbSize = min_rb; sched_pusch->tb_size = nr_compute_tbs(sched_pusch->Qm, @@ -1199,7 +1199,7 @@ void pf_ul(module_id_t module_id, /* Create UE_sched for UEs eligibale for new data transmission*/ /* Calculate coefficient*/ - const uint32_t tbs = ul_pf_tbs[BWP->mcs_table][sched_pusch->mcs]; + const uint32_t tbs = ul_pf_tbs[current_BWP->mcs_table][sched_pusch->mcs]; float coeff_ue = (float) tbs / UE->ul_thr_ue; LOG_D(NR_MAC,"rnti %04x b %d, ul_thr_ue %f, tbs %d, coeff_ue %f\n", UE->rnti, b, UE->ul_thr_ue, tbs, coeff_ue); @@ -1242,9 +1242,9 @@ void pf_ul(module_id_t module_id, } else LOG_D(NR_MAC, "%4d.%2d free CCE for UL DCI UE %04x\n",frame,slot, iterator->UE->rnti); - NR_UE_UL_BWP_t *BWP = &iterator->UE->current_UL_BWP; + NR_UE_UL_BWP_t *current_BWP = &iterator->UE->current_UL_BWP; - const uint16_t bwpSize = BWP->BWPSize; + const uint16_t bwpSize = current_BWP->BWPSize; NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; @@ -1256,13 +1256,13 @@ void pf_ul(module_id_t module_id, const int tda = get_ul_tda(nrmac, scc, sched_pusch->slot); if (ps->time_domain_allocation != tda || ps->nrOfLayers != nrOfLayers) { - nr_set_pusch_semi_static(BWP, + nr_set_pusch_semi_static(current_BWP, scc, tda, nrOfLayers, ps); } - update_ul_ue_R_Qm(sched_pusch, BWP->pusch_Config, BWP->mcs_table); + update_ul_ue_R_Qm(sched_pusch, current_BWP->pusch_Config, current_BWP->mcs_table); int rbStart = 0; const uint16_t slbitmap = SL_to_bitmap(ps->startSymbolIndex, ps->nrOfSymbols); @@ -1341,16 +1341,16 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t * TDAs yet). If the TDA is negative, it means that there is no UL slot to * schedule now (slot + k2 is not UL slot) */ NR_UE_sched_ctrl_t *sched_ctrl = &nr_mac->UE_info.list[0]->UE_sched_ctrl; - NR_UE_UL_BWP_t *BWP = &nr_mac->UE_info.list[0]->current_UL_BWP; - int mu = BWP->scs; + NR_UE_UL_BWP_t *current_BWP = &nr_mac->UE_info.list[0]->current_UL_BWP; + int mu = current_BWP->scs; const int temp_tda = get_ul_tda(nr_mac, scc, slot); - int K2 = get_K2(BWP->tdaList, temp_tda, mu); + int K2 = get_K2(current_BWP->tdaList, temp_tda, mu); const int sched_frame = (frame + (slot + K2 >= nr_slots_per_frame[mu])) & 1023; const int sched_slot = (slot + K2) % nr_slots_per_frame[mu]; const int tda = get_ul_tda(nr_mac, scc, sched_slot); if (tda < 0) return false; - DevAssert(K2 == get_K2(BWP->tdaList, tda, mu)); + DevAssert(K2 == get_K2(current_BWP->tdaList, tda, mu)); if (!is_xlsch_in_slot(nr_mac->ulsch_slot_bitmap[sched_slot / 64], sched_slot)) return false; @@ -1364,7 +1364,7 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t is_xlsch_in_slot(nr_mac->ulsch_slot_bitmap[sched_slot / 64], sched_slot); // FIXME: Avoid mixed slots for initialUplinkBWP - if (BWP->bwp_id==0 && is_mixed_slot) + if (current_BWP->bwp_id==0 && is_mixed_slot) return false; // Avoid slots with the SRS @@ -1379,9 +1379,9 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t sched_ctrl->sched_pusch.frame = sched_frame; UE_iterator(nr_mac->UE_info.list, UE2) { NR_UE_sched_ctrl_t *sched_ctrl = &UE2->UE_sched_ctrl; - AssertFatal(K2 == get_K2(BWP->tdaList, tda, mu), + AssertFatal(K2 == get_K2(current_BWP->tdaList, tda, mu), "Different K2, %d(UE%d) != %ld(UE%04x)\n", - K2, 0, get_K2(BWP->tdaList, tda, mu), UE2->rnti); + K2, 0, get_K2(current_BWP->tdaList, tda, mu), UE2->rnti); sched_ctrl->sched_pusch.slot = sched_slot; sched_ctrl->sched_pusch.frame = sched_frame; } @@ -1392,10 +1392,10 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t uint16_t *vrb_map_UL = &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[sched_slot * MAX_BWP_SIZE]; - const uint16_t bwpSize = BWP->BWPSize; - const uint16_t bwpStart = BWP->BWPStart; + const uint16_t bwpSize = current_BWP->BWPSize; + const uint16_t bwpStart = current_BWP->BWPStart; - const int startSymbolAndLength = BWP->tdaList->list.array[tda]->startSymbolAndLength; + const int startSymbolAndLength = current_BWP->tdaList->list.array[tda]->startSymbolAndLength; int startSymbolIndex, nrOfSymbols; SLIV2SL(startSymbolAndLength, &startSymbolIndex, &nrOfSymbols); const uint16_t symb = SL_to_bitmap(startSymbolIndex, nrOfSymbols); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index b6149e9090..fe5affbf38 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -192,7 +192,7 @@ void config_uldci(const NR_SIB1_t *sib1, dci_pdu_rel15_t *dci_pdu_rel15, int time_domain_assignment, uint8_t tpc, - NR_UE_UL_BWP_t *BWP); + NR_UE_UL_BWP_t *ul_bwp); void nr_schedule_pucch(gNB_MAC_INST *nrmac, frame_t frameP, @@ -285,7 +285,7 @@ void fill_pdcch_vrb_map(gNB_MAC_INST *mac, void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, const NR_CellGroupConfig_t *CellGroup, - const NR_UE_DL_BWP_t *BWP, + const NR_UE_DL_BWP_t *dl_bwp, nfapi_nr_dl_dci_pdu_t *pdcch_dci_pdu, dci_pdu_rel15_t *dci_pdu_rel15, int dci_formats, @@ -296,7 +296,7 @@ void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, uint16_t cset0_bwp_size); void prepare_dci(const NR_CellGroupConfig_t *CellGroup, - const NR_UE_DL_BWP_t *BWP, + const NR_UE_DL_BWP_t *dl_bwp, const NR_ControlResourceSet_t *coreset, dci_pdu_rel15_t *dci_pdu_rel15, nr_dci_format_t format); @@ -325,14 +325,14 @@ long get_K2(NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList, int time_domain_assignment, int mu); -void nr_set_pdsch_semi_static(const NR_UE_DL_BWP_t *BWP, +void nr_set_pdsch_semi_static(const NR_UE_DL_BWP_t *dl_bwp, const NR_ServingCellConfigCommon_t *scc, int tda, uint8_t layers, NR_UE_sched_ctrl_t *sched_ctrl, NR_pdsch_semi_static_t *ps); -void nr_set_pusch_semi_static(const NR_UE_UL_BWP_t *BWP, +void nr_set_pusch_semi_static(const NR_UE_UL_BWP_t *ul_bwp, const NR_ServingCellConfigCommon_t *scc, int tda, uint8_t nrOfLayers, From 6e2a83856b64a5b38c4f4e355d3f22226aa3153e Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 4 Aug 2022 17:19:15 +0200 Subject: [PATCH 249/267] common function to get sample rate and BW --- common/utils/nr/nr_common.c | 230 ++++++++++++++++++++++++++ common/utils/nr/nr_common.h | 7 + executables/nr-ru.c | 228 +------------------------ openair1/SIMULATION/NR_PHY/dlsim.c | 53 ++---- openair1/SIMULATION/NR_PHY/pucchsim.c | 53 ++---- openair1/SIMULATION/NR_PHY/ulsim.c | 45 ++--- 6 files changed, 279 insertions(+), 337 deletions(-) diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index 6add03c324..0fb4824d42 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -472,6 +472,236 @@ int get_subband_size(int NPRB,int size) { } +void get_samplerate_and_bw(int mu, + int n_rb, + int8_t threequarter_fs, + double *sample_rate, + unsigned int *samples_per_frame, + double *tx_bw, + double *rx_bw) { + + if (mu == 0) { + switch(n_rb) { + case 270: + if (threequarter_fs) { + *sample_rate=92.16e6; + *samples_per_frame = 921600; + *tx_bw = 50e6; + *rx_bw = 50e6; + } else { + *sample_rate=61.44e6; + *samples_per_frame = 614400; + *tx_bw = 50e6; + *rx_bw = 50e6; + } + case 216: + if (threequarter_fs) { + *sample_rate=46.08e6; + *samples_per_frame = 460800; + *tx_bw = 40e6; + *rx_bw = 40e6; + } + else { + *sample_rate=61.44e6; + *samples_per_frame = 614400; + *tx_bw = 40e6; + *rx_bw = 40e6; + } + break; + case 160: //30 MHz + case 133: //25 MHz + if (threequarter_fs) { + AssertFatal(1==0,"N_RB %d cannot use 3/4 sampling\n",n_rb); + } + else { + *sample_rate=30.72e6; + *samples_per_frame = 307200; + *tx_bw = 20e6; + *rx_bw = 20e6; + } + case 106: + if (threequarter_fs) { + *sample_rate=23.04e6; + *samples_per_frame = 230400; + *tx_bw = 20e6; + *rx_bw = 20e6; + } + else { + *sample_rate=30.72e6; + *samples_per_frame = 307200; + *tx_bw = 20e6; + *rx_bw = 20e6; + } + break; + case 52: + if (threequarter_fs) { + *sample_rate=11.52e6; + *samples_per_frame = 115200; + *tx_bw = 10e6; + *rx_bw = 10e6; + } + else { + *sample_rate=15.36e6; + *samples_per_frame = 153600; + *tx_bw = 10e6; + *rx_bw = 10e6; + } + case 25: + if (threequarter_fs) { + *sample_rate=5.76e6; + *samples_per_frame = 57600; + *tx_bw = 5e6; + *rx_bw = 5e6; + } + else { + *sample_rate=7.68e6; + *samples_per_frame = 76800; + *tx_bw = 5e6; + *rx_bw = 5e6; + } + break; + default: + AssertFatal(0==1,"N_RB %d not yet supported for numerology %d\n",n_rb,mu); + } + } else if (mu == 1) { + switch(n_rb) { + + case 273: + if (threequarter_fs) { + *sample_rate=184.32e6; + *samples_per_frame = 1843200; + *tx_bw = 100e6; + *rx_bw = 100e6; + } else { + *sample_rate=122.88e6; + *samples_per_frame = 1228800; + *tx_bw = 100e6; + *rx_bw = 100e6; + } + break; + case 217: + if (threequarter_fs) { + *sample_rate=92.16e6; + *samples_per_frame = 921600; + *tx_bw = 80e6; + *rx_bw = 80e6; + } else { + *sample_rate=122.88e6; + *samples_per_frame = 1228800; + *tx_bw = 80e6; + *rx_bw = 80e6; + } + break; + case 162 : + if (threequarter_fs) { + AssertFatal(1==0,"N_RB %d cannot use 3/4 sampling\n",n_rb); + } + else { + *sample_rate=61.44e6; + *samples_per_frame = 614400; + *tx_bw = 60e6; + *rx_bw = 60e6; + } + + break; + + case 133 : + if (threequarter_fs) { + AssertFatal(1==0,"N_RB %d cannot use 3/4 sampling\n",n_rb); + } + else { + *sample_rate=61.44e6; + *samples_per_frame = 614400; + *tx_bw = 50e6; + *rx_bw = 50e6; + } + + break; + case 106: + if (threequarter_fs) { + *sample_rate=46.08e6; + *samples_per_frame = 460800; + *tx_bw = 40e6; + *rx_bw = 40e6; + } + else { + *sample_rate=61.44e6; + *samples_per_frame = 614400; + *tx_bw = 40e6; + *rx_bw = 40e6; + } + break; + case 51: + if (threequarter_fs) { + *sample_rate=23.04e6; + *samples_per_frame = 230400; + *tx_bw = 20e6; + *rx_bw = 20e6; + } + else { + *sample_rate=30.72e6; + *samples_per_frame = 307200; + *tx_bw = 20e6; + *rx_bw = 20e6; + } + break; + case 24: + if (threequarter_fs) { + *sample_rate=11.52e6; + *samples_per_frame = 115200; + *tx_bw = 10e6; + *rx_bw = 10e6; + } + else { + *sample_rate=15.36e6; + *samples_per_frame = 153600; + *tx_bw = 10e6; + *rx_bw = 10e6; + } + break; + default: + AssertFatal(0==1,"N_RB %d not yet supported for numerology %d\n",n_rb,mu); + } + } else if (mu == 3) { + switch(n_rb) { + case 66: + if (threequarter_fs) { + *sample_rate=184.32e6; + *samples_per_frame = 1843200; + *tx_bw = 100e6; + *rx_bw = 100e6; + } else { + *sample_rate = 122.88e6; + *samples_per_frame = 1228800; + *tx_bw = 100e6; + *rx_bw = 100e6; + } + + break; + + case 32: + if (threequarter_fs) { + *sample_rate=92.16e6; + *samples_per_frame = 921600; + *tx_bw = 50e6; + *rx_bw = 50e6; + } else { + *sample_rate=61.44e6; + *samples_per_frame = 614400; + *tx_bw = 50e6; + *rx_bw = 50e6; + } + + break; + + default: + AssertFatal(0==1,"N_RB %d not yet supported for numerology %d\n",n_rb,mu); + } + } else { + AssertFatal(0 == 1,"Numerology %d not supported for the moment\n",mu); + } +} + // from start symbol index and nb or symbols to symbol occupation bitmap in a slot uint16_t SL_to_bitmap(int startSymbolIndex, int nrOfSymbols) { return ((1<ssb_config.scs_common.value; int N_RB = config->carrier_config.dl_grid_size[config->ssb_config.scs_common.value].value; - if (mu == NR_MU_0) { - switch(N_RB) { - case 270: - if (fp->threequarter_fs) { - cfg->sample_rate=92.16e6; - cfg->samples_per_frame = 921600; - cfg->tx_bw = 50e6; - cfg->rx_bw = 50e6; - } else { - cfg->sample_rate=61.44e6; - cfg->samples_per_frame = 614400; - cfg->tx_bw = 50e6; - cfg->rx_bw = 50e6; - } - case 216: - if (fp->threequarter_fs) { - cfg->sample_rate=46.08e6; - cfg->samples_per_frame = 460800; - cfg->tx_bw = 40e6; - cfg->rx_bw = 40e6; - } - else { - cfg->sample_rate=61.44e6; - cfg->samples_per_frame = 614400; - cfg->tx_bw = 40e6; - cfg->rx_bw = 40e6; - } - break; - case 160: //30 MHz - case 133: //25 MHz - if (fp->threequarter_fs) { - AssertFatal(1==0,"N_RB %d cannot use 3/4 sampling\n",N_RB); - } - else { - cfg->sample_rate=30.72e6; - cfg->samples_per_frame = 307200; - cfg->tx_bw = 20e6; - cfg->rx_bw = 20e6; - } - case 106: - if (fp->threequarter_fs) { - cfg->sample_rate=23.04e6; - cfg->samples_per_frame = 230400; - cfg->tx_bw = 20e6; - cfg->rx_bw = 20e6; - } - else { - cfg->sample_rate=30.72e6; - cfg->samples_per_frame = 307200; - cfg->tx_bw = 20e6; - cfg->rx_bw = 20e6; - } - break; - case 52: - if (fp->threequarter_fs) { - cfg->sample_rate=11.52e6; - cfg->samples_per_frame = 115200; - cfg->tx_bw = 10e6; - cfg->rx_bw = 10e6; - } - else { - cfg->sample_rate=15.36e6; - cfg->samples_per_frame = 153600; - cfg->tx_bw = 10e6; - cfg->rx_bw = 10e6; - } - case 25: - if (fp->threequarter_fs) { - cfg->sample_rate=5.76e6; - cfg->samples_per_frame = 57600; - cfg->tx_bw = 5e6; - cfg->rx_bw = 5e6; - } - else { - cfg->sample_rate=7.68e6; - cfg->samples_per_frame = 76800; - cfg->tx_bw = 5e6; - cfg->rx_bw = 5e6; - } - break; - default: - AssertFatal(0==1,"N_RB %d not yet supported for numerology %d\n",N_RB,mu); - } - } else if (mu == NR_MU_1) { - switch(N_RB) { - - case 273: - if (fp->threequarter_fs) { - cfg->sample_rate=184.32e6; - cfg->samples_per_frame = 1843200; - cfg->tx_bw = 100e6; - cfg->rx_bw = 100e6; - } else { - cfg->sample_rate=122.88e6; - cfg->samples_per_frame = 1228800; - cfg->tx_bw = 100e6; - cfg->rx_bw = 100e6; - } - break; - case 217: - if (fp->threequarter_fs) { - cfg->sample_rate=92.16e6; - cfg->samples_per_frame = 921600; - cfg->tx_bw = 80e6; - cfg->rx_bw = 80e6; - } else { - cfg->sample_rate=122.88e6; - cfg->samples_per_frame = 1228800; - cfg->tx_bw = 80e6; - cfg->rx_bw = 80e6; - } - break; - case 162 : - if (fp->threequarter_fs) { - AssertFatal(1==0,"N_RB %d cannot use 3/4 sampling\n",N_RB); - } - else { - cfg->sample_rate=61.44e6; - cfg->samples_per_frame = 614400; - cfg->tx_bw = 60e6; - cfg->rx_bw = 60e6; - } - - break; - - case 133 : - if (fp->threequarter_fs) { - AssertFatal(1==0,"N_RB %d cannot use 3/4 sampling\n",N_RB); - } - else { - cfg->sample_rate=61.44e6; - cfg->samples_per_frame = 614400; - cfg->tx_bw = 50e6; - cfg->rx_bw = 50e6; - } - - break; - case 106: - if (fp->threequarter_fs) { - cfg->sample_rate=46.08e6; - cfg->samples_per_frame = 460800; - cfg->tx_bw = 40e6; - cfg->rx_bw = 40e6; - } - else { - cfg->sample_rate=61.44e6; - cfg->samples_per_frame = 614400; - cfg->tx_bw = 40e6; - cfg->rx_bw = 40e6; - } - break; - case 51: - if (fp->threequarter_fs) { - cfg->sample_rate=23.04e6; - cfg->samples_per_frame = 230400; - cfg->tx_bw = 20e6; - cfg->rx_bw = 20e6; - } - else { - cfg->sample_rate=30.72e6; - cfg->samples_per_frame = 307200; - cfg->tx_bw = 20e6; - cfg->rx_bw = 20e6; - } - break; - case 24: - if (fp->threequarter_fs) { - cfg->sample_rate=11.52e6; - cfg->samples_per_frame = 115200; - cfg->tx_bw = 10e6; - cfg->rx_bw = 10e6; - } - else { - cfg->sample_rate=15.36e6; - cfg->samples_per_frame = 153600; - cfg->tx_bw = 10e6; - cfg->rx_bw = 10e6; - } - break; - default: - AssertFatal(0==1,"N_RB %d not yet supported for numerology %d\n",N_RB,mu); - } - } else if (mu == NR_MU_3) { - switch(N_RB) { - case 66: - if (fp->threequarter_fs) { - cfg->sample_rate=184.32e6; - cfg->samples_per_frame = 1843200; - cfg->tx_bw = 100e6; - cfg->rx_bw = 100e6; - } else { - cfg->sample_rate = 122.88e6; - cfg->samples_per_frame = 1228800; - cfg->tx_bw = 100e6; - cfg->rx_bw = 100e6; - } - - break; - - case 32: - if (fp->threequarter_fs) { - cfg->sample_rate=92.16e6; - cfg->samples_per_frame = 921600; - cfg->tx_bw = 50e6; - cfg->rx_bw = 50e6; - } else { - cfg->sample_rate=61.44e6; - cfg->samples_per_frame = 614400; - cfg->tx_bw = 50e6; - cfg->rx_bw = 50e6; - } - - break; - - default: - AssertFatal(0==1,"N_RB %d not yet supported for numerology %d\n",N_RB,mu); - } - } else { - AssertFatal(0 == 1,"Numerology %d not supported for the moment\n",mu); - } + get_samplerate_and_bw(mu, + N_RB, + fp->threequarter_fs, + &cfg->sample_rate, + &cfg->samples_per_frame, + &cfg->tx_bw, + &cfg->rx_bw); if (config->cell_config.frame_duplex_type.value==TDD) cfg->duplex_mode = duplex_mode_TDD; diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 57c6589ca4..b62559ecfa 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -887,55 +887,22 @@ int main(int argc, char **argv) if (g_rbStart < 0) g_rbStart=0; if (g_rbSize < 0) g_rbSize = N_RB_DL - g_rbStart; - double fs,bw; + double fs,txbw,rxbw; + uint32_t samples; - if (mu == 0 && N_RB_DL == 25) { - fs = 7.68e6; - bw = 5e6; - } - else if (mu == 1 && N_RB_DL == 217) { - fs = 122.88e6; - bw = 80e6; - } - else if (mu == 1 && N_RB_DL == 245) { - fs = 122.88e6; - bw = 90e6; - } - else if (mu == 1 && N_RB_DL == 273) { - fs = 122.88e6; - bw = 100e6; - } - else if (mu == 1 && N_RB_DL == 106) { - fs = 61.44e6; - bw = 40e6; - } - else if (mu == 1 && N_RB_DL == 133) { - fs = 61.44e6; - bw = 50e6; - } - else if (mu == 1 && N_RB_DL == 162) { - fs = 61.44e6; - bw = 60e6; - } - else if (mu == 1 && N_RB_DL == 24) { - fs = 15.36e6; - bw = 10e6; - } - else if (mu == 3 && N_RB_DL == 66) { - fs = 122.88e6; - bw = 100e6; - } - else if (mu == 3 && N_RB_DL == 32) { - fs = 61.44e6; - bw = 50e6; - } - else AssertFatal(1==0,"Unsupported numerology for mu %d, N_RB %d\n",mu, N_RB_DL); + get_samplerate_and_bw(mu, + N_RB_DL, + frame_parms->threequarter_fs, + &fs, + &samples, + &txbw, + &rxbw); gNB2UE = new_channel_desc_scm(n_tx, n_rx, channel_model, fs/1e6,//sampling frequency in MHz - bw, + txbw, 30e-9, 0, 0, diff --git a/openair1/SIMULATION/NR_PHY/pucchsim.c b/openair1/SIMULATION/NR_PHY/pucchsim.c index 80a638db73..728023c246 100644 --- a/openair1/SIMULATION/NR_PHY/pucchsim.c +++ b/openair1/SIMULATION/NR_PHY/pucchsim.c @@ -27,6 +27,7 @@ #include #include "common/config/config_userapi.h" #include "common/utils/load_module_shlib.h" +#include "common/utils/nr/nr_common.h" #include "common/utils/LOG/log.h" #include "common/ran_context.h" #include "PHY/types.h" @@ -390,45 +391,18 @@ int main(int argc, char **argv) nr_phy_config_request_sim(gNB,N_RB_DL,N_RB_DL,mu,Nid_cell,SSB_positions); phy_init_nr_gNB(gNB,0,0); - double fs,bw,scs,eps; + double fs,txbw,rxbw; + uint32_t samples; - if (mu == 1 && N_RB_DL == 217) { - fs = 122.88e6; - bw = 80e6; - scs = 30000; - } - else if (mu == 1 && N_RB_DL == 245) { - fs = 122.88e6; - bw = 90e6; - scs = 30000; - } - else if (mu == 1 && N_RB_DL == 273) { - fs = 122.88e6; - bw = 100e6; - scs = 30000; - } - else if (mu == 1 && N_RB_DL == 106) { - fs = 61.44e6; - bw = 40e6; - scs = 30000; - } - else AssertFatal(1==0,"Unsupported numerology for mu %d, N_RB %d\n",mu, N_RB_DL); + get_samplerate_and_bw(mu, + N_RB_DL, + frame_parms->threequarter_fs, + &fs, + &samples, + &txbw, + &rxbw); - // cfo with respect to sub-carrier spacing - eps = cfo/scs; - - // computation of integer and fractional FO to compare with estimation results - int IFO; - if(eps!=0.0){ - printf("Introducing a CFO of %lf relative to SCS of %d kHz\n",eps,(int)(scs/1000)); - if (eps>0) - IFO=(int)(eps+0.5); - else - IFO=(int)(eps-0.5); - printf("FFO = %lf; IFO = %d\n",eps-IFO,IFO); - } - - UE2gNB = new_channel_desc_scm(n_tx, n_rx, channel_model, fs, bw, DS_TDL,0, 0, 0, 0); + UE2gNB = new_channel_desc_scm(n_tx, n_rx, channel_model, fs, txbw, DS_TDL,0, 0, 0, 0); if (UE2gNB==NULL) { printf("Problem generating channel model. Exiting.\n"); @@ -477,9 +451,6 @@ int main(int argc, char **argv) memcpy(&UE->frame_parms,frame_parms,sizeof(NR_DL_FRAME_PARMS)); UE->frame_parms.nb_antennas_rx=1; - if(eps!=0.0) - UE->UE_fo_compensation = 1; // if a frequency offset is set then perform fo estimation and compensation - if (init_nr_ue_signal(UE, 1) != 0) { printf("Error at UE NR initialisation\n"); @@ -568,7 +539,7 @@ int main(int argc, char **argv) } random_channel(UE2gNB,0); - freq_channel(UE2gNB,N_RB_DL,2*N_RB_DL+1,scs/1000); + freq_channel(UE2gNB,N_RB_DL,2*N_RB_DL+1,15<frame_parms.ofdm_symbol_size; for (int re=0;re Date: Thu, 4 Aug 2022 17:46:18 +0200 Subject: [PATCH 250/267] adding an assertion in configure_UE_BWP --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 497546184f..a737e66c40 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2181,6 +2181,8 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, NR_RA_t *ra, NR_UE_info_t *UE) { + AssertFatal((ra != NULL && UE == NULL) || (ra == NULL && UE != NULL), "RA and UE structures are mutually exlusive in BWP configuration\n"); + NR_CellGroupConfig_t *CellGroup; NR_UE_DL_BWP_t *DL_BWP; NR_UE_UL_BWP_t *UL_BWP; From ddc6df0bf45d74c88063c95276e59203ba80d02f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Aug 2022 18:51:02 +0200 Subject: [PATCH 251/267] Remove files accidentally added in MR 1382 --- ...384_rate_1-3_block_length_8448_maxit_5.txt | 64 - rxsigF0.m | 57345 --------------- txsig0.m | 61441 ---------------- 3 files changed, 118850 deletions(-) delete mode 100644 ldpctest_BG_1_Zc_384_rate_1-3_block_length_8448_maxit_5.txt delete mode 100644 rxsigF0.m delete mode 100644 txsig0.m diff --git a/ldpctest_BG_1_Zc_384_rate_1-3_block_length_8448_maxit_5.txt b/ldpctest_BG_1_Zc_384_rate_1-3_block_length_8448_maxit_5.txt deleted file mode 100644 index 2983268dac..0000000000 --- a/ldpctest_BG_1_Zc_384_rate_1-3_block_length_8448_maxit_5.txt +++ /dev/null @@ -1,64 +0,0 @@ -SNR BLER BER UNCODED_BER ENCODER_MEAN ENCODER_STD ENCODER_MAX DECODER_TIME_MEAN DECODER_TIME_STD DECODER_TIME_MAX DECODER_ITER_MEAN DECODER_ITER_STD DECODER_ITER_MAX --2.000000 1.000000 0.346185 0.258473 44.551218 31.688925 357.883903 217.655668 12.810778 326.852166 5.000000 0.000000 5 --1.900000 1.000000 0.345395 0.256275 40.787109 4.190954 65.926488 215.687102 4.300128 230.585721 5.000000 0.000000 5 --1.800000 1.000000 0.343100 0.253634 40.748628 3.912915 56.669470 215.314020 4.139156 227.806468 5.000000 0.000000 5 --1.700000 1.000000 0.341806 0.250634 40.550845 3.347808 56.032851 216.839001 5.959734 244.483352 5.000000 0.000000 5 --1.600000 1.000000 0.339245 0.248129 40.457158 3.735092 56.853508 215.747244 4.995522 242.867659 5.000000 0.000000 5 --1.500000 1.000000 0.337230 0.245763 41.178595 4.297429 56.265874 215.785600 4.151781 227.795995 5.000000 0.000000 5 --1.400000 1.000000 0.335131 0.243311 39.915221 2.739586 55.454917 216.866764 6.547848 251.528327 5.000000 0.000000 5 --1.300000 1.000000 0.333085 0.240664 40.119215 3.044973 55.978253 216.208443 4.459816 228.810686 5.000000 0.000000 5 --1.200000 1.000000 0.330664 0.238769 40.507713 2.998241 55.701876 215.868796 3.778455 226.049304 5.000000 0.000000 5 --1.100000 1.000000 0.329130 0.235812 41.038895 4.522472 56.760814 215.654663 4.746822 236.021980 5.000000 0.000000 5 --1.000000 1.000000 0.325980 0.233534 41.067622 4.626711 57.444142 215.260535 3.481966 225.512853 5.000000 0.000000 5 --0.900000 1.000000 0.323823 0.230863 40.683316 3.689159 56.208182 215.560917 5.180017 243.603452 5.000000 0.000000 5 --0.800000 1.000000 0.321004 0.228222 41.643513 4.717568 58.502452 215.630891 4.283475 238.574145 5.000000 0.000000 5 --0.700000 1.000000 0.317983 0.225520 41.214547 3.941824 56.054211 215.910346 4.375081 227.444626 5.000000 0.000000 5 --0.600000 1.000000 0.316243 0.222903 40.834442 4.370416 56.765508 215.153296 3.617927 226.280086 5.000000 0.000000 5 --0.500000 1.000000 0.312886 0.220473 40.178174 4.185502 64.657291 219.647151 4.454154 236.473446 5.000000 0.000000 5 --0.400000 1.000000 0.309757 0.217536 40.240385 3.172484 55.751563 217.761119 3.900779 228.757195 5.000000 0.000000 5 --0.300000 1.000000 0.305464 0.215229 40.852271 3.761739 56.158869 217.830497 4.087453 230.237764 5.000000 0.000000 5 --0.200000 1.000000 0.302919 0.212364 40.531166 3.688281 56.426841 217.657657 5.498697 253.516146 5.000000 0.000000 5 --0.100000 1.000000 0.298246 0.209310 41.058364 4.140510 59.959571 217.519279 4.087389 228.768313 5.000000 0.000000 5 -0.000000 1.000000 0.294110 0.207107 40.436486 3.604369 55.788895 217.853044 4.012624 236.118036 5.000000 0.000000 5 -0.100000 1.000000 0.288139 0.204033 40.603738 4.045866 57.560760 217.046816 4.583841 244.429411 5.000000 0.000000 5 -0.200000 1.000000 0.285604 0.201954 40.494607 3.886199 59.431970 217.322824 4.080988 233.317513 5.000000 0.000000 5 -0.300000 1.000000 0.278478 0.198929 40.311327 3.452837 56.124657 217.319394 4.434358 232.534720 5.000000 0.000000 5 -0.400000 1.000000 0.270992 0.196299 40.649243 3.415612 56.204178 218.079445 4.990947 245.055337 5.000000 0.000000 5 -0.500000 1.000000 0.263944 0.193661 40.464299 3.622703 56.602842 218.555364 3.936432 229.481159 5.000000 0.000000 5 -0.600000 1.000000 0.256340 0.191194 40.200314 2.474984 53.432412 216.547260 3.695211 227.198078 5.000000 0.000000 5 -0.700000 1.000000 0.251578 0.188606 40.111945 3.029821 54.900896 216.581752 4.247622 237.358365 5.000000 0.000000 5 -0.800000 1.000000 0.234558 0.184742 39.533282 1.182169 42.753097 215.462335 2.960246 226.716604 5.000000 0.000000 5 -0.900000 1.000000 0.225915 0.182691 39.851294 1.108193 42.180342 216.404194 4.450720 228.482353 5.000000 0.000000 5 -1.000000 1.000000 0.216180 0.179994 40.721936 3.302539 56.032206 217.082196 4.599188 227.979232 5.000000 0.000000 5 -1.100000 1.000000 0.203481 0.177332 41.006217 3.798207 56.014901 216.204345 4.292145 227.297386 5.000000 0.000000 5 -1.200000 1.000000 0.188297 0.174121 40.739289 3.269948 56.653507 216.585873 6.250858 251.207034 5.000000 0.000000 5 -1.300000 1.000000 0.172624 0.171622 41.215540 4.783342 55.692883 215.885639 3.629370 226.473280 5.000000 0.000000 5 -1.400000 1.000000 0.156483 0.169110 40.289903 3.749338 56.290861 215.663761 4.176366 225.824735 5.000000 0.000000 5 -1.500000 1.000000 0.136293 0.165692 42.208932 6.070189 69.182665 216.390504 4.816283 235.417446 5.000000 0.000000 5 -1.600000 1.000000 0.125127 0.163325 40.890581 3.941185 56.491504 215.752348 4.426511 226.425984 5.000000 0.000000 5 -1.700000 1.000000 0.104593 0.159971 41.263557 4.128935 57.062514 217.284932 5.311288 249.647163 5.000000 0.000000 5 -1.800000 1.000000 0.091397 0.157460 40.273078 3.062810 55.546913 217.252505 6.331426 251.175692 5.000000 0.000000 5 -1.900000 1.000000 0.078256 0.154628 40.407489 3.419342 56.316166 216.967648 4.712664 245.093313 5.000000 0.000000 5 -2.000000 1.000000 0.065221 0.152571 40.660365 4.317854 57.537407 216.198346 4.991856 245.173269 5.000000 0.000000 5 -2.100000 1.000000 0.053694 0.148885 40.355654 4.062614 60.051963 215.797667 4.447252 236.221454 5.000000 0.000000 5 -2.200000 1.000000 0.042182 0.146229 40.613562 4.124655 56.201536 216.117304 4.060825 227.115987 5.000000 0.000000 5 -2.300000 1.000000 0.034334 0.143612 40.465884 3.541452 55.067611 215.575953 4.891719 244.546802 5.000000 0.000000 5 -2.400000 1.000000 0.026641 0.140869 41.074690 4.697458 61.619188 216.069185 4.700827 233.830937 5.000000 0.000000 5 -2.500000 1.000000 0.019976 0.138112 40.766971 4.274128 58.871741 215.761570 5.633731 249.753931 5.000000 0.000000 5 -2.600000 1.000000 0.012826 0.135122 40.559343 2.952804 54.017706 215.835161 4.039993 226.822103 5.000000 0.000000 5 -2.700000 1.000000 0.010550 0.132915 40.985193 3.330639 55.013950 215.975836 4.240744 227.040703 5.000000 0.000000 5 -2.800000 1.000000 0.007327 0.130133 39.778804 3.002485 56.610555 216.462786 7.082268 265.051418 5.000000 0.000000 5 -2.900000 1.000000 0.004038 0.126763 40.327795 3.934211 55.515352 215.982666 4.626198 230.696124 5.000000 0.000000 5 -3.000000 1.000000 0.003087 0.124336 40.337807 3.537021 55.101627 215.468662 4.177203 230.789145 5.000000 0.000000 5 -3.100000 1.000000 0.001576 0.121689 39.812195 3.116738 55.422687 215.797778 4.091192 225.897780 5.000000 0.000000 5 -3.200000 0.980000 0.001000 0.118928 39.853764 2.871322 56.405555 215.562722 4.187466 232.598421 5.000000 0.000000 5 -3.300000 0.960000 0.000623 0.116065 40.440328 3.580650 56.738889 216.165848 4.735158 240.329999 5.000000 0.000000 5 -3.400000 0.850000 0.000303 0.113505 40.974107 4.291544 56.280236 215.889562 4.448049 237.556780 5.000000 0.000000 5 -3.500000 0.690000 0.000152 0.111010 41.508631 4.251791 56.198873 216.740295 4.889693 242.922934 5.000000 0.000000 5 -3.600000 0.530000 0.000102 0.108493 40.065231 3.643794 57.120823 216.887338 5.242621 250.003843 5.000000 0.000000 5 -3.700000 0.320000 0.000043 0.105612 40.462159 4.162383 56.782173 216.465615 3.846314 227.022697 5.000000 0.000000 5 -3.800000 0.210000 0.000032 0.103084 42.192455 6.207380 64.648964 217.030913 4.482820 228.095918 5.000000 0.000000 5 -3.900000 0.110000 0.000013 0.100391 40.640286 3.715782 55.922914 217.726055 4.553212 236.362804 5.000000 0.000000 5 -4.000000 0.050000 0.000006 0.097518 40.437760 2.838308 54.764308 218.230040 4.309275 237.932625 5.000000 0.000000 5 -4.100000 0.020000 0.000002 0.095436 41.347934 4.608500 64.182062 217.408836 4.385757 228.219627 5.000000 0.000000 5 -4.200000 0.000000 0.000000 0.092396 40.782371 3.621708 55.984245 217.579878 4.102149 228.145363 5.000000 0.000000 5 diff --git a/rxsigF0.m b/rxsigF0.m deleted file mode 100644 index 3309e1aa6f..0000000000 --- a/rxsigF0.m +++ /dev/null @@ -1,57345 +0,0 @@ -rxsF0 = [173 + j*(-306) --141 + j*(-130) --166 + j*(-246) --107 + j*(-42) --105 + j*(0) --179 + j*(-28) --87 + j*(186) --95 + j*(151) --1 + j*(228) -172 + j*(-62) -110 + j*(-5) --178 + j*(-33) --18 + j*(57) -9 + j*(146) --11 + j*(103) --67 + j*(64) -28 + j*(-375) --72 + j*(-75) --14 + j*(-318) -194 + j*(193) --173 + j*(-228) -295 + j*(119) -203 + j*(-179) --238 + j*(-276) --286 + j*(112) --409 + j*(95) --260 + j*(84) -72 + j*(40) -105 + j*(-120) -57 + j*(66) -58 + j*(173) --170 + j*(-189) -192 + j*(-50) --88 + j*(160) --187 + j*(-132) -120 + j*(41) -239 + j*(-115) -80 + j*(263) --45 + j*(-30) -396 + j*(192) -161 + j*(-11) --325 + j*(296) --64 + j*(-192) --181 + j*(-59) --272 + j*(192) -11 + j*(192) --215 + j*(50) -122 + j*(177) --255 + j*(26) -87 + j*(11) --86 + j*(-129) --199 + j*(199) --238 + j*(163) -29 + j*(134) -175 + j*(81) -30 + j*(-214) --344 + j*(131) -124 + j*(-252) -134 + j*(-325) -224 + j*(-78) -223 + j*(-190) --15 + j*(88) --223 + j*(128) --48 + j*(-223) --109 + j*(-209) --17 + j*(-84) -179 + j*(73) --25 + j*(-81) -6 + j*(88) -8 + j*(83) --75 + j*(38) --119 + j*(51) -15 + j*(199) -140 + j*(42) -44 + j*(-132) --247 + j*(118) -242 + j*(-82) -140 + j*(-258) --98 + j*(28) -262 + j*(107) --141 + j*(-21) -137 + j*(382) -64 + j*(-163) --81 + j*(62) -54 + j*(245) --132 + j*(75) -196 + j*(-219) --146 + j*(211) --64 + j*(64) --146 + j*(-37) --37 + j*(-94) --318 + j*(160) --237 + j*(112) --98 + j*(2) --286 + j*(209) --69 + j*(192) --52 + j*(105) --63 + j*(-35) -119 + j*(59) --19 + j*(-25) -110 + j*(54) -45 + j*(-37) -42 + j*(-107) -57 + j*(74) -190 + j*(105) -246 + j*(20) -233 + j*(93) -290 + j*(180) -232 + j*(-113) -281 + j*(243) -280 + j*(-250) -47 + j*(-245) -144 + j*(-150) --272 + j*(25) --94 + j*(163) --135 + j*(-334) -16 + j*(-211) --165 + j*(214) -88 + j*(34) -27 + j*(-36) --161 + j*(-243) -94 + j*(151) -112 + j*(-66) --180 + j*(48) --77 + j*(-64) --293 + j*(300) --42 + j*(-139) --177 + j*(91) --37 + j*(-39) --88 + j*(216) --123 + j*(1) -141 + j*(-250) -100 + j*(-148) --11 + j*(265) -30 + j*(-212) --9 + j*(146) -281 + j*(223) --166 + j*(141) --7 + j*(-51) -69 + j*(-37) --91 + j*(45) -198 + j*(-225) -560 + j*(-64) --245 + j*(-145) -194 + j*(231) --96 + j*(216) -8 + j*(-158) -117 + j*(42) --42 + j*(132) -97 + j*(178) --182 + j*(-65) --59 + j*(118) -129 + j*(-45) -75 + j*(-6) --88 + j*(20) --425 + j*(35) -140 + j*(424) --40 + j*(116) -27 + j*(-297) -123 + j*(230) -86 + j*(-293) -104 + j*(-127) -47 + j*(-89) -60 + j*(97) --23 + j*(197) --7 + j*(-93) -115 + j*(205) -271 + j*(-159) --56 + j*(159) --57 + j*(556) --48 + j*(-196) --71 + j*(-63) --353 + j*(-221) --84 + j*(-173) -30 + j*(45) --302 + j*(371) -354 + j*(-22) --233 + j*(35) --308 + j*(-202) --433 + j*(-44) --158 + j*(73) -185 + j*(-150) -48 + j*(124) --7 + j*(168) -190 + j*(78) -211 + j*(-9) --71 + j*(-193) --119 + j*(97) --234 + j*(-197) -341 + j*(-197) --346 + j*(74) -105 + j*(17) -57 + j*(-105) --161 + j*(-138) --180 + j*(180) --156 + j*(91) --9 + j*(-139) --87 + j*(165) --64 + j*(-238) -15 + j*(-221) --113 + j*(8) --331 + j*(59) -90 + j*(-150) --136 + j*(-325) -73 + j*(178) --18 + j*(170) -67 + j*(-96) -85 + j*(-37) --9 + j*(-114) --22 + j*(136) --175 + j*(165) --87 + j*(-25) --31 + j*(-152) --301 + j*(-18) -42 + j*(-54) --32 + j*(-168) --74 + j*(163) --54 + j*(-52) --76 + j*(-21) -67 + j*(73) -129 + j*(-255) --270 + j*(203) --112 + j*(-71) --106 + j*(13) -175 + j*(-194) -6 + j*(110) -115 + j*(135) --22 + j*(-50) -143 + j*(220) --17 + j*(-82) --65 + j*(204) --46 + j*(-112) -86 + j*(-199) -3 + j*(-52) -88 + j*(116) -184 + j*(227) --65 + j*(189) --54 + j*(-150) -139 + j*(206) -122 + j*(72) --71 + j*(194) --134 + j*(287) -44 + j*(-124) -13 + j*(-250) --100 + j*(95) --110 + j*(16) -233 + j*(-139) -228 + j*(-39) --252 + j*(133) --122 + j*(-129) -21 + j*(-143) --55 + j*(-144) --199 + j*(14) -110 + j*(-195) -85 + j*(-45) --243 + j*(-35) -59 + j*(-86) --361 + j*(179) -69 + j*(34) --22 + j*(42) --267 + j*(-294) -28 + j*(-84) -40 + j*(-247) --112 + j*(128) -54 + j*(182) -71 + j*(-33) --40 + j*(448) --75 + j*(-132) -10 + j*(-37) -272 + j*(-126) --209 + j*(-100) --98 + j*(58) -72 + j*(391) -25 + j*(21) --126 + j*(-110) --238 + j*(138) -227 + j*(-283) -64 + j*(-523) --42 + j*(392) -103 + j*(-288) --131 + j*(-207) -88 + j*(3) --81 + j*(382) --4 + j*(119) -177 + j*(-137) --95 + j*(228) -39 + j*(-127) --265 + j*(202) -145 + j*(66) --358 + j*(127) --320 + j*(-144) --48 + j*(-260) -119 + j*(37) --359 + j*(49) -257 + j*(-112) -112 + j*(84) -30 + j*(171) -136 + j*(-186) --250 + j*(-115) --274 + j*(-281) --37 + j*(1) -69 + j*(130) --125 + j*(-184) --315 + j*(-75) --93 + j*(104) -64 + j*(-6) -198 + j*(141) --88 + j*(18) -248 + j*(-57) --107 + j*(74) --71 + j*(26) --90 + j*(-21) --282 + j*(-201) -57 + j*(47) --15 + j*(33) --144 + j*(153) --202 + j*(-221) --124 + j*(-175) --146 + j*(-276) --74 + j*(39) --91 + j*(512) -125 + j*(213) -139 + j*(168) --233 + j*(-91) -60 + j*(-132) --36 + j*(-132) -21 + j*(105) --129 + j*(231) --283 + j*(191) -320 + j*(134) --171 + j*(70) --133 + j*(66) -189 + j*(47) -188 + j*(-88) --16 + j*(263) --44 + j*(4) -93 + j*(-2) -33 + j*(2) -30 + j*(211) --114 + j*(-76) -54 + j*(12) --128 + j*(-8) --23 + j*(265) --235 + j*(224) --56 + j*(260) -30 + j*(106) --150 + j*(-223) --37 + j*(-291) --175 + j*(177) --165 + j*(259) --206 + j*(63) -131 + j*(-61) --43 + j*(-186) --90 + j*(14) -79 + j*(-190) --127 + j*(115) -48 + j*(28) --5 + j*(17) --28 + j*(47) -163 + j*(135) -44 + j*(-125) --86 + j*(275) -1 + j*(117) -49 + j*(-62) -147 + j*(80) -85 + j*(84) --31 + j*(-101) -243 + j*(150) --181 + j*(-219) --138 + j*(-10) --214 + j*(-151) -27 + j*(-88) -211 + j*(86) --162 + j*(-350) --455 + j*(77) -237 + j*(30) -18 + j*(189) --131 + j*(119) -18 + j*(96) -85 + j*(78) -182 + j*(155) -6 + j*(250) -195 + j*(-153) --74 + j*(-51) -44 + j*(-60) --234 + j*(221) -359 + j*(-139) --228 + j*(291) --28 + j*(173) --147 + j*(-59) --357 + j*(100) --86 + j*(464) --113 + j*(-74) --282 + j*(356) -16 + j*(-52) -204 + j*(-316) -258 + j*(178) --75 + j*(100) --113 + j*(83) -158 + j*(309) -65 + j*(-170) -91 + j*(-125) --151 + j*(318) --52 + j*(-18) --138 + j*(176) --226 + j*(30) --177 + j*(39) --150 + j*(-13) -35 + j*(-183) -204 + j*(-308) -186 + j*(-243) --115 + j*(-71) -66 + j*(55) --88 + j*(-128) --109 + j*(195) --244 + j*(-90) -175 + j*(-177) -231 + j*(-194) --59 + j*(101) -23 + j*(-8) --117 + j*(209) --16 + j*(-97) -4 + j*(190) --28 + j*(-67) --94 + j*(3) --54 + j*(-21) --27 + j*(83) --127 + j*(-21) -187 + j*(-289) -3 + j*(-82) --1 + j*(-223) --168 + j*(232) --148 + j*(163) -274 + j*(-324) --156 + j*(-82) -384 + j*(162) --91 + j*(94) --37 + j*(10) --66 + j*(330) --85 + j*(-8) -62 + j*(216) --98 + j*(95) -126 + j*(189) -196 + j*(-243) -81 + j*(-42) --250 + j*(-2) -118 + j*(146) --1 + j*(-98) -88 + j*(-234) --151 + j*(25) -175 + j*(235) -36 + j*(-182) --108 + j*(69) -105 + j*(-38) --175 + j*(-36) --327 + j*(-45) -80 + j*(268) -13 + j*(-43) --87 + j*(57) --70 + j*(-112) -192 + j*(71) --369 + j*(-114) -224 + j*(341) --144 + j*(-145) -262 + j*(105) --91 + j*(-185) --6 + j*(116) --344 + j*(-245) -90 + j*(-101) -147 + j*(-123) --76 + j*(-71) -6 + j*(197) --44 + j*(-130) -21 + j*(-84) -448 + j*(74) -175 + j*(-3) --175 + j*(-156) --18 + j*(-110) --95 + j*(-250) --107 + j*(172) --110 + j*(157) -132 + j*(6) -47 + j*(146) -212 + j*(-167) -95 + j*(40) --239 + j*(-44) -97 + j*(134) --104 + j*(-193) --363 + j*(-244) -86 + j*(-1) -72 + j*(-13) -62 + j*(157) -214 + j*(-103) --161 + j*(-3) --252 + j*(-139) -147 + j*(39) -30 + j*(-73) --100 + j*(-203) -159 + j*(-250) --323 + j*(-118) --35 + j*(-88) --76 + j*(-105) --24 + j*(28) --194 + j*(-233) --272 + j*(23) --204 + j*(89) --83 + j*(-110) --88 + j*(110) -254 + j*(-103) -32 + j*(136) -92 + j*(-226) --92 + j*(-203) --136 + j*(94) --283 + j*(-192) -161 + j*(272) --102 + j*(30) -71 + j*(-71) -158 + j*(58) --71 + j*(-139) -220 + j*(-131) -225 + j*(-135) --222 + j*(332) --296 + j*(-165) --156 + j*(-104) --216 + j*(164) -305 + j*(-68) --102 + j*(47) --25 + j*(66) -28 + j*(250) -120 + j*(-64) --120 + j*(-134) --42 + j*(114) -18 + j*(32) --83 + j*(157) -115 + j*(-25) --247 + j*(-110) --53 + j*(206) -170 + j*(-30) --86 + j*(100) -384 + j*(119) --332 + j*(-5) --37 + j*(163) -74 + j*(285) -139 + j*(-320) --286 + j*(18) -21 + j*(313) -125 + j*(50) --30 + j*(530) -153 + j*(24) -115 + j*(-141) --392 + j*(-131) -194 + j*(-179) -167 + j*(211) -161 + j*(133) -101 + j*(-263) --185 + j*(-81) --6 + j*(240) -257 + j*(71) --30 + j*(68) --143 + j*(29) -124 + j*(154) -296 + j*(-67) -360 + j*(-25) -187 + j*(-21) --70 + j*(409) --95 + j*(39) -53 + j*(161) --158 + j*(64) --141 + j*(112) -414 + j*(-13) --153 + j*(-59) --189 + j*(-54) --69 + j*(19) -1 + j*(-12) -191 + j*(192) --133 + j*(-95) --245 + j*(232) -86 + j*(-66) --173 + j*(129) -63 + j*(131) --348 + j*(-260) -143 + j*(-136) --97 + j*(-107) -135 + j*(58) -184 + j*(-80) --7 + j*(363) --285 + j*(-198) --103 + j*(290) -134 + j*(87) --22 + j*(-163) -66 + j*(-226) -182 + j*(54) --204 + j*(-52) --194 + j*(161) --63 + j*(-117) -61 + j*(98) -49 + j*(-33) --152 + j*(40) -177 + j*(-91) -22 + j*(-106) -89 + j*(-54) -37 + j*(-148) -286 + j*(-67) --114 + j*(69) -13 + j*(127) --218 + j*(-8) --154 + j*(19) -73 + j*(138) --132 + j*(16) -185 + j*(117) --136 + j*(351) --121 + j*(98) -184 + j*(-65) -187 + j*(51) -119 + j*(68) --85 + j*(-50) -145 + j*(-25) --8 + j*(61) -137 + j*(325) --124 + j*(-22) -326 + j*(-175) --25 + j*(86) -279 + j*(-95) -8 + j*(159) --4 + j*(186) -390 + j*(-138) --162 + j*(-42) --28 + j*(114) -153 + j*(44) -340 + j*(-112) --300 + j*(-58) --86 + j*(-173) -267 + j*(-119) -209 + j*(74) --279 + j*(105) --37 + j*(-37) --59 + j*(80) --148 + j*(-163) -81 + j*(-156) --163 + j*(80) --73 + j*(378) --189 + j*(190) --35 + j*(-102) --49 + j*(-172) --177 + j*(-221) --4 + j*(215) --297 + j*(1) --94 + j*(-299) -129 + j*(-374) --38 + j*(-16) --21 + j*(-97) --215 + j*(-75) -147 + j*(111) --173 + j*(-72) -92 + j*(-138) -110 + j*(132) -28 + j*(16) --143 + j*(-182) --109 + j*(325) --30 + j*(128) --200 + j*(-168) --148 + j*(-261) -132 + j*(-63) --30 + j*(-14) --238 + j*(-55) --67 + j*(26) --214 + j*(1) --180 + j*(-286) --147 + j*(-66) -205 + j*(41) -152 + j*(-89) -35 + j*(148) --112 + j*(38) -156 + j*(-81) --177 + j*(104) --194 + j*(307) --46 + j*(-199) --290 + j*(35) --170 + j*(28) --23 + j*(214) --78 + j*(-90) --52 + j*(249) --140 + j*(-72) -175 + j*(-34) -103 + j*(115) -266 + j*(-186) -70 + j*(-192) --204 + j*(94) -18 + j*(287) --173 + j*(289) -136 + j*(216) --98 + j*(164) --37 + j*(185) --147 + j*(59) --105 + j*(-132) -51 + j*(139) -68 + j*(165) --330 + j*(-124) --30 + j*(-76) -5 + j*(-193) -209 + j*(-233) -63 + j*(117) --260 + j*(-180) --34 + j*(182) -40 + j*(-52) -97 + j*(-188) --62 + j*(-71) --13 + j*(-250) --15 + j*(234) -243 + j*(-193) -26 + j*(-392) --129 + j*(69) --143 + j*(-115) --108 + j*(56) --52 + j*(282) --7 + j*(-90) -37 + j*(-105) --615 + j*(-199) --74 + j*(85) --322 + j*(-64) -69 + j*(-165) --70 + j*(101) -29 + j*(92) --150 + j*(-327) -54 + j*(89) --398 + j*(186) --102 + j*(-121) --269 + j*(-71) -52 + j*(-62) -170 + j*(-125) -6 + j*(-69) --76 + j*(-327) -35 + j*(139) --3 + j*(-87) --322 + j*(167) -4 + j*(-26) -184 + j*(160) --178 + j*(-75) -109 + j*(62) -50 + j*(54) --64 + j*(-115) --371 + j*(-247) --124 + j*(-45) --211 + j*(-123) -153 + j*(86) --222 + j*(-161) --163 + j*(-173) --17 + j*(263) -171 + j*(27) -287 + j*(105) -31 + j*(-233) --8 + j*(-81) -37 + j*(120) --8 + j*(21) -3 + j*(-138) -95 + j*(202) -511 + j*(81) --117 + j*(-196) -35 + j*(28) --136 + j*(-301) -182 + j*(-140) --60 + j*(-66) --206 + j*(-111) -231 + j*(27) -48 + j*(49) -206 + j*(315) -86 + j*(93) -131 + j*(-232) --161 + j*(6) -22 + j*(306) --307 + j*(-81) --170 + j*(87) -173 + j*(1) --286 + j*(-155) --278 + j*(-192) -10 + j*(-42) --153 + j*(202) -377 + j*(35) -8 + j*(-47) --54 + j*(-46) -138 + j*(-201) -26 + j*(-49) -235 + j*(-73) --143 + j*(-291) --103 + j*(-30) -18 + j*(-281) -311 + j*(122) -9 + j*(-27) --240 + j*(50) --110 + j*(209) -187 + j*(-209) -68 + j*(247) -498 + j*(-59) -161 + j*(-189) --132 + j*(72) --127 + j*(18) --193 + j*(-185) --127 + j*(-276) --104 + j*(235) --26 + j*(165) -148 + j*(-181) -87 + j*(-107) --177 + j*(136) -173 + j*(2) --298 + j*(-63) -218 + j*(29) --330 + j*(-167) -110 + j*(127) --18 + j*(-42) --85 + j*(153) --92 + j*(-119) -23 + j*(115) -149 + j*(-76) --132 + j*(85) --163 + j*(-52) --139 + j*(303) -151 + j*(113) -264 + j*(74) -48 + j*(115) --38 + j*(-9) --232 + j*(262) -412 + j*(123) -28 + j*(108) --53 + j*(-95) --79 + j*(184) --252 + j*(192) -170 + j*(39) -220 + j*(249) --5 + j*(-8) -125 + j*(27) -147 + j*(-80) -25 + j*(-272) -52 + j*(47) -248 + j*(-56) --84 + j*(-51) --93 + j*(-395) --179 + j*(221) --110 + j*(108) -13 + j*(26) -332 + j*(336) -31 + j*(-141) --2 + j*(76) -334 + j*(-79) -28 + j*(86) -307 + j*(-129) --251 + j*(197) --21 + j*(-36) --117 + j*(71) --279 + j*(42) -220 + j*(216) -135 + j*(-161) -345 + j*(-245) -40 + j*(-155) --61 + j*(159) -105 + j*(52) -278 + j*(-63) --40 + j*(35) --47 + j*(326) --171 + j*(-151) -83 + j*(177) --250 + j*(-70) -20 + j*(-68) -87 + j*(-123) --325 + j*(-98) --3 + j*(81) --21 + j*(165) -97 + j*(295) -554 + j*(168) --192 + j*(-154) -14 + j*(-11) --201 + j*(67) --163 + j*(153) --23 + j*(-153) --44 + j*(-7) --18 + j*(63) --110 + j*(-35) -471 + j*(-202) -267 + j*(-194) --140 + j*(-358) --204 + j*(-94) --25 + j*(-147) -59 + j*(199) -58 + j*(-13) --36 + j*(-114) -115 + j*(-163) -190 + j*(226) --142 + j*(-144) -51 + j*(-93) -68 + j*(-77) -1 + j*(-323) -95 + j*(-72) --112 + j*(3) -202 + j*(284) --261 + j*(18) --358 + j*(122) --129 + j*(-37) -80 + j*(-91) -59 + j*(132) -274 + j*(-385) -54 + j*(-131) --49 + j*(-127) --94 + j*(-332) -276 + j*(-44) -332 + j*(139) -13 + j*(-103) --63 + j*(137) -115 + j*(-137) --117 + j*(233) -10 + j*(-170) --358 + j*(-182) --37 + j*(15) -68 + j*(9) -342 + j*(-268) --127 + j*(-199) -141 + j*(-452) --265 + j*(1) --180 + j*(236) --18 + j*(4) -35 + j*(228) --30 + j*(8) -182 + j*(-211) --233 + j*(0) --79 + j*(-53) --159 + j*(100) --29 + j*(-131) --22 + j*(27) --136 + j*(165) -44 + j*(146) --162 + j*(21) -60 + j*(-158) --127 + j*(-2) --11 + j*(191) --139 + j*(9) -315 + j*(115) -175 + j*(-193) --45 + j*(250) -36 + j*(2) -141 + j*(-198) --307 + j*(2) -144 + j*(-59) -122 + j*(-27) --211 + j*(-483) -185 + j*(58) -39 + j*(127) --238 + j*(-109) -106 + j*(345) -76 + j*(33) -239 + j*(207) --109 + j*(-249) --146 + j*(45) --38 + j*(-150) -78 + j*(-186) -8 + j*(71) --207 + j*(-255) -85 + j*(16) --23 + j*(-153) -82 + j*(-11) --10 + j*(116) -162 + j*(-201) -66 + j*(-116) -277 + j*(163) -102 + j*(-358) -54 + j*(10) -37 + j*(-112) -127 + j*(-64) --74 + j*(-93) --54 + j*(214) -149 + j*(-37) --269 + j*(-66) --13 + j*(-220) --120 + j*(76) -97 + j*(75) -238 + j*(-78) -263 + j*(-293) --57 + j*(-131) -127 + j*(-202) -235 + j*(-105) -226 + j*(-18) --107 + j*(-286) -194 + j*(-118) -104 + j*(-121) -21 + j*(117) -380 + j*(92) -22 + j*(-190) -79 + j*(37) -175 + j*(180) -42 + j*(-70) -40 + j*(-174) --36 + j*(-141) --165 + j*(92) -9 + j*(-335) -328 + j*(-194) --198 + j*(-147) -342 + j*(-129) -71 + j*(-201) -176 + j*(-66) -16 + j*(-255) -179 + j*(-119) -89 + j*(133) -144 + j*(-78) -106 + j*(235) -175 + j*(-324) --68 + j*(315) --265 + j*(-374) --28 + j*(14) --213 + j*(106) -106 + j*(-163) -49 + j*(-71) --151 + j*(6) --421 + j*(119) --244 + j*(23) -81 + j*(-57) --259 + j*(-230) -177 + j*(101) --48 + j*(-308) -147 + j*(57) -152 + j*(47) --194 + j*(-25) --116 + j*(356) --68 + j*(149) -7 + j*(-132) --126 + j*(-159) --177 + j*(272) -226 + j*(-257) --158 + j*(51) --73 + j*(214) -47 + j*(-237) -161 + j*(250) -83 + j*(105) -103 + j*(35) -99 + j*(81) --6 + j*(0) --122 + j*(39) --116 + j*(-209) --172 + j*(-250) -179 + j*(-8) --174 + j*(134) --71 + j*(-194) -105 + j*(257) --124 + j*(100) -33 + j*(-117) --73 + j*(53) -144 + j*(-12) --185 + j*(-141) -136 + j*(110) -45 + j*(117) --7 + j*(-195) --86 + j*(172) --23 + j*(-103) --263 + j*(-26) --37 + j*(124) -166 + j*(392) --373 + j*(111) --34 + j*(-202) -63 + j*(299) -474 + j*(273) --264 + j*(-284) --119 + j*(33) -227 + j*(-117) --98 + j*(135) --47 + j*(-141) --158 + j*(-36) -160 + j*(38) --29 + j*(66) -144 + j*(-272) --171 + j*(-107) -357 + j*(-86) --231 + j*(-86) --75 + j*(-76) -216 + j*(156) --13 + j*(-187) --88 + j*(37) -119 + j*(270) -31 + j*(-77) --140 + j*(37) -21 + j*(-17) -211 + j*(-33) --287 + j*(101) --112 + j*(142) --3 + j*(-140) --91 + j*(-151) -150 + j*(-243) --64 + j*(96) --262 + j*(163) -196 + j*(-39) --126 + j*(-71) --161 + j*(102) --125 + j*(35) -292 + j*(98) --6 + j*(192) -107 + j*(-71) -83 + j*(-193) -272 + j*(-25) -235 + j*(67) --87 + j*(-159) --54 + j*(-118) --279 + j*(-4) -29 + j*(-20) -132 + j*(314) --73 + j*(-148) --470 + j*(86) -262 + j*(-260) --76 + j*(-42) -256 + j*(64) --18 + j*(-144) -40 + j*(-151) -75 + j*(-166) --196 + j*(21) --45 + j*(184) -121 + j*(18) --89 + j*(-148) --170 + j*(-18) -338 + j*(-150) --276 + j*(221) --177 + j*(236) -139 + j*(-134) -139 + j*(213) -33 + j*(233) --53 + j*(16) --219 + j*(-206) -301 + j*(-21) -83 + j*(-59) -47 + j*(-66) -325 + j*(-275) -53 + j*(10) --25 + j*(106) -85 + j*(-86) --150 + j*(-16) --172 + j*(-122) -317 + j*(-115) -66 + j*(-1) --176 + j*(4) --47 + j*(-43) --122 + j*(-28) -79 + j*(519) --87 + j*(190) -81 + j*(-124) -149 + j*(-67) --68 + j*(-148) --154 + j*(-199) --127 + j*(94) --21 + j*(-108) --185 + j*(155) --327 + j*(223) -127 + j*(27) -140 + j*(118) -260 + j*(-68) --228 + j*(200) --431 + j*(-226) -97 + j*(153) -68 + j*(25) --226 + j*(245) --83 + j*(133) -23 + j*(45) -70 + j*(52) --4 + j*(-66) --137 + j*(71) --110 + j*(78) -95 + j*(-11) -93 + j*(-266) --163 + j*(103) --246 + j*(-91) --9 + j*(-296) -177 + j*(-14) --151 + j*(-157) -60 + j*(73) -54 + j*(308) -165 + j*(-85) -106 + j*(-66) --205 + j*(-183) -45 + j*(107) -71 + j*(-59) -249 + j*(27) -10 + j*(168) --153 + j*(-134) --40 + j*(208) --214 + j*(156) -77 + j*(220) -115 + j*(103) -52 + j*(-8) --93 + j*(133) --163 + j*(78) -283 + j*(22) --500 + j*(-91) --42 + j*(-286) -25 + j*(143) --62 + j*(350) -303 + j*(157) --164 + j*(-109) -36 + j*(-296) -166 + j*(19) -298 + j*(161) -99 + j*(-253) -37 + j*(-6) --117 + j*(245) -191 + j*(-123) -153 + j*(-14) -107 + j*(77) --71 + j*(-195) -266 + j*(-438) -163 + j*(3) --202 + j*(-173) --95 + j*(62) -11 + j*(337) -33 + j*(-120) -206 + j*(-425) --189 + j*(-49) -183 + j*(118) --66 + j*(144) --214 + j*(-160) -88 + j*(-28) --49 + j*(102) --262 + j*(-225) --136 + j*(-174) --87 + j*(265) --43 + j*(-2) -68 + j*(36) -47 + j*(-197) --139 + j*(194) -14 + j*(332) -89 + j*(-95) --348 + j*(-112) -122 + j*(-240) -221 + j*(132) -170 + j*(-24) -310 + j*(-73) --103 + j*(-392) -61 + j*(-144) -112 + j*(-128) -73 + j*(52) -48 + j*(435) -224 + j*(169) -116 + j*(-322) -91 + j*(-1) --40 + j*(243) -72 + j*(-96) -159 + j*(-83) -69 + j*(30) --173 + j*(316) -322 + j*(-42) -99 + j*(208) -76 + j*(-222) --35 + j*(-66) -4 + j*(-345) --223 + j*(-115) --37 + j*(212) --119 + j*(6) --23 + j*(-83) --25 + j*(-12) --78 + j*(-47) -166 + j*(69) -116 + j*(72) --60 + j*(105) -165 + j*(53) -83 + j*(-57) --48 + j*(337) -35 + j*(-71) --260 + j*(124) --185 + j*(49) --117 + j*(-358) -138 + j*(-20) --103 + j*(-228) --87 + j*(105) --141 + j*(-50) -160 + j*(124) --448 + j*(42) --87 + j*(36) --227 + j*(-343) --188 + j*(-226) --101 + j*(-183) --8 + j*(-93) --264 + j*(-92) -233 + j*(57) -5 + j*(6) --47 + j*(122) -46 + j*(11) --13 + j*(-95) --35 + j*(60) -203 + j*(-5) --267 + j*(25) -112 + j*(-79) -329 + j*(-30) -111 + j*(-98) --238 + j*(286) --76 + j*(-166) -103 + j*(-232) --41 + j*(-90) -28 + j*(182) -190 + j*(-57) -203 + j*(-90) --51 + j*(-117) -74 + j*(120) --161 + j*(-360) -72 + j*(-57) -296 + j*(-36) -146 + j*(-111) -149 + j*(-75) --59 + j*(-81) -104 + j*(-30) -198 + j*(124) --120 + j*(-214) --98 + j*(63) --127 + j*(-165) -284 + j*(-8) --92 + j*(-310) --368 + j*(105) --314 + j*(-363) -184 + j*(265) --100 + j*(-36) --134 + j*(-56) --158 + j*(121) -72 + j*(-204) -130 + j*(44) --209 + j*(-211) -62 + j*(-212) -177 + j*(100) -78 + j*(-333) --42 + j*(-40) --37 + j*(125) -57 + j*(21) -182 + j*(-21) -3 + j*(-171) -243 + j*(-354) -344 + j*(57) --157 + j*(-167) -121 + j*(59) -151 + j*(145) --162 + j*(-107) -181 + j*(-11) --32 + j*(383) -86 + j*(7) --135 + j*(-260) --79 + j*(-11) --136 + j*(-334) -66 + j*(219) -300 + j*(1) --116 + j*(-202) -186 + j*(-223) -228 + j*(400) --150 + j*(-101) -161 + j*(-204) --10 + j*(53) --236 + j*(172) -143 + j*(-182) -10 + j*(272) -55 + j*(184) -32 + j*(-390) --69 + j*(317) --37 + j*(11) --74 + j*(30) -140 + j*(-83) -53 + j*(-136) -200 + j*(-285) --189 + j*(-378) --101 + j*(-253) --25 + j*(78) -17 + j*(-104) --180 + j*(196) --148 + j*(-309) --317 + j*(119) -141 + j*(79) --41 + j*(-72) --162 + j*(-63) --65 + j*(-35) --110 + j*(49) -110 + j*(-48) -19 + j*(92) --148 + j*(14) --102 + j*(280) -139 + j*(43) --36 + j*(-207) -40 + j*(-76) -172 + j*(-279) --35 + j*(224) -414 + j*(-378) -157 + j*(-112) -529 + j*(-307) --1 + j*(-74) --11 + j*(330) -236 + j*(-36) --158 + j*(-353) --215 + j*(-29) -185 + j*(174) --8 + j*(-27) -306 + j*(170) --214 + j*(-102) --73 + j*(37) -199 + j*(-156) -230 + j*(-113) --2 + j*(-106) --80 + j*(204) -40 + j*(-276) -196 + j*(-459) --330 + j*(-98) --267 + j*(83) --15 + j*(-58) --163 + j*(403) --126 + j*(-262) --215 + j*(178) -89 + j*(121) --132 + j*(130) -154 + j*(210) --159 + j*(337) --264 + j*(161) -25 + j*(201) --21 + j*(102) --132 + j*(101) -6 + j*(98) --19 + j*(-328) -62 + j*(-122) --151 + j*(-103) --72 + j*(316) -150 + j*(-520) -438 + j*(378) -144 + j*(462) -161 + j*(15) -42 + j*(-182) --123 + j*(479) --248 + j*(145) --416 + j*(305) -34 + j*(-459) -334 + j*(133) -391 + j*(-385) --167 + j*(324) --98 + j*(104) -444 + j*(-168) -151 + j*(-241) --143 + j*(56) --148 + j*(281) --276 + j*(269) -260 + j*(-255) -173 + j*(-64) -534 + j*(206) --692 + j*(597) -173 + j*(-259) -235 + j*(346) --59 + j*(-310) -124 + j*(334) --416 + j*(-148) -438 + j*(66) --269 + j*(421) --455 + j*(235) -355 + j*(-293) --326 + j*(-148) --332 + j*(-433) --89 + j*(75) -468 + j*(-103) -376 + j*(-51) --180 + j*(12) -91 + j*(-346) --95 + j*(447) --214 + j*(281) -107 + j*(256) -179 + j*(-77) --397 + j*(-168) --208 + j*(528) --342 + j*(282) -212 + j*(-330) --327 + j*(119) -339 + j*(-146) -112 + j*(346) -361 + j*(142) --556 + j*(260) --226 + j*(-152) --368 + j*(-221) --532 + j*(-147) --494 + j*(-18) -614 + j*(-132) -274 + j*(-102) --269 + j*(-486) --263 + j*(134) --486 + j*(426) --143 + j*(-286) --215 + j*(-343) --383 + j*(-17) --139 + j*(245) -346 + j*(157) -2 + j*(60) -264 + j*(64) -304 + j*(-49) -298 + j*(-491) --375 + j*(-129) -170 + j*(109) --226 + j*(-220) -450 + j*(117) --173 + j*(221) --119 + j*(484) --325 + j*(-109) --301 + j*(-263) --227 + j*(-337) --144 + j*(-313) --93 + j*(-265) --14 + j*(-269) --456 + j*(25) --330 + j*(127) --286 + j*(351) -482 + j*(-336) --387 + j*(436) --182 + j*(260) --327 + j*(-333) --502 + j*(-140) --131 + j*(-227) --261 + j*(-309) -183 + j*(195) --160 + j*(-465) --325 + j*(-431) -212 + j*(-549) -19 + j*(-120) -73 + j*(-1) --316 + j*(347) -192 + j*(265) --192 + j*(-124) -260 + j*(417) -431 + j*(-404) -192 + j*(-508) --54 + j*(-424) -370 + j*(18) --393 + j*(-101) -434 + j*(-268) -50 + j*(-37) -504 + j*(-91) -462 + j*(337) --223 + j*(-328) -298 + j*(-308) -140 + j*(-303) --208 + j*(-406) -378 + j*(-223) --325 + j*(105) --467 + j*(-122) -297 + j*(279) --589 + j*(-381) -252 + j*(185) -161 + j*(-177) -348 + j*(605) --329 + j*(116) -122 + j*(-226) --303 + j*(-57) -357 + j*(-264) --152 + j*(-261) --234 + j*(-112) --66 + j*(37) -239 + j*(446) --20 + j*(170) --202 + j*(72) --132 + j*(-164) --121 + j*(-69) --368 + j*(-541) --16 + j*(356) --226 + j*(-168) --274 + j*(-315) -606 + j*(-180) --187 + j*(-28) --444 + j*(333) --466 + j*(-235) --121 + j*(-71) --236 + j*(-49) -506 + j*(-332) -218 + j*(248) --22 + j*(-289) -308 + j*(-8) --85 + j*(414) --154 + j*(360) -46 + j*(-332) -199 + j*(10) --243 + j*(485) --368 + j*(-624) --367 + j*(170) --339 + j*(274) -895 + j*(286) -148 + j*(-251) -167 + j*(156) -195 + j*(205) -27 + j*(-98) -86 + j*(-226) --197 + j*(-206) -417 + j*(-226) -308 + j*(503) -401 + j*(-250) --139 + j*(158) -108 + j*(190) -462 + j*(257) -14 + j*(-387) -360 + j*(155) --435 + j*(-99) -361 + j*(416) -258 + j*(-62) -25 + j*(-333) -66 + j*(352) -546 + j*(-286) --180 + j*(-458) -280 + j*(-151) -72 + j*(-216) --368 + j*(403) -464 + j*(527) --344 + j*(-60) --129 + j*(516) --279 + j*(348) --249 + j*(257) -95 + j*(226) -180 + j*(170) --97 + j*(-238) --234 + j*(-164) -148 + j*(-344) --190 + j*(-359) -152 + j*(537) -187 + j*(-93) --264 + j*(311) -100 + j*(115) -329 + j*(-129) --264 + j*(495) -281 + j*(296) --216 + j*(-100) -255 + j*(635) --410 + j*(324) -368 + j*(349) --515 + j*(-427) --296 + j*(-91) --89 + j*(-357) -23 + j*(-220) --39 + j*(-482) -366 + j*(613) -359 + j*(44) -270 + j*(-241) -146 + j*(-653) --220 + j*(441) -269 + j*(125) --350 + j*(321) -284 + j*(12) --209 + j*(-60) -305 + j*(144) --368 + j*(272) -468 + j*(-231) -176 + j*(12) --149 + j*(-216) -424 + j*(-84) --462 + j*(-520) -349 + j*(-377) --361 + j*(166) -165 + j*(238) --78 + j*(201) --188 + j*(330) --70 + j*(-25) --220 + j*(330) --206 + j*(308) -378 + j*(-181) --203 + j*(-356) -501 + j*(-574) -63 + j*(134) --493 + j*(-103) --26 + j*(-341) --390 + j*(158) -69 + j*(249) -279 + j*(358) -441 + j*(-253) --142 + j*(142) --346 + j*(-387) -332 + j*(-606) -187 + j*(240) -431 + j*(-35) -308 + j*(-181) -240 + j*(-338) -240 + j*(-168) --429 + j*(-134) -161 + j*(-89) --460 + j*(-346) --382 + j*(247) --521 + j*(-66) -99 + j*(318) --193 + j*(-20) -148 + j*(551) -366 + j*(200) -560 + j*(-170) -281 + j*(280) --462 + j*(-173) --424 + j*(66) -190 + j*(354) --135 + j*(-346) --283 + j*(-282) -306 + j*(-280) -308 + j*(341) -57 + j*(-380) --439 + j*(-147) -46 + j*(-188) --189 + j*(136) --167 + j*(281) --73 + j*(-352) -286 + j*(165) --353 + j*(152) -255 + j*(-443) -458 + j*(300) -126 + j*(-267) --147 + j*(430) -756 + j*(232) --462 + j*(-200) --246 + j*(368) -392 + j*(501) -593 + j*(-118) --341 + j*(274) -240 + j*(221) --474 + j*(-129) -277 + j*(418) --134 + j*(231) --302 + j*(115) -101 + j*(337) --122 + j*(-20) -503 + j*(-217) -473 + j*(-235) --338 + j*(-158) --43 + j*(472) --428 + j*(-216) --344 + j*(75) --728 + j*(233) --86 + j*(6) -337 + j*(-549) --318 + j*(4) --322 + j*(177) -141 + j*(-152) -445 + j*(85) -260 + j*(178) -54 + j*(128) --45 + j*(103) --320 + j*(307) --640 + j*(-346) --98 + j*(445) --356 + j*(-291) -173 + j*(229) --5 + j*(130) -142 + j*(248) --248 + j*(412) --18 + j*(494) -238 + j*(195) --159 + j*(-196) -338 + j*(211) -767 + j*(-549) -516 + j*(185) -252 + j*(87) --416 + j*(387) -371 + j*(-352) --396 + j*(34) -455 + j*(34) -298 + j*(-147) --377 + j*(119) -214 + j*(-19) --242 + j*(-141) -115 + j*(305) -542 + j*(292) -58 + j*(-453) -199 + j*(-347) --431 + j*(-128) -260 + j*(-252) --175 + j*(491) -535 + j*(-119) -330 + j*(69) --240 + j*(-301) -499 + j*(525) --400 + j*(-455) -549 + j*(636) -247 + j*(-328) --293 + j*(-170) --178 + j*(270) --119 + j*(250) -183 + j*(57) -252 + j*(97) --539 + j*(-34) --353 + j*(-15) --105 + j*(-148) --272 + j*(-336) --338 + j*(-402) --396 + j*(57) -292 + j*(41) --204 + j*(-299) -281 + j*(333) -77 + j*(323) --190 + j*(-385) -426 + j*(-128) -263 + j*(282) -16 + j*(18) -327 + j*(-40) --411 + j*(-99) -387 + j*(91) --238 + j*(166) --72 + j*(11) --508 + j*(233) -244 + j*(-490) --442 + j*(216) -178 + j*(-419) -313 + j*(187) -266 + j*(-521) -390 + j*(-337) -448 + j*(-103) -425 + j*(-349) --151 + j*(310) -283 + j*(-153) -320 + j*(-281) -56 + j*(99) --202 + j*(-406) --141 + j*(-409) -121 + j*(317) -380 + j*(371) --177 + j*(-47) -361 + j*(-379) --448 + j*(-28) -296 + j*(-269) -508 + j*(-238) -659 + j*(-47) --298 + j*(-180) -104 + j*(174) -49 + j*(-67) -233 + j*(-449) -339 + j*(156) -258 + j*(-158) --181 + j*(426) -278 + j*(-175) --68 + j*(-334) -327 + j*(-599) -118 + j*(-216) -45 + j*(-304) --158 + j*(216) --257 + j*(204) -396 + j*(-415) -338 + j*(229) --194 + j*(256) --583 + j*(306) -103 + j*(-457) -185 + j*(-439) -478 + j*(66) --255 + j*(464) --145 + j*(346) --660 + j*(-47) --511 + j*(-410) --288 + j*(453) --258 + j*(250) --115 + j*(-121) -134 + j*(344) -349 + j*(-287) --503 + j*(205) --383 + j*(-410) --470 + j*(240) -325 + j*(-687) -221 + j*(-151) -426 + j*(418) -134 + j*(206) -88 + j*(-121) --111 + j*(362) --305 + j*(-182) -93 + j*(-185) --174 + j*(406) --417 + j*(240) -104 + j*(-155) -146 + j*(375) -618 + j*(146) -134 + j*(196) --393 + j*(343) --454 + j*(-76) -260 + j*(-24) -132 + j*(-68) -242 + j*(426) -106 + j*(-454) --266 + j*(-200) -337 + j*(576) -180 + j*(95) --257 + j*(116) -459 + j*(417) --129 + j*(-160) -142 + j*(-197) -219 + j*(504) -154 + j*(170) -132 + j*(185) -316 + j*(264) --440 + j*(200) -97 + j*(-3) --9 + j*(-173) -249 + j*(-28) -612 + j*(-663) --484 + j*(-26) -419 + j*(425) --228 + j*(330) -4 + j*(-297) -445 + j*(201) -519 + j*(37) -333 + j*(158) -362 + j*(45) -333 + j*(-542) -187 + j*(-188) --148 + j*(-273) --329 + j*(241) --148 + j*(-251) -423 + j*(-16) -90 + j*(-232) --293 + j*(551) --190 + j*(165) --256 + j*(-518) -143 + j*(-260) -463 + j*(-392) --295 + j*(-20) -14 + j*(-130) -2 + j*(293) --354 + j*(-299) -409 + j*(298) -185 + j*(238) -383 + j*(220) -316 + j*(-39) -177 + j*(-8) --269 + j*(-223) --332 + j*(132) --312 + j*(137) --254 + j*(-224) --279 + j*(-206) -103 + j*(276) --81 + j*(235) -106 + j*(-356) --250 + j*(170) -146 + j*(-256) -375 + j*(206) -35 + j*(285) -179 + j*(-480) --4 + j*(262) -286 + j*(339) -349 + j*(3) -262 + j*(-317) --188 + j*(314) -258 + j*(280) --60 + j*(-63) --358 + j*(-431) -355 + j*(-313) -602 + j*(-572) --97 + j*(29) --361 + j*(112) -426 + j*(-446) --334 + j*(-248) --468 + j*(-301) --134 + j*(-296) -344 + j*(-398) --33 + j*(361) -339 + j*(-470) -238 + j*(311) -455 + j*(372) --419 + j*(47) --267 + j*(-6) -313 + j*(-315) --314 + j*(148) --167 + j*(-559) -371 + j*(-467) --377 + j*(337) -535 + j*(-262) -170 + j*(-213) --719 + j*(-409) --59 + j*(155) --137 + j*(240) --403 + j*(-211) --310 + j*(-119) -405 + j*(-72) --488 + j*(136) --270 + j*(-495) -375 + j*(-124) -294 + j*(-73) -494 + j*(406) -423 + j*(311) --401 + j*(-383) -378 + j*(293) --290 + j*(-348) -111 + j*(-182) -414 + j*(523) --121 + j*(746) -129 + j*(-466) -409 + j*(-359) -342 + j*(63) --325 + j*(174) --292 + j*(103) -221 + j*(407) -298 + j*(240) --343 + j*(363) -192 + j*(-296) --291 + j*(180) --76 + j*(-33) --58 + j*(-362) --260 + j*(-202) --301 + j*(-129) -86 + j*(400) --240 + j*(337) -77 + j*(-55) -279 + j*(831) -20 + j*(-13) -305 + j*(-124) -551 + j*(99) -439 + j*(438) --194 + j*(490) -592 + j*(216) --382 + j*(228) --316 + j*(76) -98 + j*(30) -216 + j*(-286) -268 + j*(18) --13 + j*(233) --497 + j*(-483) -25 + j*(-332) -168 + j*(227) -301 + j*(143) -73 + j*(-48) --3 + j*(-291) -588 + j*(16) -192 + j*(-489) -243 + j*(76) -254 + j*(539) --380 + j*(229) -489 + j*(15) -241 + j*(131) -158 + j*(-295) -306 + j*(195) --283 + j*(428) -412 + j*(-48) -384 + j*(-260) --188 + j*(38) --104 + j*(-159) -64 + j*(142) --39 + j*(92) --73 + j*(243) -114 + j*(-292) --19 + j*(36) --160 + j*(345) -123 + j*(-62) --45 + j*(297) -299 + j*(33) -117 + j*(-93) --214 + j*(44) --345 + j*(-15) --11 + j*(-78) -204 + j*(16) -132 + j*(-22) --45 + j*(59) --220 + j*(-21) -145 + j*(-76) --124 + j*(120) -156 + j*(-31) -21 + j*(-187) --81 + j*(160) --43 + j*(-79) -114 + j*(7) -247 + j*(-122) -90 + j*(96) --132 + j*(27) -228 + j*(11) --179 + j*(40) -78 + j*(89) --513 + j*(3) --152 + j*(246) --60 + j*(211) --108 + j*(-76) --30 + j*(-112) --68 + j*(-276) -18 + j*(42) --13 + j*(-322) --76 + j*(-78) -156 + j*(48) --25 + j*(121) -106 + j*(-127) --110 + j*(257) -263 + j*(132) --168 + j*(303) -18 + j*(271) -6 + j*(-148) -133 + j*(-263) --25 + j*(130) -71 + j*(329) -406 + j*(-14) --28 + j*(-89) --214 + j*(40) --121 + j*(194) --138 + j*(-7) -107 + j*(97) -213 + j*(-98) -114 + j*(73) --233 + j*(3) --34 + j*(290) -18 + j*(-125) --28 + j*(263) --121 + j*(12) -53 + j*(-48) -95 + j*(-21) --461 + j*(13) -213 + j*(110) -223 + j*(98) --137 + j*(-126) --167 + j*(30) --60 + j*(-438) -86 + j*(-72) -94 + j*(-175) --103 + j*(111) -93 + j*(57) --177 + j*(-207) --134 + j*(130) -194 + j*(159) -25 + j*(36) -25 + j*(-231) -134 + j*(7) -117 + j*(-178) --200 + j*(214) -11 + j*(51) --337 + j*(-10) -259 + j*(-6) --61 + j*(129) --28 + j*(39) --150 + j*(-81) -67 + j*(1) --139 + j*(144) --64 + j*(-216) -107 + j*(-387) --105 + j*(93) -342 + j*(-31) --133 + j*(26) -18 + j*(-242) --230 + j*(-160) --255 + j*(-103) -288 + j*(70) -45 + j*(18) -91 + j*(-15) -95 + j*(69) -6 + j*(193) --107 + j*(-19) -264 + j*(-83) -42 + j*(-170) --48 + j*(-8) -242 + j*(4) -320 + j*(47) --75 + j*(-93) --161 + j*(45) --58 + j*(-127) -112 + j*(66) -193 + j*(224) --577 + j*(-352) --33 + j*(142) -117 + j*(72) -1 + j*(-115) --107 + j*(167) --45 + j*(187) -29 + j*(-117) -108 + j*(-128) -103 + j*(226) --436 + j*(-210) --245 + j*(54) -37 + j*(-62) -1 + j*(-59) --233 + j*(82) --101 + j*(299) -74 + j*(46) -59 + j*(-214) --245 + j*(-179) -153 + j*(-385) --86 + j*(215) --105 + j*(-47) --48 + j*(-337) -51 + j*(153) -118 + j*(159) --117 + j*(-160) -131 + j*(19) -245 + j*(74) --171 + j*(86) --31 + j*(-61) --144 + j*(179) -35 + j*(-370) -170 + j*(-76) -280 + j*(-52) --89 + j*(-163) -78 + j*(47) --345 + j*(-32) --236 + j*(-15) -204 + j*(-49) --517 + j*(-52) --93 + j*(-81) -264 + j*(18) --144 + j*(-25) -212 + j*(121) -26 + j*(-342) -165 + j*(53) -41 + j*(-14) --111 + j*(197) --179 + j*(233) -121 + j*(255) -208 + j*(-71) -187 + j*(293) -110 + j*(-317) -118 + j*(225) -250 + j*(187) -4 + j*(-260) --48 + j*(72) --195 + j*(97) -91 + j*(-210) -113 + j*(-173) --32 + j*(2) --112 + j*(-9) -373 + j*(-229) -42 + j*(-64) --106 + j*(-13) --58 + j*(25) -68 + j*(89) --93 + j*(-106) -204 + j*(-76) --177 + j*(13) --84 + j*(-198) -168 + j*(287) --218 + j*(220) --139 + j*(-203) -346 + j*(156) --194 + j*(-30) -134 + j*(-30) --124 + j*(147) --199 + j*(-285) -168 + j*(-201) -122 + j*(-271) -103 + j*(-25) -40 + j*(-42) --129 + j*(42) -119 + j*(234) -91 + j*(185) -154 + j*(-153) -114 + j*(396) -103 + j*(156) --127 + j*(-274) -122 + j*(-151) -34 + j*(112) --236 + j*(-66) -266 + j*(-33) --177 + j*(-86) --26 + j*(-129) -52 + j*(164) --59 + j*(-304) --383 + j*(-279) -146 + j*(136) -419 + j*(40) --30 + j*(113) --105 + j*(142) -213 + j*(-259) -30 + j*(363) -168 + j*(-375) --107 + j*(60) -128 + j*(199) --71 + j*(113) --95 + j*(-124) --17 + j*(48) --57 + j*(65) --76 + j*(23) --274 + j*(-206) -125 + j*(276) -98 + j*(-57) --129 + j*(-179) --58 + j*(311) -54 + j*(52) --351 + j*(226) --252 + j*(55) --142 + j*(-17) -202 + j*(107) -176 + j*(-477) --71 + j*(18) --174 + j*(125) -144 + j*(-108) --10 + j*(-19) --28 + j*(112) --26 + j*(132) --236 + j*(-8) -37 + j*(-214) -111 + j*(216) -260 + j*(70) --30 + j*(-69) --91 + j*(157) -221 + j*(-96) --162 + j*(-126) --71 + j*(110) -16 + j*(117) -128 + j*(-4) -69 + j*(35) --62 + j*(177) -143 + j*(88) --124 + j*(-195) --118 + j*(-61) -26 + j*(-187) --76 + j*(262) --21 + j*(-103) --164 + j*(-139) --73 + j*(-175) -262 + j*(-58) -44 + j*(58) -78 + j*(-43) --245 + j*(336) --28 + j*(-38) --124 + j*(-168) --320 + j*(34) --175 + j*(-11) --190 + j*(-241) -119 + j*(-78) --242 + j*(264) --91 + j*(234) --57 + j*(-42) --189 + j*(11) -130 + j*(103) -217 + j*(-100) -170 + j*(-62) --327 + j*(82) --132 + j*(-118) -19 + j*(1) -15 + j*(-6) --479 + j*(69) -38 + j*(68) -1 + j*(-229) -93 + j*(-98) -54 + j*(-93) --23 + j*(-100) -1 + j*(-197) --269 + j*(-126) -177 + j*(23) --412 + j*(-282) --78 + j*(88) --214 + j*(225) --96 + j*(127) --40 + j*(181) -276 + j*(175) --191 + j*(-257) -163 + j*(-84) --82 + j*(92) -171 + j*(132) -213 + j*(-79) -234 + j*(125) --62 + j*(-272) -57 + j*(-56) -62 + j*(-363) --136 + j*(64) -40 + j*(33) --63 + j*(-95) --162 + j*(172) --141 + j*(-281) --13 + j*(40) -248 + j*(-70) --104 + j*(-439) -57 + j*(192) -21 + j*(16) --385 + j*(-86) -86 + j*(-322) --263 + j*(279) -238 + j*(83) -62 + j*(-112) --68 + j*(-26) -30 + j*(182) -6 + j*(-152) -100 + j*(-80) -91 + j*(1) --49 + j*(-240) -88 + j*(19) -74 + j*(98) -87 + j*(234) -5 + j*(-245) --310 + j*(57) --78 + j*(-243) --163 + j*(-32) -114 + j*(-437) -44 + j*(150) -158 + j*(-68) -327 + j*(-263) --3 + j*(-2) -151 + j*(268) --274 + j*(-351) --291 + j*(-420) --409 + j*(204) --454 + j*(-66) -66 + j*(26) --187 + j*(277) -73 + j*(-33) -118 + j*(123) -136 + j*(-40) -87 + j*(138) -264 + j*(47) -93 + j*(288) -113 + j*(107) --233 + j*(95) -19 + j*(170) --23 + j*(-486) -30 + j*(-47) -146 + j*(107) -177 + j*(226) --82 + j*(-301) -155 + j*(58) -78 + j*(-10) -390 + j*(233) --5 + j*(74) --33 + j*(25) --117 + j*(394) -202 + j*(-98) -18 + j*(83) -47 + j*(-127) -230 + j*(-156) -255 + j*(112) --26 + j*(358) -50 + j*(109) --56 + j*(-51) --78 + j*(-240) --190 + j*(42) -119 + j*(98) --146 + j*(84) --37 + j*(-115) -76 + j*(38) -99 + j*(-181) -31 + j*(-63) -69 + j*(61) --100 + j*(62) --81 + j*(161) -130 + j*(-101) -134 + j*(-168) -40 + j*(25) --57 + j*(-278) --58 + j*(244) --368 + j*(-64) -214 + j*(367) -43 + j*(104) -347 + j*(-150) -293 + j*(45) --139 + j*(-16) -198 + j*(120) -286 + j*(255) -342 + j*(-254) -70 + j*(-104) --275 + j*(-223) --37 + j*(-50) --337 + j*(-89) --74 + j*(-56) -133 + j*(202) --61 + j*(255) --209 + j*(-103) --110 + j*(-83) -130 + j*(244) --274 + j*(2) -78 + j*(-186) -56 + j*(163) --122 + j*(-139) -90 + j*(-124) --6 + j*(-28) -99 + j*(-203) --340 + j*(-146) -90 + j*(-62) -215 + j*(-257) -42 + j*(-3) -170 + j*(380) -2 + j*(62) --43 + j*(-52) --331 + j*(12) --26 + j*(33) -77 + j*(141) --184 + j*(-206) -349 + j*(74) -128 + j*(-83) --309 + j*(213) -233 + j*(22) -155 + j*(-16) --82 + j*(-190) --129 + j*(-1) -131 + j*(-341) -182 + j*(-120) -211 + j*(81) -47 + j*(-32) --79 + j*(233) --113 + j*(-443) -89 + j*(170) -218 + j*(-257) --78 + j*(74) --11 + j*(-57) --220 + j*(233) --165 + j*(62) -19 + j*(44) --121 + j*(-240) --3 + j*(-156) -272 + j*(11) --161 + j*(-361) --133 + j*(-153) --51 + j*(122) --30 + j*(56) --116 + j*(-74) -90 + j*(-298) -97 + j*(-151) -126 + j*(-69) -64 + j*(49) --18 + j*(-126) --45 + j*(-190) -72 + j*(-124) -42 + j*(-128) -238 + j*(-228) -18 + j*(-296) -182 + j*(188) -52 + j*(-131) --25 + j*(47) -66 + j*(-49) -327 + j*(-474) -110 + j*(71) --76 + j*(-78) -86 + j*(30) --158 + j*(221) --16 + j*(-371) --144 + j*(100) -9 + j*(197) --65 + j*(-11) --218 + j*(-257) -278 + j*(75) --103 + j*(40) -42 + j*(-145) -496 + j*(53) --161 + j*(-137) --82 + j*(-205) -116 + j*(-37) --134 + j*(98) --26 + j*(392) -221 + j*(-45) --209 + j*(-288) --261 + j*(96) -199 + j*(-429) -516 + j*(-110) -18 + j*(112) -106 + j*(-329) --83 + j*(-117) --190 + j*(36) -177 + j*(252) -13 + j*(15) -0 + j*(-269) -18 + j*(49) -262 + j*(17) --161 + j*(154) -71 + j*(-43) -274 + j*(-88) --167 + j*(67) -192 + j*(-173) --156 + j*(251) --127 + j*(31) -53 + j*(112) --47 + j*(306) --409 + j*(-194) -70 + j*(172) --108 + j*(-223) --54 + j*(6) -215 + j*(283) -281 + j*(-138) -53 + j*(102) -12 + j*(-93) -293 + j*(48) --223 + j*(-163) -37 + j*(127) --21 + j*(-30) -122 + j*(139) --6 + j*(147) --168 + j*(-25) --1 + j*(63) -203 + j*(-30) --184 + j*(-281) -0 + j*(-66) -245 + j*(80) --3 + j*(-154) --151 + j*(-327) --185 + j*(-123) -105 + j*(-202) --218 + j*(190) --54 + j*(29) -25 + j*(-47) --437 + j*(-132) --42 + j*(-11) --264 + j*(-191) --55 + j*(-18) -277 + j*(-223) -69 + j*(-213) --334 + j*(-90) -185 + j*(-269) --95 + j*(-21) --281 + j*(240) --86 + j*(132) --134 + j*(-120) -17 + j*(-402) --30 + j*(-4) -124 + j*(-308) --21 + j*(-54) -107 + j*(-12) -86 + j*(-109) -23 + j*(53) --42 + j*(-352) --68 + j*(-250) -354 + j*(-155) -34 + j*(-111) --156 + j*(228) -127 + j*(-209) -47 + j*(69) --118 + j*(298) -33 + j*(-36) -62 + j*(392) --269 + j*(-88) --366 + j*(-47) --127 + j*(-98) -91 + j*(40) --138 + j*(-253) --57 + j*(181) -186 + j*(-102) -83 + j*(-89) --9 + j*(-419) -109 + j*(265) -124 + j*(316) -12 + j*(-206) --10 + j*(153) --159 + j*(27) -53 + j*(-252) --21 + j*(168) -129 + j*(91) --205 + j*(-82) -85 + j*(143) --11 + j*(17) -71 + j*(-145) -45 + j*(80) -71 + j*(50) -180 + j*(49) -110 + j*(0) --60 + j*(233) -24 + j*(-153) --16 + j*(137) -269 + j*(187) --115 + j*(156) -29 + j*(81) --232 + j*(-161) -206 + j*(-56) --47 + j*(17) --18 + j*(-177) --100 + j*(126) --270 + j*(82) --180 + j*(42) -238 + j*(366) -69 + j*(236) -182 + j*(-151) -0 + j*(180) -232 + j*(-28) -72 + j*(299) -87 + j*(84) -35 + j*(-416) --200 + j*(-43) -206 + j*(-60) --245 + j*(-146) -89 + j*(95) --127 + j*(250) --342 + j*(-6) --5 + j*(342) --239 + j*(-119) -169 + j*(-29) --375 + j*(98) -81 + j*(-380) --65 + j*(4) --139 + j*(-205) -69 + j*(-94) --81 + j*(-175) -16 + j*(-124) --81 + j*(185) -165 + j*(378) --140 + j*(337) -42 + j*(91) --156 + j*(201) --127 + j*(-64) --35 + j*(-177) --238 + j*(-87) --241 + j*(-294) -88 + j*(-289) --164 + j*(56) --141 + j*(-109) -64 + j*(29) --239 + j*(-172) -88 + j*(-416) --188 + j*(-76) --222 + j*(103) -7 + j*(-53) -218 + j*(-284) -82 + j*(-288) -111 + j*(40) --47 + j*(111) --57 + j*(176) -20 + j*(-96) --25 + j*(284) --29 + j*(87) -63 + j*(266) --67 + j*(-129) -154 + j*(-69) -141 + j*(78) -38 + j*(-177) --46 + j*(-306) -271 + j*(125) -378 + j*(130) --303 + j*(-30) -148 + j*(-64) --124 + j*(-332) --153 + j*(71) --49 + j*(18) --78 + j*(-183) --334 + j*(-199) --238 + j*(-58) --269 + j*(-38) -253 + j*(-426) --166 + j*(197) -197 + j*(-147) --33 + j*(-86) -190 + j*(80) --111 + j*(-462) --76 + j*(-369) -501 + j*(-119) -192 + j*(-117) -106 + j*(-60) -148 + j*(-238) -10 + j*(79) -97 + j*(53) -64 + j*(-66) --162 + j*(-535) -60 + j*(83) --188 + j*(-98) -32 + j*(15) --74 + j*(-52) --30 + j*(-102) -61 + j*(300) --64 + j*(8) --245 + j*(105) -114 + j*(-330) -83 + j*(141) -98 + j*(98) --74 + j*(-268) -112 + j*(49) -451 + j*(-61) --107 + j*(52) -136 + j*(-39) --157 + j*(350) -33 + j*(-122) -258 + j*(173) -334 + j*(45) --48 + j*(170) -78 + j*(-82) -59 + j*(-108) -347 + j*(75) --314 + j*(86) --387 + j*(275) -6 + j*(132) --204 + j*(294) -124 + j*(98) --254 + j*(22) --89 + j*(-156) --392 + j*(-168) -141 + j*(-159) -201 + j*(-175) --28 + j*(5) -132 + j*(116) -4 + j*(-4) -227 + j*(-108) --268 + j*(-85) -115 + j*(-98) --57 + j*(139) -200 + j*(-103) --65 + j*(-194) --146 + j*(-59) --314 + j*(45) -146 + j*(-1) -26 + j*(40) --290 + j*(-56) --260 + j*(-264) -165 + j*(35) -235 + j*(-228) -149 + j*(-168) --25 + j*(-196) -33 + j*(-211) --172 + j*(-173) --148 + j*(168) --281 + j*(62) --56 + j*(-12) -179 + j*(-24) -54 + j*(45) --128 + j*(-153) -72 + j*(-62) --12 + j*(343) -214 + j*(-173) --105 + j*(41) -151 + j*(-11) --226 + j*(140) -24 + j*(175) --57 + j*(12) --25 + j*(86) --269 + j*(27) -175 + j*(13) -238 + j*(9) -107 + j*(62) -15 + j*(-73) -115 + j*(-37) -80 + j*(-197) --50 + j*(118) --206 + j*(123) -23 + j*(35) --257 + j*(-112) --66 + j*(183) --155 + j*(-4) --161 + j*(135) -132 + j*(-220) --22 + j*(-358) -197 + j*(277) -339 + j*(8) --232 + j*(-293) -134 + j*(-162) --253 + j*(179) --255 + j*(-197) --110 + j*(-202) --216 + j*(-243) --247 + j*(103) --16 + j*(-33) -107 + j*(-113) --93 + j*(-20) --52 + j*(299) --43 + j*(-234) --131 + j*(-33) -135 + j*(207) -88 + j*(-26) -125 + j*(206) -164 + j*(5) -78 + j*(-178) --151 + j*(-197) -190 + j*(-16) -151 + j*(88) --52 + j*(255) -19 + j*(-182) -144 + j*(-44) --16 + j*(-112) -145 + j*(81) --35 + j*(-1) --107 + j*(-6) -148 + j*(351) --156 + j*(421) --252 + j*(-71) -373 + j*(-182) -228 + j*(51) --71 + j*(137) -83 + j*(201) -54 + j*(-112) -26 + j*(-145) --55 + j*(4) -161 + j*(330) --30 + j*(-250) --421 + j*(-114) -30 + j*(-16) -69 + j*(106) --43 + j*(43) --155 + j*(178) -20 + j*(-208) --395 + j*(226) --147 + j*(129) -11 + j*(-42) --331 + j*(91) -81 + j*(56) --460 + j*(-49) --269 + j*(1) -19 + j*(216) --124 + j*(30) -16 + j*(190) --293 + j*(-240) --170 + j*(149) --101 + j*(95) -130 + j*(-82) --33 + j*(116) -28 + j*(21) -83 + j*(-83) --211 + j*(257) --6 + j*(133) -32 + j*(-163) -44 + j*(-69) -36 + j*(95) --80 + j*(24) --17 + j*(-354) -115 + j*(130) -28 + j*(-41) -287 + j*(195) -433 + j*(-71) --191 + j*(195) --75 + j*(-296) --195 + j*(170) -291 + j*(-35) --164 + j*(128) -271 + j*(50) -132 + j*(-71) -202 + j*(26) -12 + j*(-90) --260 + j*(25) -165 + j*(29) --89 + j*(250) --25 + j*(-21) --33 + j*(-4) -284 + j*(108) --162 + j*(-106) -76 + j*(-163) -85 + j*(70) --106 + j*(61) --273 + j*(32) -24 + j*(-115) -268 + j*(-297) --211 + j*(58) -243 + j*(16) -105 + j*(-155) --36 + j*(-225) -64 + j*(80) --42 + j*(31) -115 + j*(276) --332 + j*(-232) -111 + j*(7) --216 + j*(-134) --154 + j*(-279) --182 + j*(76) -121 + j*(-49) --88 + j*(-52) -167 + j*(-93) --135 + j*(-245) --210 + j*(405) --69 + j*(212) --48 + j*(-240) -385 + j*(306) -31 + j*(108) --7 + j*(-222) -30 + j*(-53) --194 + j*(-183) --21 + j*(57) --330 + j*(171) --42 + j*(-16) -199 + j*(221) --12 + j*(25) --70 + j*(458) --371 + j*(-155) --78 + j*(100) -49 + j*(-85) -110 + j*(-243) --23 + j*(40) -12 + j*(-71) --82 + j*(-624) --156 + j*(53) --153 + j*(264) -2 + j*(-132) -63 + j*(86) -133 + j*(40) -129 + j*(221) -192 + j*(-300) --122 + j*(202) -76 + j*(-155) -94 + j*(28) --17 + j*(281) --382 + j*(105) -310 + j*(158) -20 + j*(122) -211 + j*(-99) -217 + j*(-166) --1 + j*(-130) -32 + j*(-39) --64 + j*(-286) -365 + j*(-83) -216 + j*(89) -167 + j*(-338) -324 + j*(67) -223 + j*(123) -44 + j*(-21) -66 + j*(79) --109 + j*(105) -59 + j*(-62) -211 + j*(35) --165 + j*(-54) -142 + j*(123) --187 + j*(-115) -76 + j*(100) --290 + j*(-316) --78 + j*(162) -156 + j*(49) --69 + j*(-29) -202 + j*(151) -37 + j*(11) --40 + j*(-138) -31 + j*(10) --28 + j*(-112) --195 + j*(175) --178 + j*(187) -51 + j*(-35) -112 + j*(-6) --207 + j*(-35) --70 + j*(19) --129 + j*(-331) -99 + j*(-210) -275 + j*(123) --262 + j*(250) --9 + j*(129) -156 + j*(223) -59 + j*(42) --272 + j*(-320) --107 + j*(-27) --274 + j*(317) --271 + j*(238) -74 + j*(-22) -181 + j*(-249) -286 + j*(86) -57 + j*(268) --69 + j*(-50) -22 + j*(233) -137 + j*(168) -156 + j*(88) -250 + j*(165) -175 + j*(-258) --250 + j*(-158) --57 + j*(251) --192 + j*(98) -88 + j*(208) --175 + j*(130) -40 + j*(-162) --237 + j*(-4) -272 + j*(8) --54 + j*(163) -105 + j*(72) -216 + j*(-69) --257 + j*(139) --250 + j*(53) -30 + j*(-439) -78 + j*(-208) -182 + j*(177) -262 + j*(83) -318 + j*(-4) --6 + j*(214) --37 + j*(-172) --144 + j*(-33) --278 + j*(42) -195 + j*(29) -158 + j*(76) --30 + j*(-395) -189 + j*(-122) --165 + j*(-22) --307 + j*(240) -18 + j*(-73) -11 + j*(422) --108 + j*(-59) -366 + j*(13) --81 + j*(-116) --286 + j*(244) -99 + j*(349) --102 + j*(-100) --247 + j*(-32) -2 + j*(175) --40 + j*(337) -284 + j*(124) -107 + j*(-8) -126 + j*(107) --348 + j*(-184) -206 + j*(-15) -242 + j*(-8) -248 + j*(9) -83 + j*(65) --153 + j*(53) --117 + j*(169) --359 + j*(41) --34 + j*(3) --264 + j*(-237) -42 + j*(-223) -218 + j*(116) --92 + j*(-192) --259 + j*(-144) -304 + j*(78) --10 + j*(337) -8 + j*(122) --57 + j*(28) --35 + j*(37) --46 + j*(13) -55 + j*(261) --244 + j*(-163) -42 + j*(-45) --339 + j*(-79) -82 + j*(412) -7 + j*(150) -132 + j*(199) -137 + j*(-323) -269 + j*(-166) --7 + j*(54) --243 + j*(232) --180 + j*(-30) --78 + j*(-49) --113 + j*(4) -30 + j*(-32) -95 + j*(64) --1 + j*(-146) -20 + j*(-11) -91 + j*(194) -51 + j*(-269) --250 + j*(-105) --141 + j*(-33) --114 + j*(310) -177 + j*(211) --138 + j*(417) --13 + j*(258) -260 + j*(-113) -47 + j*(169) -11 + j*(-429) --204 + j*(-11) --370 + j*(33) -401 + j*(-77) -74 + j*(186) -322 + j*(146) -57 + j*(-364) -18 + j*(-114) -171 + j*(-362) --86 + j*(66) -11 + j*(-148) --72 + j*(190) -185 + j*(-168) --73 + j*(-161) -182 + j*(18) --256 + j*(-304) --103 + j*(21) --41 + j*(358) --136 + j*(132) --18 + j*(-144) -267 + j*(102) -76 + j*(146) --5 + j*(-34) --105 + j*(29) --261 + j*(-179) --86 + j*(63) -106 + j*(280) --15 + j*(-155) -144 + j*(-52) --55 + j*(-344) -156 + j*(-20) -161 + j*(-242) -163 + j*(-223) --354 + j*(64) --5 + j*(-21) -20 + j*(-246) -210 + j*(-316) -396 + j*(-194) -16 + j*(225) --228 + j*(165) -46 + j*(21) --43 + j*(-298) --129 + j*(-132) --201 + j*(77) --32 + j*(21) --37 + j*(107) --16 + j*(94) -18 + j*(-93) -207 + j*(-175) -88 + j*(226) -216 + j*(-142) --170 + j*(102) -21 + j*(-291) -119 + j*(-173) --236 + j*(-33) -49 + j*(302) --151 + j*(136) --284 + j*(-181) -286 + j*(39) --70 + j*(160) --56 + j*(122) -5 + j*(320) --34 + j*(-181) --272 + j*(83) -33 + j*(-203) --248 + j*(-199) -146 + j*(255) --190 + j*(28) --60 + j*(-340) -13 + j*(-252) -134 + j*(269) -130 + j*(-115) -137 + j*(-25) -292 + j*(141) -171 + j*(82) -14 + j*(49) -11 + j*(23) --257 + j*(124) --130 + j*(-160) --247 + j*(164) --13 + j*(168) --62 + j*(-258) --11 + j*(-66) -291 + j*(274) -42 + j*(224) --135 + j*(266) --109 + j*(47) --37 + j*(-110) -84 + j*(-120) --73 + j*(322) --52 + j*(33) --139 + j*(24) -42 + j*(-132) -41 + j*(259) --45 + j*(165) -248 + j*(-201) --334 + j*(-131) --92 + j*(154) -202 + j*(7) -88 + j*(154) --100 + j*(42) --251 + j*(9) -129 + j*(-116) --187 + j*(82) -134 + j*(-412) --271 + j*(-181) --137 + j*(-20) --57 + j*(79) -136 + j*(95) -81 + j*(157) --100 + j*(107) --235 + j*(233) -117 + j*(-72) -388 + j*(-156) --147 + j*(-264) -0 + j*(-124) --18 + j*(156) --119 + j*(-114) --334 + j*(144) -206 + j*(303) -181 + j*(84) --198 + j*(-121) --146 + j*(91) --49 + j*(-77) -313 + j*(148) --241 + j*(57) -33 + j*(11) -161 + j*(-20) --76 + j*(158) -51 + j*(28) --106 + j*(67) --6 + j*(-136) --172 + j*(-97) -77 + j*(112) -0 + j*(59) -34 + j*(-29) -276 + j*(-67) --209 + j*(-214) -21 + j*(-59) -19 + j*(23) -35 + j*(-177) --221 + j*(242) -49 + j*(-40) -291 + j*(248) -220 + j*(57) --193 + j*(65) -129 + j*(101) --36 + j*(-160) --431 + j*(-53) --78 + j*(-492) -147 + j*(-326) --260 + j*(-37) -322 + j*(-134) --202 + j*(-203) -58 + j*(40) -45 + j*(-83) --66 + j*(-205) --130 + j*(-68) -122 + j*(47) -124 + j*(-115) --37 + j*(281) --276 + j*(-77) --188 + j*(379) -195 + j*(-42) --4 + j*(110) --288 + j*(-63) -1 + j*(-96) -69 + j*(-42) -100 + j*(173) --129 + j*(246) -311 + j*(-30) --71 + j*(-151) --368 + j*(-41) --347 + j*(190) --173 + j*(-92) --170 + j*(224) --40 + j*(-163) --103 + j*(90) -373 + j*(301) --206 + j*(55) --8 + j*(-184) -30 + j*(-18) --184 + j*(15) --132 + j*(103) -69 + j*(88) --115 + j*(-293) --318 + j*(124) -250 + j*(284) -33 + j*(-127) -193 + j*(317) --72 + j*(242) --32 + j*(122) --214 + j*(277) -78 + j*(-18) --173 + j*(-41) --135 + j*(-180) --31 + j*(-104) --22 + j*(278) -52 + j*(-16) -204 + j*(-62) --30 + j*(-24) -171 + j*(-48) --54 + j*(-339) --84 + j*(91) --95 + j*(-288) -40 + j*(-330) --115 + j*(16) --451 + j*(-48) -119 + j*(99) --36 + j*(135) -200 + j*(144) -127 + j*(-43) -252 + j*(91) -105 + j*(218) -29 + j*(176) -139 + j*(-190) --108 + j*(-139) -144 + j*(-76) -120 + j*(214) -47 + j*(228) --42 + j*(-4) -279 + j*(3) --140 + j*(-100) --16 + j*(49) --148 + j*(-21) -102 + j*(-150) --48 + j*(-264) --204 + j*(-53) -207 + j*(81) --272 + j*(-115) --28 + j*(-252) --61 + j*(-4) --114 + j*(116) -64 + j*(182) -131 + j*(101) -117 + j*(-1) -148 + j*(-296) -99 + j*(248) -112 + j*(-18) -198 + j*(306) --63 + j*(13) --226 + j*(-149) -93 + j*(121) --233 + j*(140) --156 + j*(-279) --182 + j*(-107) --117 + j*(-240) --209 + j*(36) -32 + j*(-31) -257 + j*(-126) --320 + j*(94) -25 + j*(-454) --35 + j*(81) --132 + j*(170) --161 + j*(230) -365 + j*(304) --53 + j*(-175) -101 + j*(165) -242 + j*(301) -113 + j*(190) -164 + j*(-160) -25 + j*(-512) -343 + j*(31) --228 + j*(4) -185 + j*(-76) --13 + j*(272) -69 + j*(6) -45 + j*(-23) -3 + j*(135) --240 + j*(-105) -124 + j*(143) --40 + j*(-218) --35 + j*(-109) --23 + j*(-3) --96 + j*(-139) -93 + j*(240) --193 + j*(-181) --45 + j*(80) -165 + j*(-144) --176 + j*(-94) --85 + j*(-242) --100 + j*(-11) --73 + j*(181) --6 + j*(-151) -98 + j*(109) --223 + j*(101) --279 + j*(58) -81 + j*(86) -14 + j*(102) -56 + j*(-215) --228 + j*(-92) --165 + j*(-62) -262 + j*(52) --40 + j*(-160) --183 + j*(-139) -226 + j*(-66) --107 + j*(184) -115 + j*(-64) --129 + j*(139) -90 + j*(-296) --88 + j*(-1) --81 + j*(-83) -78 + j*(-35) -68 + j*(-37) --86 + j*(-149) --1 + j*(84) --124 + j*(-24) --319 + j*(-315) --105 + j*(-221) --185 + j*(77) --211 + j*(28) --58 + j*(-169) -59 + j*(-424) -97 + j*(222) --82 + j*(216) -170 + j*(-109) -185 + j*(6) --328 + j*(202) --128 + j*(-71) --34 + j*(-259) -23 + j*(409) --218 + j*(55) -55 + j*(-269) --49 + j*(368) -62 + j*(131) -15 + j*(29) -79 + j*(349) -9 + j*(-190) --188 + j*(232) -194 + j*(153) -74 + j*(291) --152 + j*(119) -148 + j*(-206) --110 + j*(-170) -194 + j*(-139) -113 + j*(-100) --209 + j*(-302) -2 + j*(64) --128 + j*(-59) -13 + j*(-122) -7 + j*(-200) -25 + j*(-101) -104 + j*(-127) -168 + j*(-125) -93 + j*(-216) --91 + j*(-49) --179 + j*(-68) --95 + j*(117) -267 + j*(-81) --48 + j*(-41) --122 + j*(-340) --91 + j*(216) -104 + j*(142) --69 + j*(-206) --82 + j*(-101) --93 + j*(136) -6 + j*(-57) --51 + j*(-202) -53 + j*(-167) --127 + j*(-216) --292 + j*(-243) -170 + j*(-228) --241 + j*(-90) --132 + j*(-216) --81 + j*(-295) --40 + j*(96) --180 + j*(-167) --404 + j*(42) --64 + j*(-373) --190 + j*(100) -75 + j*(-219) -430 + j*(219) --23 + j*(-146) --93 + j*(25) -18 + j*(257) --28 + j*(303) --209 + j*(261) -748 + j*(271) -177 + j*(154) -352 + j*(577) --202 + j*(-223) --177 + j*(11) -327 + j*(256) -346 + j*(-228) --372 + j*(398) -354 + j*(666) -399 + j*(-1) -406 + j*(-42) -105 + j*(-37) --281 + j*(523) --76 + j*(-529) -675 + j*(81) --245 + j*(418) -333 + j*(275) --395 + j*(136) --63 + j*(338) --166 + j*(-158) --139 + j*(-445) --238 + j*(407) --342 + j*(-115) --323 + j*(101) --547 + j*(289) -329 + j*(117) --255 + j*(-172) -375 + j*(-109) --52 + j*(-234) -643 + j*(-313) --18 + j*(258) -11 + j*(168) --12 + j*(15) -351 + j*(-247) --199 + j*(334) -387 + j*(21) --126 + j*(63) --375 + j*(263) -23 + j*(206) -31 + j*(261) --211 + j*(334) -633 + j*(210) --194 + j*(-467) -335 + j*(-243) -368 + j*(-135) -542 + j*(-241) --190 + j*(-300) --18 + j*(-262) -279 + j*(-42) --548 + j*(-407) -107 + j*(-480) -318 + j*(274) --220 + j*(-252) -142 + j*(66) --156 + j*(290) --474 + j*(320) -602 + j*(255) --226 + j*(187) --403 + j*(-288) --443 + j*(-303) -159 + j*(-513) --480 + j*(-58) -263 + j*(-127) --346 + j*(537) -187 + j*(-350) --146 + j*(336) --175 + j*(-127) -250 + j*(532) -317 + j*(173) --38 + j*(-279) -339 + j*(-542) -168 + j*(-103) -606 + j*(-121) -128 + j*(-260) -132 + j*(-116) -487 + j*(497) --177 + j*(-310) --281 + j*(-375) --33 + j*(-250) --459 + j*(37) -13 + j*(-3) -206 + j*(-288) -167 + j*(-218) -225 + j*(163) --460 + j*(-350) --422 + j*(-256) --273 + j*(-288) -145 + j*(-539) -264 + j*(675) --177 + j*(-416) --278 + j*(92) -256 + j*(93) --11 + j*(122) -119 + j*(205) -264 + j*(-350) -267 + j*(320) -628 + j*(115) --300 + j*(206) --256 + j*(127) -46 + j*(644) --257 + j*(174) -397 + j*(-358) -437 + j*(-221) --404 + j*(-392) --453 + j*(-234) -211 + j*(-168) --473 + j*(-173) -378 + j*(297) -206 + j*(280) --203 + j*(-341) --251 + j*(-229) -173 + j*(-60) --311 + j*(-156) -1 + j*(134) --24 + j*(-322) --291 + j*(-203) --424 + j*(127) -134 + j*(-62) --295 + j*(-141) --380 + j*(-233) --83 + j*(320) --169 + j*(171) --419 + j*(263) -219 + j*(-126) --227 + j*(221) --533 + j*(-33) -139 + j*(162) --259 + j*(81) --77 + j*(-316) --334 + j*(368) -78 + j*(-279) --127 + j*(-14) -186 + j*(-54) --317 + j*(-562) -127 + j*(424) -23 + j*(241) --170 + j*(-218) -533 + j*(511) --530 + j*(-110) --246 + j*(576) -151 + j*(-443) -38 + j*(358) --462 + j*(-40) --293 + j*(386) -403 + j*(404) -465 + j*(126) --39 + j*(220) -546 + j*(-482) -187 + j*(267) --166 + j*(-417) -293 + j*(-158) -190 + j*(-276) -291 + j*(-456) --256 + j*(177) -236 + j*(83) --21 + j*(566) --309 + j*(-536) --276 + j*(274) -291 + j*(30) -316 + j*(480) -471 + j*(114) --284 + j*(197) -344 + j*(-291) --263 + j*(-347) -81 + j*(33) --381 + j*(-364) -49 + j*(-97) -300 + j*(516) -303 + j*(-48) -192 + j*(499) -115 + j*(-372) -387 + j*(-398) -264 + j*(2) --104 + j*(286) -643 + j*(-144) -327 + j*(447) -33 + j*(-457) --221 + j*(-59) --251 + j*(37) -300 + j*(4) -245 + j*(77) --199 + j*(-344) --103 + j*(16) --275 + j*(596) -226 + j*(-307) --321 + j*(379) -151 + j*(237) -403 + j*(-258) -292 + j*(-358) -728 + j*(378) -204 + j*(601) --392 + j*(-49) -205 + j*(56) --96 + j*(143) --361 + j*(270) -132 + j*(159) -342 + j*(156) -171 + j*(262) -252 + j*(55) -205 + j*(-261) -272 + j*(-192) -225 + j*(139) --375 + j*(241) --179 + j*(325) --121 + j*(-150) -178 + j*(-279) -532 + j*(-95) --397 + j*(361) -149 + j*(-227) --253 + j*(-415) --622 + j*(-208) --309 + j*(369) -305 + j*(361) -224 + j*(394) -385 + j*(617) --238 + j*(-120) -524 + j*(-277) --209 + j*(-190) -387 + j*(658) -405 + j*(211) -45 + j*(333) --313 + j*(137) --313 + j*(-31) -492 + j*(320) -138 + j*(-307) --240 + j*(364) -316 + j*(204) -177 + j*(-408) -204 + j*(-63) -358 + j*(-165) --47 + j*(-238) -425 + j*(361) -596 + j*(-56) -409 + j*(-180) --61 + j*(-536) --389 + j*(262) --337 + j*(-270) --185 + j*(-47) --414 + j*(-222) -394 + j*(200) -102 + j*(201) --581 + j*(-57) -312 + j*(118) -284 + j*(421) -171 + j*(242) -385 + j*(-218) -119 + j*(166) -408 + j*(484) -215 + j*(188) -269 + j*(434) -8 + j*(337) --308 + j*(514) -366 + j*(-49) -167 + j*(-166) -638 + j*(185) -344 + j*(-203) --331 + j*(174) -315 + j*(-16) -264 + j*(-185) --389 + j*(382) --76 + j*(-346) -284 + j*(221) -216 + j*(309) --296 + j*(-339) --290 + j*(89) -341 + j*(400) -126 + j*(-108) -267 + j*(288) --211 + j*(177) -355 + j*(-21) -522 + j*(255) -268 + j*(-234) -436 + j*(392) -703 + j*(57) --435 + j*(-436) -284 + j*(-130) --115 + j*(-286) --614 + j*(-284) --152 + j*(-368) -219 + j*(-30) -313 + j*(-261) --134 + j*(-260) --55 + j*(-498) --254 + j*(291) -196 + j*(-122) -318 + j*(334) --264 + j*(366) -13 + j*(-230) -314 + j*(609) -241 + j*(-139) --88 + j*(347) -323 + j*(-305) --443 + j*(-257) --231 + j*(300) --424 + j*(479) -320 + j*(543) -23 + j*(-188) --392 + j*(22) --497 + j*(93) --218 + j*(-392) --286 + j*(-441) --263 + j*(-591) --153 + j*(-87) --125 + j*(204) --385 + j*(54) -92 + j*(269) --45 + j*(46) --571 + j*(-607) --372 + j*(122) --384 + j*(19) -193 + j*(258) --22 + j*(377) --268 + j*(331) --184 + j*(425) -554 + j*(-243) --146 + j*(490) --168 + j*(-530) -180 + j*(38) --352 + j*(25) --334 + j*(57) --215 + j*(188) -57 + j*(89) -196 + j*(182) -397 + j*(491) --361 + j*(-99) -214 + j*(161) --84 + j*(346) -112 + j*(364) --244 + j*(346) --320 + j*(79) -406 + j*(93) --196 + j*(-371) -158 + j*(-298) -82 + j*(189) --342 + j*(-235) -202 + j*(-280) --194 + j*(-349) --197 + j*(-312) --291 + j*(-99) --171 + j*(283) -87 + j*(-41) --266 + j*(92) -595 + j*(573) --362 + j*(-139) -154 + j*(-235) -127 + j*(-603) -191 + j*(663) -387 + j*(-70) -275 + j*(505) -161 + j*(-393) -411 + j*(-243) --258 + j*(366) --273 + j*(35) --436 + j*(-470) -472 + j*(62) --401 + j*(75) -99 + j*(-165) -180 + j*(421) -270 + j*(-199) --52 + j*(-218) --260 + j*(-283) --527 + j*(277) --286 + j*(456) --444 + j*(97) --276 + j*(309) -132 + j*(-304) --231 + j*(-378) --245 + j*(153) -406 + j*(305) --338 + j*(229) -163 + j*(180) --281 + j*(290) -477 + j*(-118) --377 + j*(457) -169 + j*(-161) --347 + j*(-248) -291 + j*(-45) --157 + j*(60) -124 + j*(227) --281 + j*(-433) -513 + j*(-282) -333 + j*(235) -299 + j*(-273) -322 + j*(211) -391 + j*(402) -198 + j*(-60) --58 + j*(-472) -559 + j*(125) -130 + j*(334) --93 + j*(245) -471 + j*(-211) -93 + j*(276) -36 + j*(-378) -780 + j*(281) --291 + j*(301) -286 + j*(334) -227 + j*(-363) -351 + j*(163) -194 + j*(98) --512 + j*(317) --47 + j*(197) --325 + j*(393) -122 + j*(9) --264 + j*(-231) -339 + j*(141) --274 + j*(-426) -330 + j*(-318) -625 + j*(-276) --372 + j*(406) --253 + j*(-171) --314 + j*(-271) -159 + j*(161) -264 + j*(-505) --280 + j*(563) -326 + j*(3) -235 + j*(78) -66 + j*(-384) -368 + j*(156) --227 + j*(-17) --409 + j*(-381) --252 + j*(-306) -108 + j*(218) --433 + j*(-35) -16 + j*(23) -648 + j*(-353) -296 + j*(47) --291 + j*(360) -408 + j*(-459) -530 + j*(156) -175 + j*(262) -8 + j*(-363) -57 + j*(221) -142 + j*(161) --162 + j*(72) -185 + j*(-160) -280 + j*(-128) --272 + j*(-232) -31 + j*(-88) --626 + j*(-132) -122 + j*(-325) --274 + j*(126) --312 + j*(206) -231 + j*(37) --261 + j*(-124) -86 + j*(450) --328 + j*(-586) --175 + j*(-283) -25 + j*(-170) -340 + j*(372) -385 + j*(181) -354 + j*(-480) --204 + j*(30) --368 + j*(273) --315 + j*(204) --453 + j*(269) --433 + j*(173) -532 + j*(258) -351 + j*(-124) --26 + j*(-1) -208 + j*(83) -84 + j*(141) --620 + j*(-32) --229 + j*(34) --146 + j*(-315) --143 + j*(-223) --135 + j*(375) -421 + j*(345) -498 + j*(-307) -425 + j*(-670) -315 + j*(613) --361 + j*(253) -470 + j*(-390) --8 + j*(132) --173 + j*(74) --375 + j*(317) -278 + j*(-225) --247 + j*(156) --371 + j*(-346) --366 + j*(-146) -417 + j*(-374) -27 + j*(-231) -462 + j*(311) --147 + j*(385) -433 + j*(-363) --347 + j*(-521) --345 + j*(206) --503 + j*(473) -238 + j*(-395) -159 + j*(-239) --163 + j*(189) --468 + j*(-154) --351 + j*(-30) --271 + j*(491) -277 + j*(94) --4 + j*(-162) -331 + j*(-389) --246 + j*(496) -165 + j*(330) -453 + j*(257) --64 + j*(-125) --544 + j*(-247) -135 + j*(-176) --383 + j*(-524) --16 + j*(693) --104 + j*(189) -139 + j*(110) -525 + j*(236) -172 + j*(-342) -313 + j*(223) -307 + j*(-435) --525 + j*(-231) -317 + j*(-317) --525 + j*(-696) -245 + j*(-131) --568 + j*(-351) -71 + j*(-274) --57 + j*(95) --313 + j*(-417) -250 + j*(-74) -338 + j*(-238) -270 + j*(-151) --166 + j*(437) --414 + j*(460) --285 + j*(304) --274 + j*(511) -408 + j*(-422) -25 + j*(-37) --370 + j*(107) -367 + j*(146) --135 + j*(-324) --329 + j*(180) -163 + j*(-82) --568 + j*(185) --496 + j*(-288) --416 + j*(-366) -37 + j*(-95) -70 + j*(-424) -88 + j*(38) --277 + j*(87) --44 + j*(404) --184 + j*(-651) --304 + j*(-487) --301 + j*(-136) --36 + j*(-501) -416 + j*(104) -130 + j*(-443) -127 + j*(-177) -387 + j*(-144) --186 + j*(6) --333 + j*(-57) --101 + j*(-190) -450 + j*(161) -85 + j*(-147) -442 + j*(-466) --52 + j*(-173) -45 + j*(13) -289 + j*(96) -148 + j*(461) --49 + j*(330) --6 + j*(-279) --44 + j*(152) -279 + j*(-176) -404 + j*(178) -239 + j*(297) --267 + j*(449) --371 + j*(-45) --206 + j*(-267) -144 + j*(-57) --352 + j*(199) -249 + j*(472) --87 + j*(136) --147 + j*(-480) -442 + j*(397) --30 + j*(129) --322 + j*(417) -818 + j*(11) --14 + j*(338) --257 + j*(-72) -352 + j*(-235) --411 + j*(82) -348 + j*(-66) -50 + j*(257) --315 + j*(103) --394 + j*(-30) --274 + j*(336) --436 + j*(-178) --147 + j*(-202) -173 + j*(264) --167 + j*(-347) --430 + j*(-67) -229 + j*(-447) --255 + j*(771) -29 + j*(-579) -412 + j*(208) -385 + j*(-573) --523 + j*(-310) --513 + j*(-223) -148 + j*(-237) --70 + j*(127) --346 + j*(12) --245 + j*(-208) --146 + j*(204) --216 + j*(23) -4 + j*(87) --163 + j*(274) --146 + j*(-27) --74 + j*(250) --97 + j*(69) -18 + j*(85) --33 + j*(-192) --84 + j*(-299) -15 + j*(32) -182 + j*(-194) -30 + j*(-209) --151 + j*(-126) -315 + j*(-103) --146 + j*(-21) -79 + j*(168) -535 + j*(44) -169 + j*(-331) --139 + j*(229) --192 + j*(55) --84 + j*(-47) -221 + j*(78) --83 + j*(-228) -86 + j*(-13) --165 + j*(58) --315 + j*(72) --57 + j*(-23) -16 + j*(-209) --50 + j*(-103) --206 + j*(-19) -36 + j*(-36) --78 + j*(-187) --224 + j*(173) -172 + j*(29) -284 + j*(66) -155 + j*(194) -14 + j*(28) -144 + j*(-105) --102 + j*(-113) --132 + j*(-83) -15 + j*(-325) -40 + j*(-86) -203 + j*(-185) -64 + j*(115) -427 + j*(-47) -20 + j*(40) --71 + j*(127) -238 + j*(44) -112 + j*(-142) -39 + j*(-171) -122 + j*(-204) -62 + j*(-64) --33 + j*(-149) --170 + j*(106) -296 + j*(52) -332 + j*(279) -203 + j*(70) -286 + j*(76) --206 + j*(42) --11 + j*(298) -129 + j*(-209) -110 + j*(218) --17 + j*(-75) -198 + j*(15) -153 + j*(256) --6 + j*(-125) -71 + j*(-89) -64 + j*(-11) -80 + j*(-31) -192 + j*(112) --196 + j*(-18) --21 + j*(204) --54 + j*(305) -10 + j*(292) -30 + j*(238) --144 + j*(333) --230 + j*(-60) --354 + j*(76) -87 + j*(-45) -193 + j*(215) --170 + j*(204) -143 + j*(93) --206 + j*(231) -151 + j*(121) -323 + j*(-74) --132 + j*(-209) --150 + j*(-150) --153 + j*(-82) --243 + j*(-144) -310 + j*(95) -342 + j*(-61) --155 + j*(-117) -357 + j*(66) --360 + j*(119) -86 + j*(-33) -209 + j*(40) --105 + j*(62) -163 + j*(43) --58 + j*(56) -134 + j*(-247) -14 + j*(84) --105 + j*(-28) --193 + j*(-215) --51 + j*(-180) -97 + j*(-98) --116 + j*(-25) -422 + j*(107) -105 + j*(62) --30 + j*(62) -255 + j*(141) --247 + j*(240) -23 + j*(25) --163 + j*(6) -0 + j*(308) --115 + j*(-250) --83 + j*(-33) --345 + j*(-57) -495 + j*(-29) -148 + j*(-51) --203 + j*(144) --57 + j*(39) --52 + j*(283) --7 + j*(218) -300 + j*(-182) -274 + j*(202) -59 + j*(13) --74 + j*(259) -300 + j*(28) -1 + j*(117) -151 + j*(242) -267 + j*(332) -57 + j*(-315) -38 + j*(-178) -65 + j*(8) --144 + j*(-271) -213 + j*(-199) -151 + j*(-91) --252 + j*(-130) --93 + j*(-66) -74 + j*(69) --118 + j*(110) -293 + j*(187) -124 + j*(84) -211 + j*(-75) --40 + j*(-15) -123 + j*(28) -105 + j*(-295) -198 + j*(185) -76 + j*(74) --236 + j*(203) --81 + j*(1) --135 + j*(73) --333 + j*(-332) -46 + j*(64) --37 + j*(233) --17 + j*(37) -321 + j*(182) -146 + j*(307) -98 + j*(-2) --191 + j*(-138) --252 + j*(124) -168 + j*(-105) -28 + j*(343) --59 + j*(-71) --119 + j*(-351) -18 + j*(-82) -319 + j*(69) -140 + j*(-41) -278 + j*(301) --142 + j*(166) --189 + j*(-316) -173 + j*(-260) --26 + j*(-151) --94 + j*(-54) -10 + j*(23) -134 + j*(-170) --45 + j*(-260) -138 + j*(-59) -79 + j*(-220) -2 + j*(102) -163 + j*(74) --105 + j*(42) --295 + j*(-200) -184 + j*(-141) --216 + j*(246) --66 + j*(-23) -185 + j*(86) --378 + j*(146) --137 + j*(250) -233 + j*(190) --66 + j*(-220) --30 + j*(-128) -332 + j*(-71) -293 + j*(-6) --35 + j*(-1) --58 + j*(247) -252 + j*(-73) --75 + j*(-220) --57 + j*(6) --197 + j*(-8) -321 + j*(149) --308 + j*(141) -146 + j*(-230) --168 + j*(-322) --315 + j*(-190) -120 + j*(-298) -155 + j*(-344) --15 + j*(146) --156 + j*(-192) --91 + j*(-6) --62 + j*(-40) --40 + j*(109) --256 + j*(-19) -118 + j*(-350) --365 + j*(-211) --68 + j*(-100) --86 + j*(-320) -33 + j*(-34) -136 + j*(1) -7 + j*(430) -161 + j*(54) -30 + j*(-78) --87 + j*(-162) -282 + j*(269) --277 + j*(260) --10 + j*(404) -245 + j*(134) --96 + j*(-129) --183 + j*(83) --114 + j*(266) --3 + j*(-74) -115 + j*(77) -141 + j*(31) --105 + j*(50) --20 + j*(-341) -148 + j*(-116) -388 + j*(-106) --112 + j*(-20) -58 + j*(-6) -207 + j*(-138) -124 + j*(-84) --174 + j*(71) --79 + j*(321) --153 + j*(48) --171 + j*(-315) --115 + j*(19) --73 + j*(-77) --2 + j*(-59) -71 + j*(-69) -13 + j*(1) -129 + j*(-286) --316 + j*(162) -303 + j*(210) -32 + j*(136) --199 + j*(85) --248 + j*(169) -246 + j*(88) -309 + j*(-105) -83 + j*(-149) --46 + j*(-25) --194 + j*(-202) --88 + j*(-108) -76 + j*(29) -79 + j*(-213) --90 + j*(14) --88 + j*(106) --194 + j*(-71) --57 + j*(42) --478 + j*(-83) -269 + j*(-33) -180 + j*(25) --47 + j*(-96) --190 + j*(115) --10 + j*(-342) --144 + j*(-26) --264 + j*(4) --192 + j*(48) --303 + j*(117) --49 + j*(268) -95 + j*(-177) -419 + j*(69) --131 + j*(156) --170 + j*(-4) --8 + j*(-139) --42 + j*(185) -0 + j*(-301) -20 + j*(-200) -397 + j*(-147) --130 + j*(-238) --42 + j*(33) --78 + j*(12) --59 + j*(-111) --206 + j*(-145) --141 + j*(-148) --94 + j*(-163) -146 + j*(-16) -43 + j*(211) -202 + j*(244) --67 + j*(-282) -223 + j*(64) -65 + j*(194) --76 + j*(-1) -14 + j*(240) --51 + j*(136) --23 + j*(165) --44 + j*(64) -110 + j*(132) --153 + j*(-107) --20 + j*(-114) --226 + j*(-141) --103 + j*(4) --113 + j*(211) -153 + j*(-9) -252 + j*(-18) --115 + j*(-216) --83 + j*(295) -165 + j*(47) -66 + j*(-152) -194 + j*(88) --46 + j*(-30) -100 + j*(-37) -148 + j*(-224) -167 + j*(84) --174 + j*(-62) --333 + j*(-233) -250 + j*(-173) -325 + j*(-9) -36 + j*(-29) --85 + j*(20) -141 + j*(179) --13 + j*(15) --179 + j*(-415) --358 + j*(87) --236 + j*(236) -291 + j*(-188) --114 + j*(268) --187 + j*(-233) -62 + j*(-151) --139 + j*(-336) -301 + j*(-37) --75 + j*(74) -12 + j*(-259) --351 + j*(-17) -193 + j*(-151) --4 + j*(105) -206 + j*(5) --153 + j*(-107) -185 + j*(242) --5 + j*(-105) -20 + j*(14) -36 + j*(368) -37 + j*(139) -11 + j*(-123) --218 + j*(-71) --122 + j*(86) --95 + j*(95) --412 + j*(-148) --218 + j*(-69) --326 + j*(-87) --131 + j*(11) --11 + j*(84) -98 + j*(-194) --49 + j*(-99) -207 + j*(-170) --200 + j*(-292) --46 + j*(152) --144 + j*(-54) -196 + j*(268) -100 + j*(31) --132 + j*(157) --95 + j*(-239) -185 + j*(-6) --117 + j*(-161) -106 + j*(164) -122 + j*(48) --47 + j*(45) -47 + j*(83) -195 + j*(361) -68 + j*(207) -43 + j*(17) --120 + j*(-76) -1 + j*(-81) --138 + j*(-8) -1 + j*(-15) -10 + j*(-10) -30 + j*(37) --24 + j*(-55) --235 + j*(251) --16 + j*(236) -139 + j*(-286) -62 + j*(86) -183 + j*(-165) --71 + j*(-117) -57 + j*(-56) -71 + j*(-23) --518 + j*(52) -189 + j*(-45) -3 + j*(-190) -89 + j*(186) -36 + j*(-11) --308 + j*(283) -153 + j*(-55) -170 + j*(68) -16 + j*(-214) -141 + j*(223) -13 + j*(163) --99 + j*(197) --350 + j*(-84) -361 + j*(-123) --153 + j*(-35) -184 + j*(-101) --250 + j*(104) --256 + j*(147) --56 + j*(166) --67 + j*(-78) -1 + j*(-257) --173 + j*(-69) --109 + j*(-93) --17 + j*(71) -243 + j*(-110) -54 + j*(166) --80 + j*(-250) --134 + j*(-32) --169 + j*(-201) --98 + j*(-239) -339 + j*(-90) --11 + j*(-78) -25 + j*(45) -109 + j*(-8) -45 + j*(-274) --215 + j*(-130) --139 + j*(178) -213 + j*(-269) --202 + j*(-202) --221 + j*(-17) -219 + j*(-466) -87 + j*(-278) -358 + j*(-91) -5 + j*(169) --129 + j*(330) -42 + j*(0) --86 + j*(-29) --80 + j*(295) --154 + j*(-121) -76 + j*(233) -238 + j*(-31) -97 + j*(-160) -23 + j*(-81) -5 + j*(-187) --39 + j*(-139) --262 + j*(83) -128 + j*(23) --274 + j*(-51) -229 + j*(-56) -127 + j*(486) -104 + j*(112) --46 + j*(257) --210 + j*(-244) -81 + j*(111) -112 + j*(198) -231 + j*(319) --86 + j*(103) --7 + j*(-55) --6 + j*(-153) -139 + j*(141) -37 + j*(212) -56 + j*(346) -298 + j*(-73) --4 + j*(-55) -163 + j*(36) --46 + j*(229) -124 + j*(-144) --156 + j*(122) --209 + j*(-109) -117 + j*(-151) --235 + j*(-193) --38 + j*(-64) -136 + j*(28) -66 + j*(-388) --102 + j*(101) -171 + j*(182) --192 + j*(81) -251 + j*(-343) -261 + j*(-61) -88 + j*(-33) --158 + j*(408) -305 + j*(-63) --8 + j*(-103) -565 + j*(250) --128 + j*(-51) --211 + j*(-122) --115 + j*(170) -42 + j*(-29) --99 + j*(-112) --30 + j*(-85) -232 + j*(213) -282 + j*(-5) --86 + j*(113) --300 + j*(-236) --132 + j*(-146) --4 + j*(93) -99 + j*(215) --70 + j*(-24) --95 + j*(23) --104 + j*(-33) -237 + j*(-209) -190 + j*(-75) -15 + j*(73) -106 + j*(86) -3 + j*(-178) -148 + j*(-86) -105 + j*(209) -34 + j*(-276) -10 + j*(204) -135 + j*(-187) --57 + j*(-210) -69 + j*(93) --7 + j*(487) --141 + j*(-340) -33 + j*(13) -106 + j*(-265) -51 + j*(105) --247 + j*(-185) --168 + j*(-27) --46 + j*(-325) -79 + j*(139) --74 + j*(535) -245 + j*(-96) -334 + j*(-317) --103 + j*(159) --204 + j*(-19) -144 + j*(239) -36 + j*(-187) -98 + j*(-91) --249 + j*(-33) -9 + j*(-223) -326 + j*(-165) --135 + j*(-42) --125 + j*(-16) -15 + j*(-2) --243 + j*(-287) --33 + j*(182) --91 + j*(15) --81 + j*(-71) --194 + j*(-63) -37 + j*(-23) --138 + j*(-11) --54 + j*(100) -50 + j*(31) --43 + j*(115) --36 + j*(-128) -153 + j*(-170) -23 + j*(-226) --72 + j*(13) -130 + j*(-53) --259 + j*(93) --315 + j*(-78) --141 + j*(-96) -241 + j*(112) --54 + j*(159) -58 + j*(57) --355 + j*(63) -307 + j*(-132) -192 + j*(88) --240 + j*(15) --35 + j*(-6) -123 + j*(291) --161 + j*(158) -34 + j*(-92) -36 + j*(233) -302 + j*(-199) -71 + j*(56) --144 + j*(91) -131 + j*(276) --77 + j*(151) --110 + j*(214) -12 + j*(-490) --186 + j*(-77) -308 + j*(84) --203 + j*(3) -113 + j*(-112) --222 + j*(-176) -81 + j*(-112) -15 + j*(-14) --50 + j*(-186) -144 + j*(-47) --120 + j*(-125) -215 + j*(207) --32 + j*(-16) --383 + j*(247) --96 + j*(81) --148 + j*(-11) -48 + j*(148) -173 + j*(0) -79 + j*(390) -180 + j*(-223) -274 + j*(40) --153 + j*(47) --116 + j*(112) -121 + j*(255) -198 + j*(176) -74 + j*(134) --170 + j*(168) -91 + j*(129) -105 + j*(-324) --326 + j*(25) --109 + j*(74) -174 + j*(-59) --244 + j*(54) --314 + j*(279) --145 + j*(213) -238 + j*(103) -28 + j*(190) -46 + j*(-172) --28 + j*(-190) --122 + j*(-110) --112 + j*(-82) -298 + j*(-21) --171 + j*(83) -99 + j*(16) -143 + j*(71) --141 + j*(-247) --214 + j*(-83) --9 + j*(14) --66 + j*(-51) --175 + j*(-115) -233 + j*(-421) -117 + j*(54) -148 + j*(-204) --122 + j*(128) --4 + j*(20) --139 + j*(-47) -105 + j*(-64) -21 + j*(-56) --144 + j*(-13) --238 + j*(-225) --97 + j*(139) --83 + j*(15) -45 + j*(80) --1 + j*(173) -260 + j*(141) --125 + j*(2) -117 + j*(100) -100 + j*(-3) -255 + j*(-33) --214 + j*(-199) -243 + j*(344) -85 + j*(158) --322 + j*(-165) --214 + j*(296) --128 + j*(58) --74 + j*(-222) --25 + j*(-93) -44 + j*(5) --63 + j*(-137) --160 + j*(-328) -29 + j*(12) --78 + j*(107) -142 + j*(238) -205 + j*(-250) --207 + j*(191) -165 + j*(-142) -199 + j*(141) -28 + j*(-93) --141 + j*(175) --177 + j*(148) -274 + j*(-18) --224 + j*(-92) -17 + j*(-247) -265 + j*(-45) --121 + j*(134) --66 + j*(-78) -253 + j*(-176) --52 + j*(86) --156 + j*(13) --239 + j*(-81) -51 + j*(-115) --134 + j*(36) --83 + j*(-69) --117 + j*(78) -145 + j*(91) -288 + j*(114) -6 + j*(136) -121 + j*(240) --60 + j*(37) -197 + j*(100) --275 + j*(78) -57 + j*(321) --260 + j*(170) -91 + j*(-288) --168 + j*(-164) --171 + j*(-35) --136 + j*(344) -43 + j*(3) --206 + j*(168) --343 + j*(124) --222 + j*(-301) -98 + j*(146) --30 + j*(-252) -203 + j*(-21) --42 + j*(-90) -49 + j*(-36) --62 + j*(-53) --202 + j*(103) -2 + j*(53) -95 + j*(297) -67 + j*(-303) -183 + j*(-70) --399 + j*(74) --272 + j*(-213) --167 + j*(158) -68 + j*(-21) --180 + j*(77) -25 + j*(-18) --57 + j*(-4) -136 + j*(-37) -215 + j*(-322) -322 + j*(34) --122 + j*(-172) -185 + j*(264) --144 + j*(247) -5 + j*(-125) -36 + j*(-313) -189 + j*(5) -140 + j*(-150) -7 + j*(69) --113 + j*(11) -190 + j*(368) --284 + j*(-105) --62 + j*(5) --132 + j*(-367) --225 + j*(-90) -50 + j*(-269) -134 + j*(243) --141 + j*(-52) --226 + j*(53) -342 + j*(-53) -93 + j*(-263) --92 + j*(-141) -125 + j*(162) --123 + j*(66) -42 + j*(49) --93 + j*(-114) --92 + j*(-310) --271 + j*(-95) -114 + j*(-197) -322 + j*(158) --43 + j*(28) --215 + j*(-171) -173 + j*(204) -332 + j*(213) -94 + j*(67) -328 + j*(23) -392 + j*(-35) -155 + j*(-135) -3 + j*(315) --211 + j*(50) -226 + j*(-136) --25 + j*(-26) --126 + j*(78) --107 + j*(-45) -24 + j*(227) --100 + j*(100) -260 + j*(22) --76 + j*(390) --288 + j*(49) -66 + j*(110) --163 + j*(-91) --273 + j*(-385) -28 + j*(-218) --231 + j*(156) -47 + j*(-76) -75 + j*(-82) --43 + j*(133) -3 + j*(-226) --69 + j*(-83) -231 + j*(-101) --290 + j*(-52) -47 + j*(57) --200 + j*(89) --70 + j*(265) -55 + j*(-255) --156 + j*(127) -91 + j*(337) --3 + j*(163) --129 + j*(-339) --16 + j*(167) --245 + j*(291) --114 + j*(168) --84 + j*(-148) --7 + j*(-243) --47 + j*(-44) -166 + j*(50) -227 + j*(-92) -215 + j*(291) -149 + j*(35) --109 + j*(-145) --190 + j*(-100) --102 + j*(-8) -230 + j*(169) -16 + j*(58) -133 + j*(-169) --16 + j*(291) -267 + j*(72) -84 + j*(52) --342 + j*(73) --101 + j*(228) --16 + j*(180) --2 + j*(122) -3 + j*(-344) --93 + j*(-185) -38 + j*(92) -226 + j*(71) -390 + j*(-98) -179 + j*(-201) --180 + j*(-31) --40 + j*(-165) -109 + j*(-119) -105 + j*(-171) --322 + j*(313) --1 + j*(-18) --47 + j*(256) -282 + j*(-29) --383 + j*(-225) -284 + j*(16) -81 + j*(244) -252 + j*(279) -257 + j*(-23) --491 + j*(254) --102 + j*(175) --46 + j*(269) -102 + j*(91) -5 + j*(123) -55 + j*(69) -29 + j*(105) --197 + j*(4) --84 + j*(226) --12 + j*(95) --57 + j*(-259) -195 + j*(-243) -134 + j*(133) -25 + j*(-165) --71 + j*(-205) -91 + j*(-71) --201 + j*(18) --135 + j*(-405) -180 + j*(153) -323 + j*(276) -376 + j*(73) -221 + j*(65) --231 + j*(236) -164 + j*(156) -238 + j*(97) --18 + j*(-199) -144 + j*(-33) --231 + j*(33) --23 + j*(154) -50 + j*(24) --145 + j*(-113) -32 + j*(138) -110 + j*(-121) -168 + j*(-242) -233 + j*(20) -30 + j*(87) -115 + j*(-67) -221 + j*(-12) -23 + j*(64) -66 + j*(161) --91 + j*(-159) --98 + j*(158) --73 + j*(49) --74 + j*(-26) --209 + j*(76) -280 + j*(88) -1 + j*(-30) -474 + j*(136) --39 + j*(-202) -61 + j*(-49) --82 + j*(-31) --25 + j*(267) -110 + j*(286) --257 + j*(-42) -288 + j*(-35) -16 + j*(324) -449 + j*(-50) --169 + j*(190) -108 + j*(-13) --151 + j*(33) --21 + j*(119) -82 + j*(-81) -132 + j*(-28) --413 + j*(-19) --295 + j*(-208) -153 + j*(145) --7 + j*(194) --110 + j*(-147) --145 + j*(-126) -284 + j*(64) --81 + j*(110) -263 + j*(-72) -12 + j*(-312) --76 + j*(119) -154 + j*(52) -138 + j*(109) --98 + j*(-220) --433 + j*(-9) -267 + j*(-3) --168 + j*(203) -33 + j*(-329) -129 + j*(-35) --177 + j*(-58) --161 + j*(-55) --161 + j*(108) --168 + j*(320) --258 + j*(65) --165 + j*(30) --131 + j*(-6) --98 + j*(25) -136 + j*(410) -1 + j*(332) -6 + j*(117) --42 + j*(-151) --15 + j*(-139) -292 + j*(-97) -208 + j*(-216) -113 + j*(-93) -168 + j*(160) --261 + j*(88) -226 + j*(110) -70 + j*(-298) --221 + j*(312) -54 + j*(101) --108 + j*(166) -306 + j*(162) -75 + j*(52) --129 + j*(-223) -47 + j*(59) -235 + j*(75) --226 + j*(45) -238 + j*(91) -324 + j*(168) -132 + j*(-354) --504 + j*(151) -234 + j*(112) -236 + j*(179) --25 + j*(-47) -136 + j*(-141) -311 + j*(352) -20 + j*(-145) -61 + j*(-187) -146 + j*(-66) --111 + j*(-25) -238 + j*(-6) --248 + j*(-57) -255 + j*(169) -368 + j*(-76) -13 + j*(7) --101 + j*(33) -1 + j*(227) --243 + j*(-105) --4 + j*(59) -118 + j*(38) --23 + j*(57) -85 + j*(-116) --170 + j*(-131) --13 + j*(-11) -49 + j*(-61) --37 + j*(294) -118 + j*(308) --120 + j*(-21) --232 + j*(-107) -393 + j*(312) -25 + j*(76) -74 + j*(23) -59 + j*(-136) -306 + j*(86) --260 + j*(-314) -194 + j*(163) --199 + j*(257) --175 + j*(-257) --232 + j*(13) -240 + j*(-95) --155 + j*(-172) -361 + j*(-116) --132 + j*(-152) --110 + j*(71) --279 + j*(288) --4 + j*(-28) --12 + j*(154) -89 + j*(190) -104 + j*(42) --221 + j*(-151) --91 + j*(115) -162 + j*(-30) --471 + j*(-45) -225 + j*(-34) -161 + j*(199) -136 + j*(164) --116 + j*(87) --48 + j*(195) -74 + j*(156) --23 + j*(7) -204 + j*(166) --150 + j*(1) -19 + j*(79) -44 + j*(5) --161 + j*(76) -122 + j*(-240) -151 + j*(-18) --23 + j*(53) --227 + j*(97) --26 + j*(-221) --358 + j*(-142) -217 + j*(-240) --139 + j*(-170) -39 + j*(202) -55 + j*(-36) -122 + j*(-217) -65 + j*(242) -23 + j*(13) --46 + j*(-73) --81 + j*(-328) -131 + j*(-276) --136 + j*(186) -158 + j*(204) -100 + j*(-209) -35 + j*(43) -4 + j*(43) --263 + j*(6) --16 + j*(159) -316 + j*(139) -336 + j*(-135) --201 + j*(-235) --13 + j*(-197) -275 + j*(139) --188 + j*(13) --152 + j*(-9) --61 + j*(-177) --369 + j*(-195) -160 + j*(-98) -56 + j*(-1) --276 + j*(-13) -112 + j*(-183) --231 + j*(206) -42 + j*(-163) -76 + j*(-34) -25 + j*(-84) -62 + j*(-61) --258 + j*(-87) --145 + j*(169) --240 + j*(289) --204 + j*(-272) --191 + j*(-68) -45 + j*(91) --124 + j*(46) --261 + j*(-18) -144 + j*(340) --24 + j*(216) --7 + j*(-41) -239 + j*(52) --292 + j*(-157) -210 + j*(-414) --299 + j*(-11) -6 + j*(71) -226 + j*(-406) -27 + j*(187) --72 + j*(-43) --115 + j*(-215) -41 + j*(-39) -220 + j*(38) --158 + j*(-246) --24 + j*(-111) --69 + j*(126) -137 + j*(-32) --279 + j*(11) --98 + j*(-329) --38 + j*(68) --366 + j*(19) --94 + j*(-104) -197 + j*(-37) --93 + j*(34) --352 + j*(-19) -64 + j*(40) -165 + j*(-195) -37 + j*(42) --177 + j*(-74) --194 + j*(-129) -269 + j*(174) -55 + j*(-28) --56 + j*(-37) --309 + j*(-131) -69 + j*(-18) --173 + j*(-9) -122 + j*(-270) -64 + j*(-221) -197 + j*(66) --66 + j*(354) -1 + j*(133) --125 + j*(129) --255 + j*(-137) -180 + j*(106) --223 + j*(385) -335 + j*(42) --99 + j*(-32) -182 + j*(91) -213 + j*(29) -32 + j*(-33) --75 + j*(37) --109 + j*(-296) -134 + j*(99) --53 + j*(-76) -140 + j*(176) -248 + j*(-379) --76 + j*(-151) --132 + j*(-22) --116 + j*(110) --82 + j*(-76) --199 + j*(-174) -118 + j*(240) --144 + j*(13) --25 + j*(173) --230 + j*(-95) -125 + j*(182) --105 + j*(122) --101 + j*(195) -20 + j*(-121) -35 + j*(-342) --119 + j*(-385) --188 + j*(-165) --252 + j*(-393) --269 + j*(-127) --31 + j*(-12) -336 + j*(-78) --52 + j*(-105) --25 + j*(330) -11 + j*(149) --81 + j*(-163) --153 + j*(-223) -107 + j*(-33) --294 + j*(-106) --189 + j*(247) --218 + j*(-154) -99 + j*(-35) -127 + j*(-290) -404 + j*(-88) --135 + j*(268) -316 + j*(313) -206 + j*(161) --385 + j*(36) --17 + j*(266) -4 + j*(-23) --83 + j*(73) -0 + j*(116) -160 + j*(199) -178 + j*(-109) --69 + j*(-147) -125 + j*(59) -244 + j*(98) --146 + j*(197) -59 + j*(234) -218 + j*(386) -23 + j*(-74) -438 + j*(90) -259 + j*(55) -181 + j*(214) --38 + j*(-76) --182 + j*(55) --148 + j*(-138) --130 + j*(281) -125 + j*(-132) --90 + j*(-105) -183 + j*(255) --138 + j*(288) --165 + j*(-25) --207 + j*(427) -259 + j*(-175) -147 + j*(-359) -116 + j*(-28) --263 + j*(-146) --217 + j*(48) -9 + j*(-62) -77 + j*(-11) -61 + j*(-215) -35 + j*(66) -85 + j*(1) -6 + j*(-23) -161 + j*(37) --124 + j*(280) -111 + j*(-3) -26 + j*(233) --76 + j*(130) -15 + j*(-241) --78 + j*(-167) -44 + j*(-25) --167 + j*(205) --99 + j*(-188) --154 + j*(120) --61 + j*(11) -361 + j*(-10) -236 + j*(-204) -139 + j*(-104) --106 + j*(44) --40 + j*(99) --1 + j*(-134) --148 + j*(30) --134 + j*(54) --239 + j*(85) --275 + j*(-269) -90 + j*(-83) --225 + j*(-148) -332 + j*(-88) --47 + j*(424) --128 + j*(78) -163 + j*(69) --175 + j*(88) --146 + j*(243) -308 + j*(25) -301 + j*(26) -110 + j*(-218) --139 + j*(-78) -279 + j*(92) -161 + j*(252) --91 + j*(81) --100 + j*(11) --90 + j*(92) --98 + j*(-146) -404 + j*(216) -178 + j*(-197) --50 + j*(-149) -165 + j*(-58) -27 + j*(-303) -95 + j*(169) --108 + j*(52) -294 + j*(-26) --37 + j*(-3) --101 + j*(-292) -187 + j*(250) --71 + j*(339) -42 + j*(-67) --66 + j*(50) --37 + j*(-90) -93 + j*(56) -141 + j*(-18) -77 + j*(-32) -74 + j*(28) -248 + j*(223) -232 + j*(-345) -66 + j*(-51) -42 + j*(49) -54 + j*(113) -25 + j*(-40) --88 + j*(156) -52 + j*(-112) --214 + j*(325) -144 + j*(122) --170 + j*(147) --251 + j*(33) --195 + j*(-218) -433 + j*(224) --174 + j*(-269) --75 + j*(-378) --30 + j*(-155) -227 + j*(-212) --1 + j*(-420) --45 + j*(331) -139 + j*(-228) -114 + j*(438) -313 + j*(-54) --460 + j*(-39) -125 + j*(-170) -222 + j*(-85) --127 + j*(-302) -97 + j*(279) -114 + j*(121) --226 + j*(144) -69 + j*(10) -162 + j*(-109) -206 + j*(-395) --243 + j*(-5) --86 + j*(294) -15 + j*(68) -206 + j*(-216) --190 + j*(151) --88 + j*(-41) -44 + j*(202) --36 + j*(-110) --35 + j*(16) --29 + j*(85) -0 + j*(155) --35 + j*(-83) -221 + j*(-148) -18 + j*(-342) --83 + j*(7) --8 + j*(-144) -9 + j*(-88) --103 + j*(-317) -191 + j*(187) --337 + j*(-266) --24 + j*(8) --515 + j*(-130) --129 + j*(142) -78 + j*(138) --70 + j*(264) -117 + j*(-196) -214 + j*(263) -45 + j*(-140) -127 + j*(-354) --16 + j*(-46) --6 + j*(-17) --69 + j*(-194) -8 + j*(315) -52 + j*(119) -243 + j*(65) -19 + j*(1) --163 + j*(-174) -124 + j*(-188) --438 + j*(25) -102 + j*(-9) -88 + j*(-352) -214 + j*(-132) -150 + j*(-23) --28 + j*(58) -52 + j*(-147) --59 + j*(332) --248 + j*(88) -47 + j*(138) -210 + j*(-60) -129 + j*(-173) --54 + j*(235) --190 + j*(284) --74 + j*(142) -73 + j*(-128) --46 + j*(-215) -126 + j*(328) --136 + j*(105) --32 + j*(-168) --313 + j*(-133) -59 + j*(-33) --39 + j*(158) -93 + j*(-158) --30 + j*(-192) -119 + j*(21) --8 + j*(180) -177 + j*(-231) -211 + j*(-264) -98 + j*(146) -46 + j*(13) --170 + j*(98) -93 + j*(18) --115 + j*(-21) --86 + j*(-20) -76 + j*(325) -77 + j*(33) -199 + j*(-40) -154 + j*(-236) --14 + j*(139) -37 + j*(65) --121 + j*(36) --206 + j*(247) --18 + j*(65) -573 + j*(148) -169 + j*(-257) --64 + j*(40) -53 + j*(-59) --46 + j*(88) --197 + j*(176) -18 + j*(-134) --177 + j*(-109) --76 + j*(142) -252 + j*(-144) --2 + j*(-101) -41 + j*(-153) --109 + j*(-24) -4 + j*(141) -49 + j*(-73) --151 + j*(134) --125 + j*(151) --78 + j*(272) -49 + j*(-177) --193 + j*(-143) --164 + j*(-261) -29 + j*(-115) -195 + j*(-140) -85 + j*(13) --86 + j*(27) --77 + j*(-128) -378 + j*(114) --436 + j*(49) --55 + j*(134) --144 + j*(-27) -99 + j*(315) -92 + j*(154) -148 + j*(177) -93 + j*(83) -119 + j*(310) -190 + j*(-248) --259 + j*(-248) -218 + j*(310) -63 + j*(197) -226 + j*(81) -22 + j*(-151) -60 + j*(-168) --285 + j*(231) --40 + j*(-78) -144 + j*(-128) --20 + j*(-402) -66 + j*(-8) --71 + j*(17) -94 + j*(-111) --22 + j*(-16) -128 + j*(-156) --212 + j*(324) --320 + j*(409) --137 + j*(235) -52 + j*(-438) -205 + j*(178) -86 + j*(-149) -246 + j*(-124) -129 + j*(-48) --23 + j*(72) -54 + j*(-18) --136 + j*(225) --134 + j*(198) -255 + j*(-239) --378 + j*(-39) --23 + j*(110) -35 + j*(-124) -47 + j*(-40) -177 + j*(-16) -178 + j*(-54) --197 + j*(33) -141 + j*(-42) -134 + j*(245) -68 + j*(101) --353 + j*(-16) --375 + j*(47) -129 + j*(-129) --75 + j*(-96) -192 + j*(66) -116 + j*(41) --33 + j*(17) -103 + j*(81) --52 + j*(214) -132 + j*(59) --342 + j*(375) --308 + j*(-103) --68 + j*(140) -460 + j*(110) --18 + j*(-97) -551 + j*(-522) -243 + j*(69) -534 + j*(264) --373 + j*(-374) --543 + j*(503) -292 + j*(223) -494 + j*(-12) --96 + j*(-122) -600 + j*(-210) -378 + j*(-357) -39 + j*(477) -298 + j*(82) --46 + j*(604) --197 + j*(28) --313 + j*(460) --57 + j*(168) -368 + j*(-167) --82 + j*(-532) -12 + j*(-259) --498 + j*(-542) -567 + j*(190) -18 + j*(-402) -675 + j*(32) --188 + j*(272) -778 + j*(51) -245 + j*(479) --82 + j*(-250) -342 + j*(-177) -360 + j*(-356) -279 + j*(286) --396 + j*(-656) -154 + j*(-335) --88 + j*(-243) -327 + j*(-137) -488 + j*(274) -322 + j*(-62) --43 + j*(507) -660 + j*(265) --264 + j*(81) --158 + j*(-299) --449 + j*(-491) -557 + j*(78) --6 + j*(-75) -569 + j*(135) -478 + j*(-146) --92 + j*(-381) --289 + j*(170) -276 + j*(-35) --373 + j*(-409) --288 + j*(-107) -173 + j*(-235) -286 + j*(-235) -236 + j*(-559) -52 + j*(164) --2 + j*(-477) -169 + j*(346) --322 + j*(-5) --154 + j*(151) -250 + j*(66) --477 + j*(79) -281 + j*(-82) -214 + j*(-72) -188 + j*(394) -146 + j*(-163) --297 + j*(292) -133 + j*(-588) -648 + j*(-378) -285 + j*(453) -377 + j*(-400) -441 + j*(349) -388 + j*(-69) -396 + j*(550) --27 + j*(-142) -446 + j*(361) -255 + j*(-25) -138 + j*(-252) -443 + j*(162) -471 + j*(-293) -309 + j*(359) -187 + j*(178) -359 + j*(-255) --251 + j*(292) --246 + j*(-288) --402 + j*(427) -77 + j*(211) --254 + j*(364) -123 + j*(-347) --223 + j*(-178) --245 + j*(-308) -392 + j*(192) --302 + j*(453) --384 + j*(-284) --161 + j*(-283) -117 + j*(-281) --272 + j*(274) --211 + j*(249) --530 + j*(-353) -204 + j*(471) -23 + j*(-124) --119 + j*(-276) --35 + j*(-373) -443 + j*(-426) --23 + j*(-441) -149 + j*(-441) --160 + j*(335) -224 + j*(-366) --166 + j*(81) -30 + j*(-435) -213 + j*(-171) -337 + j*(364) --301 + j*(121) -163 + j*(358) --417 + j*(255) --170 + j*(-19) -198 + j*(-239) -418 + j*(-470) -187 + j*(225) --338 + j*(-273) --581 + j*(87) -167 + j*(-600) --685 + j*(414) -351 + j*(-370) -6 + j*(-515) --279 + j*(-240) -45 + j*(-40) --130 + j*(233) --637 + j*(-235) --187 + j*(165) --135 + j*(386) -16 + j*(355) --219 + j*(8) -469 + j*(-107) -71 + j*(108) --16 + j*(15) --14 + j*(-530) --252 + j*(68) -288 + j*(536) -288 + j*(-182) --478 + j*(-6) --134 + j*(151) --38 + j*(-388) --414 + j*(-317) -440 + j*(-426) --218 + j*(-705) --304 + j*(-85) --662 + j*(54) -273 + j*(-4) -268 + j*(211) -18 + j*(315) -141 + j*(292) -116 + j*(268) --253 + j*(146) -235 + j*(-55) --259 + j*(-178) --197 + j*(-585) --64 + j*(441) --271 + j*(-188) -358 + j*(506) -13 + j*(-94) --339 + j*(-167) -329 + j*(400) -50 + j*(-484) -91 + j*(366) --407 + j*(-144) --439 + j*(165) -170 + j*(-325) --479 + j*(355) -237 + j*(-239) -99 + j*(-355) --122 + j*(281) -515 + j*(148) --132 + j*(-269) --174 + j*(34) -11 + j*(-386) -291 + j*(-351) -243 + j*(52) --300 + j*(129) -344 + j*(-442) --232 + j*(83) --10 + j*(2) -300 + j*(733) --139 + j*(28) -83 + j*(-425) --403 + j*(-188) --344 + j*(-337) -345 + j*(144) --245 + j*(-193) --552 + j*(105) -433 + j*(-513) -426 + j*(188) -12 + j*(385) --114 + j*(-211) --261 + j*(-512) -268 + j*(139) -327 + j*(305) -309 + j*(-86) -366 + j*(407) --206 + j*(277) --81 + j*(319) --21 + j*(108) -33 + j*(-84) -234 + j*(349) --337 + j*(759) -169 + j*(324) --183 + j*(333) -1 + j*(-487) -156 + j*(-346) -240 + j*(-270) -224 + j*(-426) --71 + j*(-328) -117 + j*(-204) -79 + j*(-344) --361 + j*(113) --165 + j*(332) --582 + j*(-463) -504 + j*(204) --578 + j*(139) --26 + j*(209) --121 + j*(378) --511 + j*(55) -156 + j*(-371) -12 + j*(-390) -231 + j*(-57) -11 + j*(-35) --498 + j*(-8) --465 + j*(-315) --45 + j*(-214) -245 + j*(53) --460 + j*(-199) --151 + j*(272) --453 + j*(-342) -194 + j*(8) --68 + j*(-393) --231 + j*(168) --364 + j*(-337) --414 + j*(-211) -701 + j*(-303) --287 + j*(-534) -201 + j*(140) -177 + j*(110) --54 + j*(-180) --344 + j*(-205) -280 + j*(53) -432 + j*(-19) -376 + j*(99) -363 + j*(509) -404 + j*(-474) --279 + j*(28) --496 + j*(74) -308 + j*(-384) -680 + j*(230) -620 + j*(-209) -295 + j*(444) -194 + j*(411) --185 + j*(-2) -546 + j*(317) --5 + j*(313) --415 + j*(229) -188 + j*(429) -247 + j*(617) --12 + j*(495) -175 + j*(312) --170 + j*(-268) --74 + j*(-233) --162 + j*(-310) --210 + j*(156) -395 + j*(-435) --184 + j*(268) --24 + j*(-264) -431 + j*(-350) --389 + j*(453) --98 + j*(-118) -117 + j*(531) --165 + j*(358) -74 + j*(-362) --304 + j*(61) --199 + j*(158) -228 + j*(167) -397 + j*(170) -266 + j*(-310) -450 + j*(93) --215 + j*(-63) --231 + j*(-31) -411 + j*(-336) -443 + j*(173) -288 + j*(240) -70 + j*(208) --298 + j*(-249) -349 + j*(279) --82 + j*(-6) --282 + j*(-40) -227 + j*(-322) -93 + j*(695) --433 + j*(392) -65 + j*(-356) --249 + j*(250) -297 + j*(-205) -107 + j*(363) -95 + j*(270) -310 + j*(-12) --228 + j*(532) -111 + j*(78) -227 + j*(-24) -141 + j*(-596) --252 + j*(409) --277 + j*(-249) --53 + j*(532) --173 + j*(-244) -519 + j*(402) -18 + j*(234) --135 + j*(307) --309 + j*(95) --289 + j*(264) -289 + j*(-284) -147 + j*(-311) --377 + j*(460) --298 + j*(549) -177 + j*(332) -599 + j*(-378) -40 + j*(355) -373 + j*(121) --266 + j*(-45) --85 + j*(-47) --186 + j*(-18) --8 + j*(-195) -409 + j*(-610) -34 + j*(502) --576 + j*(78) -298 + j*(164) -409 + j*(-331) -506 + j*(-433) -460 + j*(-700) --84 + j*(269) --303 + j*(375) --5 + j*(-106) -30 + j*(85) -296 + j*(361) --179 + j*(-178) --477 + j*(-308) --141 + j*(-696) --149 + j*(398) -392 + j*(431) --300 + j*(206) --248 + j*(515) -462 + j*(217) -253 + j*(244) -164 + j*(-196) -308 + j*(-40) -28 + j*(124) --172 + j*(-233) -471 + j*(-272) -332 + j*(445) --217 + j*(200) --307 + j*(-209) -503 + j*(207) -499 + j*(378) --203 + j*(87) --273 + j*(438) -170 + j*(364) -384 + j*(-122) -291 + j*(-509) --74 + j*(422) --571 + j*(126) -76 + j*(264) --383 + j*(-128) -333 + j*(-436) --105 + j*(-313) -260 + j*(-61) -404 + j*(465) --172 + j*(363) --225 + j*(-317) -185 + j*(-140) -132 + j*(40) --199 + j*(-365) -470 + j*(-37) -89 + j*(-250) --94 + j*(256) -0 + j*(397) --326 + j*(531) --245 + j*(-2) --105 + j*(-4) -100 + j*(274) --392 + j*(-227) --274 + j*(173) --93 + j*(-418) -646 + j*(214) --568 + j*(-668) -582 + j*(16) --129 + j*(-274) -272 + j*(226) --8 + j*(-176) -351 + j*(387) -467 + j*(194) --225 + j*(166) --40 + j*(-489) -82 + j*(-408) --168 + j*(268) --28 + j*(-298) --503 + j*(-358) -94 + j*(-250) -564 + j*(41) --468 + j*(-158) -331 + j*(311) -303 + j*(-211) -185 + j*(-366) --262 + j*(171) --165 + j*(-372) --414 + j*(-305) --334 + j*(-371) --62 + j*(26) -141 + j*(208) -250 + j*(347) --256 + j*(-16) --501 + j*(552) -452 + j*(-195) --239 + j*(-151) --426 + j*(-532) -10 + j*(-282) --412 + j*(414) --482 + j*(-233) --321 + j*(256) --124 + j*(32) -409 + j*(-373) --568 + j*(-613) --311 + j*(306) --81 + j*(-678) -432 + j*(-555) --374 + j*(376) -231 + j*(-211) -404 + j*(-189) -191 + j*(403) -511 + j*(-279) --544 + j*(202) -136 + j*(-401) -363 + j*(-269) --499 + j*(-64) -385 + j*(549) -243 + j*(250) --209 + j*(393) --231 + j*(-198) -272 + j*(-286) -133 + j*(-260) --366 + j*(-317) --76 + j*(25) --270 + j*(255) --267 + j*(118) --217 + j*(-233) -313 + j*(370) -282 + j*(-179) --513 + j*(120) --118 + j*(-400) -286 + j*(-403) --231 + j*(133) --175 + j*(-118) --161 + j*(-173) --118 + j*(411) --51 + j*(-93) --542 + j*(16) -233 + j*(-422) --13 + j*(-86) -345 + j*(-467) --296 + j*(-259) --23 + j*(-313) -74 + j*(476) -182 + j*(-244) --266 + j*(-231) --251 + j*(-226) --395 + j*(-360) --156 + j*(550) -217 + j*(163) --486 + j*(433) --281 + j*(248) --65 + j*(67) -232 + j*(-296) --383 + j*(-46) -403 + j*(99) -210 + j*(-325) --217 + j*(-564) --328 + j*(169) --196 + j*(132) --624 + j*(225) --480 + j*(200) --418 + j*(307) -367 + j*(-327) --365 + j*(-371) -422 + j*(-177) -296 + j*(-316) --284 + j*(-382) -414 + j*(163) --542 + j*(-593) -332 + j*(40) --100 + j*(368) -355 + j*(-380) -542 + j*(-166) -63 + j*(267) --427 + j*(293) --83 + j*(206) --610 + j*(45) -348 + j*(-95) -469 + j*(-153) -235 + j*(-150) --285 + j*(380) --399 + j*(-140) -247 + j*(-107) --556 + j*(472) --168 + j*(-3) --204 + j*(-325) -590 + j*(303) --222 + j*(228) -200 + j*(233) -524 + j*(-117) --57 + j*(257) --405 + j*(-373) --441 + j*(-124) -16 + j*(374) -306 + j*(-499) --36 + j*(-2) --103 + j*(-356) -378 + j*(214) --361 + j*(-255) --180 + j*(328) --267 + j*(-305) -204 + j*(-63) -45 + j*(-543) --134 + j*(-142) -321 + j*(508) --412 + j*(549) --240 + j*(182) --353 + j*(177) --138 + j*(-158) -165 + j*(-395) -234 + j*(-400) --256 + j*(373) -37 + j*(-249) -69 + j*(-151) --211 + j*(-291) --209 + j*(-90) --366 + j*(-367) -555 + j*(-146) --202 + j*(-583) --280 + j*(-259) -264 + j*(-309) -595 + j*(80) --318 + j*(-107) --306 + j*(96) -128 + j*(-289) -149 + j*(65) -265 + j*(-255) --399 + j*(-277) -325 + j*(-206) --368 + j*(122) -306 + j*(-187) --261 + j*(329) --223 + j*(-4) -443 + j*(477) --476 + j*(403) -112 + j*(-310) --124 + j*(93) --25 + j*(-349) -404 + j*(-98) --134 + j*(328) --289 + j*(-192) -151 + j*(137) -431 + j*(301) --76 + j*(-70) --161 + j*(-161) --590 + j*(-261) -276 + j*(291) -232 + j*(-365) --383 + j*(-45) -409 + j*(-97) --266 + j*(366) -433 + j*(-146) --308 + j*(18) -238 + j*(80) --52 + j*(299) --250 + j*(499) --395 + j*(358) --83 + j*(-467) -173 + j*(284) -43 + j*(-25) -97 + j*(293) --46 + j*(578) -245 + j*(-372) --127 + j*(197) --59 + j*(-461) -301 + j*(358) --95 + j*(205) --132 + j*(260) --337 + j*(286) --215 + j*(-344) --224 + j*(256) -748 + j*(-341) -402 + j*(-316) -264 + j*(-693) -18 + j*(115) -127 + j*(-64) --18 + j*(-102) --95 + j*(-594) -385 + j*(72) -73 + j*(11) --237 + j*(58) --177 + j*(-98) -117 + j*(-21) --536 + j*(173) -231 + j*(89) --290 + j*(-238) -176 + j*(-135) --293 + j*(50) -112 + j*(33) -73 + j*(-214) -89 + j*(-269) -62 + j*(6) --204 + j*(9) -49 + j*(17) -21 + j*(91) --170 + j*(49) --112 + j*(-310) --247 + j*(168) --28 + j*(221) -98 + j*(-145) -234 + j*(33) --22 + j*(-23) --81 + j*(148) -69 + j*(117) --144 + j*(-127) --62 + j*(4) -76 + j*(149) -76 + j*(-45) --6 + j*(61) -75 + j*(95) --105 + j*(-210) --378 + j*(-561) --334 + j*(86) -309 + j*(-91) -309 + j*(-67) -190 + j*(-124) -91 + j*(23) -8 + j*(-58) --235 + j*(-55) -57 + j*(-322) --93 + j*(133) --189 + j*(-179) -278 + j*(-37) -177 + j*(14) --4 + j*(-166) --71 + j*(-71) -310 + j*(-178) -107 + j*(-23) -153 + j*(55) --146 + j*(350) -17 + j*(70) --94 + j*(180) --69 + j*(181) --124 + j*(-424) --75 + j*(117) --124 + j*(-28) --194 + j*(-111) -45 + j*(58) -12 + j*(-58) -197 + j*(-82) -212 + j*(32) -144 + j*(179) --9 + j*(56) --200 + j*(-328) --64 + j*(70) --48 + j*(332) --71 + j*(-75) --189 + j*(-15) -35 + j*(143) --3 + j*(148) --158 + j*(-24) --69 + j*(165) -74 + j*(73) -149 + j*(-45) --30 + j*(-211) --195 + j*(158) --147 + j*(272) -69 + j*(-50) --73 + j*(54) --309 + j*(-164) --44 + j*(-103) --401 + j*(132) --271 + j*(104) --269 + j*(-28) --303 + j*(267) --21 + j*(281) --47 + j*(34) --164 + j*(-165) --110 + j*(241) --37 + j*(62) --40 + j*(-134) -2 + j*(19) -241 + j*(-375) --301 + j*(-67) -204 + j*(-37) -303 + j*(-142) --8 + j*(184) -60 + j*(-178) --158 + j*(238) -223 + j*(-71) -63 + j*(-277) -144 + j*(-3) --375 + j*(-45) --186 + j*(6) --36 + j*(-61) -46 + j*(-59) --22 + j*(191) --127 + j*(84) --202 + j*(-13) -519 + j*(253) --378 + j*(129) -16 + j*(176) -14 + j*(66) --198 + j*(341) --16 + j*(-180) -16 + j*(54) -42 + j*(49) -116 + j*(127) -60 + j*(-39) --100 + j*(-65) -94 + j*(-66) -126 + j*(150) -396 + j*(-101) --228 + j*(-126) -188 + j*(-42) --88 + j*(-210) --1 + j*(-69) -132 + j*(85) --140 + j*(28) --165 + j*(162) --105 + j*(129) --69 + j*(-122) --130 + j*(-45) --35 + j*(-15) --217 + j*(63) -24 + j*(-269) -67 + j*(103) --230 + j*(-104) -74 + j*(-202) --48 + j*(-80) --175 + j*(-81) --118 + j*(-93) --151 + j*(-15) -300 + j*(-88) --107 + j*(-209) -113 + j*(52) -3 + j*(162) --64 + j*(-366) --180 + j*(-201) -291 + j*(65) -56 + j*(-347) --21 + j*(28) -99 + j*(154) -119 + j*(5) --18 + j*(-43) -101 + j*(-66) -279 + j*(-172) -210 + j*(-234) -119 + j*(-100) -4 + j*(-65) --221 + j*(-33) -177 + j*(33) -289 + j*(240) --134 + j*(261) --474 + j*(50) -274 + j*(-269) -79 + j*(-84) --164 + j*(63) --103 + j*(151) -25 + j*(299) -87 + j*(67) --302 + j*(93) -378 + j*(22) -230 + j*(-15) -70 + j*(-76) -74 + j*(-161) --108 + j*(46) -52 + j*(-183) --117 + j*(20) -351 + j*(-247) -169 + j*(115) -143 + j*(-125) -122 + j*(-360) -173 + j*(199) -337 + j*(-138) --255 + j*(-175) -76 + j*(108) -256 + j*(-67) -184 + j*(-215) -103 + j*(303) -244 + j*(-360) --130 + j*(-75) -98 + j*(-192) --126 + j*(244) -249 + j*(-49) -331 + j*(-116) --232 + j*(-227) -205 + j*(50) --46 + j*(156) -274 + j*(153) --392 + j*(-40) --111 + j*(-1) -45 + j*(-269) -138 + j*(22) -238 + j*(172) --24 + j*(-80) -160 + j*(-28) --56 + j*(280) --26 + j*(-56) -73 + j*(42) -360 + j*(29) -142 + j*(-410) --126 + j*(107) --134 + j*(288) -42 + j*(414) --83 + j*(-246) -170 + j*(19) -1 + j*(-26) --31 + j*(-13) -113 + j*(40) -82 + j*(145) -139 + j*(362) --89 + j*(122) --133 + j*(-552) --269 + j*(-70) --29 + j*(-21) --161 + j*(-243) --134 + j*(-10) -16 + j*(117) -13 + j*(-63) --160 + j*(252) --27 + j*(77) --252 + j*(-119) --65 + j*(167) --71 + j*(259) -62 + j*(-130) --223 + j*(117) --58 + j*(-50) -132 + j*(-72) -21 + j*(157) -56 + j*(-150) --171 + j*(-102) --42 + j*(106) --66 + j*(21) --83 + j*(119) -158 + j*(252) --252 + j*(-111) --47 + j*(92) -46 + j*(-76) --199 + j*(39) --5 + j*(-91) --65 + j*(-152) -308 + j*(-76) -36 + j*(276) --144 + j*(-122) -382 + j*(330) -212 + j*(-305) --23 + j*(-304) --19 + j*(117) -150 + j*(-267) --317 + j*(-182) --100 + j*(33) --23 + j*(92) --258 + j*(-35) -70 + j*(-20) --83 + j*(-13) -138 + j*(98) -301 + j*(-17) -448 + j*(289) -126 + j*(176) -284 + j*(12) --176 + j*(-56) -320 + j*(144) --188 + j*(-220) --7 + j*(-40) -164 + j*(-198) -23 + j*(148) -260 + j*(184) --187 + j*(-52) --47 + j*(146) --234 + j*(-148) -66 + j*(141) -243 + j*(-199) --21 + j*(-17) -178 + j*(42) -204 + j*(93) -106 + j*(135) -14 + j*(88) -135 + j*(-242) --35 + j*(-99) --186 + j*(-61) --167 + j*(-122) --21 + j*(-138) --41 + j*(-13) --83 + j*(-98) -343 + j*(-217) -180 + j*(-9) --476 + j*(-114) --110 + j*(-219) --272 + j*(211) --47 + j*(-130) --395 + j*(-134) --200 + j*(54) --107 + j*(-376) -47 + j*(298) -84 + j*(-206) --355 + j*(115) -42 + j*(147) -211 + j*(119) -18 + j*(-42) --173 + j*(77) --40 + j*(259) --168 + j*(193) --167 + j*(-274) --182 + j*(-132) -45 + j*(124) -351 + j*(-177) -170 + j*(-41) -44 + j*(90) -183 + j*(-95) --361 + j*(60) --24 + j*(-53) -122 + j*(-78) --129 + j*(-28) --160 + j*(92) -35 + j*(83) --105 + j*(41) --86 + j*(-101) --228 + j*(120) --27 + j*(-172) -36 + j*(221) -58 + j*(217) -91 + j*(-128) --58 + j*(-247) --78 + j*(270) -221 + j*(-192) -267 + j*(66) -115 + j*(48) -200 + j*(33) -155 + j*(-253) -172 + j*(93) -260 + j*(-219) -241 + j*(-64) -21 + j*(309) -37 + j*(-251) -238 + j*(-236) --4 + j*(121) -38 + j*(-204) --116 + j*(-143) -349 + j*(137) -60 + j*(23) -174 + j*(-243) -169 + j*(-221) --192 + j*(-170) -124 + j*(-182) -43 + j*(-52) -209 + j*(223) -146 + j*(172) --155 + j*(64) -28 + j*(129) --118 + j*(232) -79 + j*(-8) --294 + j*(40) --414 + j*(-79) -45 + j*(234) -50 + j*(23) --139 + j*(61) -40 + j*(41) -88 + j*(-35) -94 + j*(11) --35 + j*(-146) -54 + j*(117) --107 + j*(5) --321 + j*(-30) --190 + j*(-89) -227 + j*(90) --72 + j*(-39) --107 + j*(-324) --117 + j*(71) --33 + j*(99) --82 + j*(-171) -75 + j*(-69) -33 + j*(151) --106 + j*(-52) -35 + j*(-5) --141 + j*(441) -48 + j*(62) -5 + j*(36) -2 + j*(136) -24 + j*(303) --137 + j*(-233) --249 + j*(241) -53 + j*(-79) -92 + j*(-265) -98 + j*(210) --89 + j*(166) --18 + j*(-91) --62 + j*(-67) -74 + j*(-53) -91 + j*(-283) -330 + j*(77) --16 + j*(-185) -293 + j*(47) --54 + j*(66) -17 + j*(28) --34 + j*(49) -190 + j*(-28) --161 + j*(287) --99 + j*(187) -5 + j*(34) -21 + j*(116) --105 + j*(335) --28 + j*(-32) --74 + j*(-55) -148 + j*(69) -37 + j*(-168) --233 + j*(42) --66 + j*(-16) -115 + j*(-319) -81 + j*(-20) -120 + j*(180) -114 + j*(346) -61 + j*(-107) -143 + j*(-15) -70 + j*(-122) --119 + j*(-272) --39 + j*(129) --163 + j*(103) -76 + j*(169) --243 + j*(-21) --145 + j*(-156) --211 + j*(-214) -127 + j*(340) -79 + j*(-57) --16 + j*(-45) --24 + j*(87) -161 + j*(52) --282 + j*(212) --62 + j*(91) --44 + j*(-33) -81 + j*(151) -69 + j*(68) -237 + j*(-74) --132 + j*(260) -143 + j*(-132) --11 + j*(-6) --49 + j*(88) --28 + j*(138) --341 + j*(6) -231 + j*(35) -88 + j*(81) --4 + j*(-156) -296 + j*(79) --458 + j*(51) -35 + j*(-387) --32 + j*(-234) -88 + j*(-45) --173 + j*(-64) --33 + j*(-172) --204 + j*(-99) --202 + j*(228) -105 + j*(-313) --60 + j*(-256) --104 + j*(-276) -222 + j*(-34) --1 + j*(-357) --98 + j*(-369) --129 + j*(-107) -344 + j*(312) --262 + j*(249) -108 + j*(-228) -364 + j*(-30) --10 + j*(83) --187 + j*(23) -330 + j*(249) -57 + j*(124) -317 + j*(-185) --100 + j*(34) -225 + j*(82) --36 + j*(-7) --25 + j*(71) --90 + j*(-27) --132 + j*(155) --106 + j*(-190) --29 + j*(403) --35 + j*(209) -66 + j*(-105) -137 + j*(-29) -84 + j*(238) --1 + j*(-75) --158 + j*(-138) --120 + j*(349) --66 + j*(-279) -127 + j*(-31) --247 + j*(42) -186 + j*(-256) --69 + j*(-107) -60 + j*(280) -237 + j*(190) --161 + j*(47) --104 + j*(173) -29 + j*(11) -59 + j*(177) --43 + j*(-9) --207 + j*(248) -115 + j*(-81) --122 + j*(57) -20 + j*(-103) --25 + j*(-41) --13 + j*(66) --169 + j*(23) -16 + j*(-243) --83 + j*(-59) -121 + j*(-153) --38 + j*(-99) -269 + j*(252) -303 + j*(-616) --87 + j*(218) --23 + j*(-52) -286 + j*(147) --146 + j*(28) -185 + j*(88) -181 + j*(88) -58 + j*(300) --59 + j*(-236) --152 + j*(-32) --132 + j*(-127) --42 + j*(62) -200 + j*(-16) -178 + j*(87) --10 + j*(-289) -85 + j*(-192) -373 + j*(92) --641 + j*(26) --253 + j*(-136) --87 + j*(38) -7 + j*(-527) -79 + j*(-31) -10 + j*(76) -235 + j*(-160) -78 + j*(-93) -346 + j*(-32) -45 + j*(-271) --30 + j*(269) -180 + j*(-45) --39 + j*(125) --256 + j*(206) --24 + j*(-163) -98 + j*(317) --194 + j*(-140) --76 + j*(-12) -523 + j*(-112) -392 + j*(28) -58 + j*(-8) --118 + j*(-94) --129 + j*(17) --217 + j*(18) -200 + j*(34) --261 + j*(-148) -43 + j*(284) --160 + j*(16) -332 + j*(67) -36 + j*(-7) -324 + j*(-185) --134 + j*(-88) --43 + j*(-363) -161 + j*(-263) --59 + j*(-300) --127 + j*(164) --178 + j*(123) --146 + j*(44) --39 + j*(-35) --131 + j*(-76) --23 + j*(-384) --112 + j*(-11) -86 + j*(177) -127 + j*(107) --75 + j*(-81) -198 + j*(50) -24 + j*(-1) --17 + j*(78) --223 + j*(-136) -257 + j*(152) --81 + j*(81) --128 + j*(255) --16 + j*(201) -16 + j*(187) --143 + j*(-303) --144 + j*(-173) -95 + j*(-123) --264 + j*(177) -449 + j*(-10) -65 + j*(21) --348 + j*(129) --72 + j*(-158) --283 + j*(43) -59 + j*(-156) -113 + j*(20) --1 + j*(115) -201 + j*(25) --91 + j*(-21) -46 + j*(140) --54 + j*(-143) -71 + j*(-136) --296 + j*(-75) --202 + j*(293) --51 + j*(202) --33 + j*(88) -231 + j*(-65) -165 + j*(23) --1 + j*(165) --47 + j*(51) --4 + j*(-314) --141 + j*(-169) -53 + j*(-211) -89 + j*(204) --105 + j*(-218) -61 + j*(-53) --143 + j*(-284) --11 + j*(-369) --54 + j*(-280) -189 + j*(250) --209 + j*(-136) --65 + j*(-126) -25 + j*(168) --137 + j*(165) -41 + j*(-85) -76 + j*(231) --229 + j*(-282) -45 + j*(122) --92 + j*(66) --80 + j*(-161) -57 + j*(-59) --95 + j*(-53) --37 + j*(-35) --20 + j*(103) --124 + j*(-59) --75 + j*(21) --260 + j*(-112) -132 + j*(-57) -183 + j*(6) -243 + j*(-146) -102 + j*(384) --172 + j*(-175) -21 + j*(-363) -192 + j*(-266) -52 + j*(-297) --293 + j*(155) -58 + j*(-263) -207 + j*(14) -62 + j*(-169) --152 + j*(250) -46 + j*(-74) -95 + j*(-74) --75 + j*(147) -29 + j*(8) --140 + j*(-167) -206 + j*(-33) -249 + j*(168) -47 + j*(38) -72 + j*(-209) -52 + j*(32) -123 + j*(294) -316 + j*(-170) --91 + j*(-158) --132 + j*(-92) -124 + j*(127) -215 + j*(110) -95 + j*(141) --309 + j*(-30) -231 + j*(-153) -165 + j*(-54) -71 + j*(-115) --250 + j*(-105) --8 + j*(-131) -251 + j*(214) --199 + j*(-33) -92 + j*(-49) -86 + j*(187) --441 + j*(-16) -303 + j*(46) -163 + j*(-116) -6 + j*(45) --53 + j*(209) -97 + j*(202) -371 + j*(-264) --113 + j*(-148) --70 + j*(-216) --23 + j*(123) --88 + j*(91) --146 + j*(96) -45 + j*(-79) --67 + j*(-41) -51 + j*(-138) --203 + j*(-65) --193 + j*(214) -91 + j*(187) --246 + j*(-214) --300 + j*(153) -21 + j*(-79) --18 + j*(-130) --165 + j*(256) -88 + j*(182) --160 + j*(105) -120 + j*(-272) -440 + j*(327) -98 + j*(3) --104 + j*(107) -215 + j*(84) -398 + j*(-12) -146 + j*(32) -343 + j*(6) --522 + j*(284) -105 + j*(8) -112 + j*(41) --263 + j*(84) --36 + j*(-168) -45 + j*(90) --111 + j*(-188) -1 + j*(83) --159 + j*(40) --345 + j*(59) --17 + j*(-190) --84 + j*(134) -201 + j*(-206) -46 + j*(-110) -136 + j*(-88) -144 + j*(92) --11 + j*(-25) --102 + j*(233) --190 + j*(285) -50 + j*(123) -112 + j*(102) -72 + j*(387) -14 + j*(-137) -33 + j*(111) --60 + j*(-201) --86 + j*(118) -52 + j*(259) -52 + j*(28) -73 + j*(-199) -284 + j*(215) -296 + j*(-136) --103 + j*(146) -1 + j*(49) -120 + j*(-55) -38 + j*(187) --581 + j*(158) -163 + j*(-325) --129 + j*(-29) -257 + j*(113) -135 + j*(250) --246 + j*(-14) --285 + j*(78) --181 + j*(-91) -311 + j*(0) -75 + j*(68) -18 + j*(-100) -144 + j*(43) -324 + j*(95) --107 + j*(69) --133 + j*(-156) --203 + j*(-366) --245 + j*(-175) -72 + j*(39) --6 + j*(-11) --67 + j*(179) --26 + j*(-18) --271 + j*(375) --201 + j*(-147) --57 + j*(-52) -139 + j*(-216) --93 + j*(54) -100 + j*(373) --148 + j*(33) --171 + j*(-137) --43 + j*(98) --4 + j*(-42) --115 + j*(213) -22 + j*(-251) --165 + j*(16) --177 + j*(-170) --275 + j*(184) --153 + j*(-170) --73 + j*(-168) -11 + j*(130) -48 + j*(121) -173 + j*(125) -1 + j*(37) -66 + j*(321) -365 + j*(-200) -240 + j*(107) -231 + j*(-123) --115 + j*(41) --211 + j*(16) --192 + j*(-125) --108 + j*(50) --66 + j*(-6) --8 + j*(-118) -81 + j*(68) -372 + j*(-31) --280 + j*(66) -105 + j*(16) --97 + j*(-85) --175 + j*(-276) --52 + j*(204) --220 + j*(64) --22 + j*(-260) --138 + j*(88) --86 + j*(-236) -0 + j*(13) -40 + j*(-56) --161 + j*(-40) --106 + j*(-194) --265 + j*(-81) -86 + j*(83) --48 + j*(7) -127 + j*(-83) -218 + j*(-228) -155 + j*(88) --195 + j*(288) --69 + j*(-33) --122 + j*(36) --195 + j*(-75) --36 + j*(127) --54 + j*(119) -95 + j*(-52) -18 + j*(-72) --44 + j*(-35) -39 + j*(105) -109 + j*(-2) --190 + j*(79) -171 + j*(301) -67 + j*(-164) -93 + j*(-250) -383 + j*(30) --233 + j*(148) -64 + j*(25) --22 + j*(-25) -73 + j*(160) -457 + j*(196) --23 + j*(6) -154 + j*(35) --78 + j*(-95) -18 + j*(-118) --17 + j*(100) -125 + j*(-159) --107 + j*(47) -18 + j*(342) --83 + j*(-453) -411 + j*(157) -83 + j*(-192) -143 + j*(-182) --266 + j*(-77) -124 + j*(-392) -94 + j*(-190) --200 + j*(261) --146 + j*(-107) -80 + j*(-24) --113 + j*(57) --4 + j*(87) -78 + j*(32) --257 + j*(-225) -252 + j*(98) -121 + j*(222) -20 + j*(15) --233 + j*(-42) --76 + j*(-408) --141 + j*(40) -146 + j*(-282) -52 + j*(-11) -88 + j*(-210) -93 + j*(157) -112 + j*(270) -45 + j*(34) -3 + j*(-139) -20 + j*(197) -86 + j*(-23) --154 + j*(-133) -98 + j*(-40) --356 + j*(-88) --159 + j*(-144) -235 + j*(289) -7 + j*(-182) --52 + j*(-290) -589 + j*(-199) --26 + j*(-64) -14 + j*(-146) --436 + j*(45) --8 + j*(339) --64 + j*(-50) --325 + j*(53) -83 + j*(223) --16 + j*(-254) -192 + j*(-69) -251 + j*(-84) -228 + j*(8) -114 + j*(163) --55 + j*(84) -10 + j*(-61) -193 + j*(84) --214 + j*(-66) --49 + j*(69) --231 + j*(-11) --22 + j*(-81) --199 + j*(90) -264 + j*(138) --331 + j*(71) -132 + j*(122) -147 + j*(7) --77 + j*(-69) -86 + j*(-34) --98 + j*(143) --408 + j*(153) -243 + j*(32) --192 + j*(45) -210 + j*(-25) -2 + j*(16) --516 + j*(-149) -80 + j*(-56) --145 + j*(54) -108 + j*(8) --151 + j*(59) --255 + j*(200) -28 + j*(30) --170 + j*(-214) --14 + j*(14) -221 + j*(3) --190 + j*(-98) --173 + j*(-229) --131 + j*(-164) -313 + j*(-194) -97 + j*(112) -222 + j*(-268) -13 + j*(-59) -117 + j*(-142) -172 + j*(-177) -67 + j*(221) --87 + j*(-32) --144 + j*(93) --135 + j*(-286) -385 + j*(-101) --86 + j*(202) --149 + j*(127) --56 + j*(195) --2 + j*(-35) --5 + j*(-182) -195 + j*(170) -202 + j*(-215) --213 + j*(-109) -101 + j*(-176) -255 + j*(-240) --86 + j*(214) --165 + j*(-35) -242 + j*(-112) --18 + j*(-156) -81 + j*(-96) --4 + j*(120) --97 + j*(8) -217 + j*(195) -256 + j*(-281) -71 + j*(-104) --125 + j*(153) --89 + j*(86) --69 + j*(210) --45 + j*(4) -445 + j*(-89) --50 + j*(-165) --212 + j*(58) -405 + j*(202) -153 + j*(383) --74 + j*(199) -317 + j*(-228) --6 + j*(-18) -24 + j*(-126) -234 + j*(141) --113 + j*(-23) -128 + j*(80) -202 + j*(194) -52 + j*(110) --8 + j*(-151) --58 + j*(132) --171 + j*(115) -54 + j*(49) --151 + j*(-103) -132 + j*(-243) -276 + j*(-27) --361 + j*(-115) --150 + j*(84) --148 + j*(-176) --145 + j*(82) -219 + j*(-160) -184 + j*(-7) -33 + j*(-124) --95 + j*(114) -190 + j*(-218) -141 + j*(-73) --187 + j*(190) --1 + j*(9) -149 + j*(6) -254 + j*(-40) --35 + j*(-286) -151 + j*(303) --139 + j*(-175) --104 + j*(49) --400 + j*(-63) -92 + j*(-197) --318 + j*(10) -25 + j*(-160) --183 + j*(-194) -74 + j*(45) -33 + j*(-66) -124 + j*(-181) --93 + j*(74) -206 + j*(-126) -257 + j*(-97) -18 + j*(9) --128 + j*(64) -119 + j*(125) --140 + j*(11) --257 + j*(7) --356 + j*(-113) --295 + j*(287) --144 + j*(104) -174 + j*(59) --13 + j*(-155) --43 + j*(92) --238 + j*(-49) --195 + j*(238) -112 + j*(-262) --103 + j*(37) -45 + j*(-238) --217 + j*(-295) --153 + j*(156) -281 + j*(88) --107 + j*(-43) -293 + j*(47) --215 + j*(80) --48 + j*(-238) --395 + j*(122) --348 + j*(-60) -11 + j*(40) -216 + j*(56) --78 + j*(163) -8 + j*(-216) -105 + j*(91) -106 + j*(261) --95 + j*(-192) -112 + j*(67) -312 + j*(-171) -168 + j*(-223) --7 + j*(171) --27 + j*(-176) -166 + j*(206) -40 + j*(89) --80 + j*(-222) --120 + j*(-236) --173 + j*(-10) --48 + j*(-100) --228 + j*(-205) -303 + j*(134) -222 + j*(18) --118 + j*(203) --35 + j*(40) -29 + j*(-70) -226 + j*(-18) -164 + j*(59) -173 + j*(-224) -45 + j*(-255) -149 + j*(-78) --10 + j*(-176) --168 + j*(216) -60 + j*(46) -45 + j*(-16) --254 + j*(-35) -116 + j*(28) -87 + j*(170) -91 + j*(-139) -204 + j*(-61) --131 + j*(-184) -158 + j*(184) --118 + j*(-86) -475 + j*(158) -255 + j*(-69) -54 + j*(-293) --11 + j*(91) --74 + j*(-40) --122 + j*(245) --371 + j*(-127) --13 + j*(-100) --156 + j*(1) -71 + j*(-356) --117 + j*(1) --56 + j*(319) --126 + j*(-319) --159 + j*(-66) --115 + j*(188) --153 + j*(257) -187 + j*(-379) -64 + j*(-60) --56 + j*(6) --279 + j*(-78) -437 + j*(-305) -164 + j*(161) -371 + j*(-175) -76 + j*(143) -240 + j*(-185) -14 + j*(187) -381 + j*(134) -65 + j*(-382) -274 + j*(-39) -91 + j*(78) --284 + j*(24) -115 + j*(82) --64 + j*(194) -33 + j*(182) --130 + j*(-107) --77 + j*(-45) --229 + j*(-103) -199 + j*(594) -117 + j*(59) -143 + j*(-350) -123 + j*(31) --86 + j*(-33) --301 + j*(258) -18 + j*(322) -166 + j*(-163) -157 + j*(-4) -201 + j*(228) --115 + j*(-309) --33 + j*(-49) --257 + j*(1) -75 + j*(-115) -45 + j*(367) --37 + j*(-36) --77 + j*(-276) -163 + j*(138) --42 + j*(103) -13 + j*(-232) -56 + j*(110) --30 + j*(-88) --47 + j*(-7) -42 + j*(235) -151 + j*(-332) -257 + j*(-101) -152 + j*(216) --316 + j*(212) --92 + j*(115) -127 + j*(-179) --67 + j*(47) --197 + j*(26) -441 + j*(-165) --227 + j*(124) -49 + j*(45) --81 + j*(368) --62 + j*(-108) -251 + j*(-332) --36 + j*(-64) -147 + j*(-291) --129 + j*(-181) -226 + j*(-194) --74 + j*(-160) --250 + j*(-107) --322 + j*(72) --95 + j*(15) --130 + j*(14) --42 + j*(-41) -23 + j*(-275) --61 + j*(-23) --400 + j*(257) -73 + j*(-130) --119 + j*(-42) --28 + j*(-104) -27 + j*(-366) --64 + j*(209) -84 + j*(206) --176 + j*(-442) -103 + j*(-235) --76 + j*(-279) -99 + j*(52) --264 + j*(-8) --288 + j*(71) -14 + j*(24) --402 + j*(25) --299 + j*(156) --146 + j*(135) --21 + j*(187) --255 + j*(-52) --214 + j*(239) -106 + j*(-19) -63 + j*(-71) -25 + j*(-88) -220 + j*(426) --358 + j*(91) --252 + j*(-223) --54 + j*(-177) -122 + j*(-41) -105 + j*(-161) --65 + j*(84) -252 + j*(10) --168 + j*(-198) -183 + j*(-35) -11 + j*(172) --226 + j*(-230) --184 + j*(-214) --151 + j*(-233) --92 + j*(-59) -31 + j*(100) -16 + j*(331) -125 + j*(81) --301 + j*(-35) -69 + j*(-139) --60 + j*(107) --64 + j*(-63) --43 + j*(-99) --130 + j*(-54) -134 + j*(381) --155 + j*(17) --499 + j*(223) --148 + j*(-124) --95 + j*(226) -247 + j*(-55) --181 + j*(-183) --94 + j*(-284) --287 + j*(-103) --136 + j*(59) -59 + j*(67) -259 + j*(-352) --150 + j*(-10) --43 + j*(119) -69 + j*(30) --106 + j*(351) --38 + j*(-85) -366 + j*(249) -71 + j*(197) -215 + j*(-37) --136 + j*(196) --231 + j*(75) -97 + j*(-383) -103 + j*(95) -99 + j*(-164) -172 + j*(-106) -93 + j*(177) -42 + j*(-337) --23 + j*(-7) -199 + j*(262) --141 + j*(70) -60 + j*(-132) --5 + j*(-18) --40 + j*(117) --18 + j*(127) --224 + j*(245) --200 + j*(-121) --22 + j*(74) --23 + j*(-212) -129 + j*(119) -42 + j*(286) -18 + j*(261) --17 + j*(-211) --72 + j*(84) -327 + j*(-28) -2 + j*(-11) -100 + j*(-301) --37 + j*(9) --66 + j*(-165) -16 + j*(-57) --59 + j*(-22) -49 + j*(158) -338 + j*(144) -11 + j*(87) --276 + j*(-42) --20 + j*(226) --117 + j*(0) --199 + j*(-294) --274 + j*(18) --21 + j*(-148) --173 + j*(216) -103 + j*(101) -162 + j*(18) -301 + j*(157) --43 + j*(486) -174 + j*(-354) --61 + j*(-138) --62 + j*(-337) -24 + j*(161) -106 + j*(-105) -69 + j*(-204) -247 + j*(166) --199 + j*(235) -11 + j*(107) -273 + j*(180) -157 + j*(-83) -174 + j*(21) --88 + j*(192) --171 + j*(-54) -393 + j*(294) --23 + j*(-21) --6 + j*(4) --73 + j*(-25) --319 + j*(-282) --407 + j*(-130) -86 + j*(76) -293 + j*(52) -392 + j*(-10) --297 + j*(-74) -89 + j*(-230) --149 + j*(286) --185 + j*(43) --91 + j*(-103) --277 + j*(-305) --189 + j*(-58) --190 + j*(-8) --54 + j*(-74) -99 + j*(26) --83 + j*(-206) -223 + j*(82) --60 + j*(-88) -342 + j*(-260) --350 + j*(-141) -154 + j*(-4) -48 + j*(-197) -153 + j*(211) -223 + j*(118) -52 + j*(-206) -158 + j*(-131) --368 + j*(49) --180 + j*(-28) -19 + j*(-435) -112 + j*(83) --167 + j*(-94) -161 + j*(284) -317 + j*(196) --108 + j*(-390) --236 + j*(105) --287 + j*(-153) --87 + j*(-1) --42 + j*(-37) --77 + j*(-438) --9 + j*(59) -48 + j*(-317) -395 + j*(133) --83 + j*(86) --60 + j*(16) --31 + j*(-90) -144 + j*(-65) --80 + j*(-160) -42 + j*(-12) --260 + j*(247) --56 + j*(185) -16 + j*(70) --87 + j*(-107) -74 + j*(187) --37 + j*(210) -303 + j*(52) --42 + j*(323) --40 + j*(-14) -54 + j*(119) --30 + j*(100) --129 + j*(-9) -223 + j*(11) --103 + j*(34) -225 + j*(316) --11 + j*(-108) --141 + j*(204) -86 + j*(-39) -50 + j*(361) --120 + j*(-119) -233 + j*(-174) --277 + j*(-74) --126 + j*(169) -58 + j*(-33) --177 + j*(-51) --153 + j*(-271) -151 + j*(119) -215 + j*(18) --69 + j*(-188) -305 + j*(130) --144 + j*(7) --210 + j*(50) -190 + j*(148) -78 + j*(-69) -37 + j*(96) -42 + j*(209) -243 + j*(57) -103 + j*(-252) --69 + j*(101) --43 + j*(-157) --168 + j*(-206) -27 + j*(-35) -100 + j*(-18) -6 + j*(33) --52 + j*(5) -13 + j*(-250) -17 + j*(268) -204 + j*(-153) -210 + j*(-54) --117 + j*(85) --30 + j*(22) --255 + j*(19) --3 + j*(-106) --87 + j*(-130) -50 + j*(-207) -340 + j*(143) --350 + j*(-105) -190 + j*(62) -32 + j*(-141) -21 + j*(289) --322 + j*(394) -29 + j*(-30) -132 + j*(-94) -114 + j*(-328) --195 + j*(372) --228 + j*(-20) -54 + j*(66) --39 + j*(-59) -186 + j*(10) -153 + j*(258) -12 + j*(45) -4 + j*(-96) --33 + j*(54) --210 + j*(116) --369 + j*(72) -28 + j*(180) -93 + j*(114) --98 + j*(208) -211 + j*(119) --148 + j*(-176) --391 + j*(-227) --63 + j*(122) -59 + j*(30) -41 + j*(269) --97 + j*(200) --49 + j*(-78) --208 + j*(261) -25 + j*(-16) --253 + j*(8) -146 + j*(68) -71 + j*(28) -221 + j*(-176) --281 + j*(-49) -278 + j*(134) -83 + j*(168) --66 + j*(543) -260 + j*(-264) --245 + j*(-107) --205 + j*(669) --275 + j*(207) --265 + j*(294) -88 + j*(137) --162 + j*(-23) --410 + j*(-24) --228 + j*(-286) -486 + j*(-153) --10 + j*(112) -113 + j*(-173) -317 + j*(-373) --211 + j*(-313) --163 + j*(-56) -362 + j*(-64) -83 + j*(397) --247 + j*(312) -385 + j*(-145) --151 + j*(74) -361 + j*(161) --247 + j*(451) --320 + j*(-274) -314 + j*(337) -155 + j*(233) -114 + j*(-267) -115 + j*(201) -377 + j*(-134) -194 + j*(218) -36 + j*(202) --598 + j*(232) -122 + j*(-301) -411 + j*(256) -260 + j*(-323) -12 + j*(466) --78 + j*(-218) -267 + j*(-318) --243 + j*(-390) -573 + j*(441) --57 + j*(-368) --492 + j*(141) --271 + j*(-62) -310 + j*(246) -226 + j*(-334) --395 + j*(-523) --323 + j*(166) --339 + j*(-184) -283 + j*(90) --737 + j*(-246) -196 + j*(335) -354 + j*(-433) --33 + j*(13) --402 + j*(-357) -322 + j*(209) -69 + j*(109) -453 + j*(-119) -245 + j*(34) -296 + j*(-48) -283 + j*(-426) -228 + j*(-288) -86 + j*(185) -453 + j*(-25) --137 + j*(255) -77 + j*(-154) --166 + j*(-66) --342 + j*(179) --454 + j*(-412) -387 + j*(-252) -292 + j*(122) -334 + j*(0) --254 + j*(129) --116 + j*(-10) --292 + j*(-6) -268 + j*(-445) --209 + j*(-537) -424 + j*(-64) -279 + j*(-367) --361 + j*(-91) --243 + j*(-316) -250 + j*(-355) -238 + j*(-216) --464 + j*(386) --296 + j*(150) --192 + j*(-322) -151 + j*(-255) -341 + j*(361) --467 + j*(269) --282 + j*(-421) -180 + j*(-375) --428 + j*(-371) -211 + j*(272) -65 + j*(-426) --378 + j*(-335) -158 + j*(-18) --214 + j*(195) --12 + j*(-337) --115 + j*(116) -433 + j*(-126) -228 + j*(-88) --329 + j*(54) -425 + j*(-19) --443 + j*(496) -358 + j*(-255) --401 + j*(272) -285 + j*(172) --81 + j*(405) -10 + j*(-358) --370 + j*(102) --477 + j*(30) -8 + j*(519) --323 + j*(447) --527 + j*(-167) --218 + j*(36) --116 + j*(-40) -501 + j*(-393) -180 + j*(-192) --93 + j*(-530) --57 + j*(-521) -21 + j*(-306) -252 + j*(228) --330 + j*(-42) -35 + j*(-476) --482 + j*(-399) -221 + j*(348) --257 + j*(-202) --110 + j*(-249) -313 + j*(-1) --303 + j*(51) --374 + j*(683) -339 + j*(279) -428 + j*(363) -18 + j*(-341) -355 + j*(508) --128 + j*(265) --309 + j*(-98) --28 + j*(-35) --439 + j*(231) -499 + j*(458) --546 + j*(-80) --31 + j*(395) --47 + j*(-1) -135 + j*(-437) -299 + j*(126) -161 + j*(424) -275 + j*(-41) --172 + j*(77) --433 + j*(57) -477 + j*(-182) -334 + j*(349) -233 + j*(-412) -414 + j*(93) -93 + j*(103) --146 + j*(-267) --232 + j*(-346) -324 + j*(204) --500 + j*(-10) -276 + j*(-453) -23 + j*(-245) -343 + j*(-359) -419 + j*(-468) -517 + j*(83) -332 + j*(583) -355 + j*(-421) --238 + j*(-115) -729 + j*(-23) -218 + j*(148) -305 + j*(-159) --265 + j*(102) --346 + j*(109) -343 + j*(140) -504 + j*(-364) --424 + j*(-228) --202 + j*(64) --35 + j*(265) --456 + j*(599) --388 + j*(-223) -83 + j*(-33) -375 + j*(-334) --115 + j*(53) -383 + j*(387) -110 + j*(-587) -518 + j*(49) -318 + j*(418) --219 + j*(-455) --37 + j*(-326) --233 + j*(182) --334 + j*(406) -559 + j*(327) --398 + j*(265) --517 + j*(-204) -436 + j*(204) -260 + j*(644) -407 + j*(-289) -355 + j*(-119) -377 + j*(-563) -171 + j*(-69) -313 + j*(-574) -228 + j*(-445) --118 + j*(-154) --161 + j*(424) -124 + j*(-366) -335 + j*(-135) --99 + j*(-424) -437 + j*(506) -490 + j*(747) -272 + j*(79) --28 + j*(-279) -214 + j*(333) --190 + j*(251) -220 + j*(-320) -18 + j*(298) -292 + j*(136) --164 + j*(-386) --437 + j*(373) --122 + j*(-311) -59 + j*(-512) -115 + j*(-47) -371 + j*(105) -432 + j*(-331) --418 + j*(247) --438 + j*(356) -231 + j*(-129) --334 + j*(178) --309 + j*(-184) -269 + j*(460) --460 + j*(118) -537 + j*(36) -550 + j*(224) -275 + j*(-334) --344 + j*(245) --120 + j*(-237) -122 + j*(-154) -68 + j*(-146) -68 + j*(-363) --211 + j*(-162) --258 + j*(-269) -560 + j*(-274) -145 + j*(-81) -562 + j*(231) --363 + j*(-486) -429 + j*(-189) -317 + j*(286) -298 + j*(-331) -110 + j*(-121) -4 + j*(-651) -4 + j*(648) -318 + j*(506) -478 + j*(79) -103 + j*(40) --136 + j*(-419) -412 + j*(-26) --493 + j*(290) --364 + j*(513) -158 + j*(35) --472 + j*(-109) --293 + j*(-365) -372 + j*(437) --171 + j*(-282) --439 + j*(202) --136 + j*(202) --196 + j*(427) --387 + j*(283) --329 + j*(118) --320 + j*(-251) --141 + j*(382) -290 + j*(-96) -262 + j*(-165) --173 + j*(-39) -126 + j*(-477) --247 + j*(299) --247 + j*(382) --315 + j*(356) -141 + j*(-220) -291 + j*(-223) -281 + j*(448) -287 + j*(90) -457 + j*(-190) --184 + j*(438) -302 + j*(-472) --176 + j*(286) --207 + j*(-400) -439 + j*(-117) -74 + j*(125) -292 + j*(-349) -299 + j*(-208) --30 + j*(-268) --59 + j*(-288) --226 + j*(-315) --499 + j*(-209) --340 + j*(423) --389 + j*(-105) --170 + j*(-335) --76 + j*(225) --312 + j*(88) -379 + j*(303) -284 + j*(-255) --291 + j*(296) -601 + j*(220) -207 + j*(105) -148 + j*(313) -281 + j*(420) --402 + j*(382) --141 + j*(148) --74 + j*(318) --618 + j*(-348) --385 + j*(-310) -448 + j*(233) -471 + j*(-279) -9 + j*(125) --191 + j*(-74) -559 + j*(529) --421 + j*(-25) -615 + j*(-308) --161 + j*(370) -493 + j*(-135) --39 + j*(-309) --270 + j*(-256) -527 + j*(8) --204 + j*(474) -88 + j*(514) --276 + j*(-429) -238 + j*(277) --216 + j*(165) --202 + j*(-349) --73 + j*(-279) -267 + j*(279) --186 + j*(-200) --404 + j*(639) -233 + j*(-351) -304 + j*(-202) --91 + j*(-161) -383 + j*(-247) --437 + j*(-287) --275 + j*(-8) -453 + j*(-290) -305 + j*(-100) -323 + j*(-377) -22 + j*(112) --371 + j*(-85) --23 + j*(-8) -276 + j*(173) -226 + j*(120) --491 + j*(337) --245 + j*(497) -368 + j*(-130) -77 + j*(190) -378 + j*(34) --298 + j*(187) -146 + j*(322) --494 + j*(-216) --312 + j*(80) -361 + j*(195) -213 + j*(-537) --49 + j*(-452) --282 + j*(-228) --171 + j*(382) -74 + j*(-387) --382 + j*(378) -513 + j*(-339) -67 + j*(-65) -301 + j*(-3) -438 + j*(-215) --516 + j*(100) -55 + j*(-149) --47 + j*(-359) -92 + j*(-285) --182 + j*(193) -152 + j*(-314) --270 + j*(255) --334 + j*(-128) -299 + j*(-450) --197 + j*(311) --231 + j*(-173) -458 + j*(-262) --206 + j*(477) --338 + j*(202) --37 + j*(454) --477 + j*(-1) --157 + j*(-477) --339 + j*(-322) --278 + j*(607) -257 + j*(-292) --199 + j*(77) -132 + j*(182) --314 + j*(-312) --439 + j*(366) --319 + j*(-279) -358 + j*(74) --198 + j*(-170) -557 + j*(-256) --207 + j*(-424) --472 + j*(-307) -158 + j*(228) --80 + j*(-64) -395 + j*(383) --168 + j*(-6) --40 + j*(-215) -78 + j*(-342) --28 + j*(97) -357 + j*(73) --584 + j*(-170) --510 + j*(296) --155 + j*(42) -187 + j*(13) -510 + j*(334) -113 + j*(-436) --448 + j*(265) --327 + j*(184) -128 + j*(141) -211 + j*(-30) -139 + j*(197) --36 + j*(65) -546 + j*(220) -473 + j*(-143) --139 + j*(175) --473 + j*(243) -247 + j*(-214) -18 + j*(262) -28 + j*(-354) -140 + j*(-25) --325 + j*(-457) --284 + j*(-313) -229 + j*(-353) --337 + j*(-385) -448 + j*(501) --292 + j*(-126) -484 + j*(-617) --291 + j*(-453) --297 + j*(-247) -347 + j*(-323) -204 + j*(-272) --252 + j*(-155) --148 + j*(-477) -166 + j*(378) -142 + j*(0) -174 + j*(438) -653 + j*(-51) -259 + j*(458) --282 + j*(237) -13 + j*(350) --537 + j*(365) -215 + j*(315) -467 + j*(129) -244 + j*(-213) -285 + j*(1) -182 + j*(-56) -135 + j*(-305) -208 + j*(-312) -612 + j*(-123) -303 + j*(473) -102 + j*(-471) --190 + j*(-270) -3 + j*(-470) -192 + j*(483) -94 + j*(-435) --69 + j*(333) -527 + j*(9) --203 + j*(201) -159 + j*(1) --428 + j*(333) -54 + j*(-194) -391 + j*(303) --171 + j*(-295) -315 + j*(-127) -260 + j*(197) --146 + j*(-67) -297 + j*(446) --474 + j*(285) --95 + j*(165) -286 + j*(-295) --482 + j*(-386) -37 + j*(-359) --295 + j*(-119) -187 + j*(-374) -359 + j*(-55) --294 + j*(-349) -301 + j*(301) -148 + j*(-211) --259 + j*(-183) --325 + j*(28) --144 + j*(39) --403 + j*(-242) --465 + j*(49) -176 + j*(-325) -262 + j*(-41) -547 + j*(260) --316 + j*(65) -425 + j*(-1) -310 + j*(-226) --163 + j*(-569) --361 + j*(268) -385 + j*(-217) --474 + j*(-19) --143 + j*(238) --280 + j*(-138) -170 + j*(233) -124 + j*(-78) -593 + j*(348) --291 + j*(-136) -98 + j*(542) --211 + j*(-704) -431 + j*(-303) -79 + j*(-228) -134 + j*(-62) --247 + j*(-397) -567 + j*(52) -521 + j*(-226) -368 + j*(-127) --654 + j*(28) --457 + j*(595) --162 + j*(-465) --161 + j*(-552) -202 + j*(-199) --409 + j*(-440) -623 + j*(137) -305 + j*(6) --115 + j*(-160) -206 + j*(-120) -182 + j*(285) --478 + j*(-85) --197 + j*(-403) -119 + j*(-354) --308 + j*(349) -482 + j*(-368) --296 + j*(96) --27 + j*(141) -665 + j*(389) -458 + j*(179) --8 + j*(-435) --648 + j*(-80) --403 + j*(192) --212 + j*(161) -319 + j*(-486) -222 + j*(-178) -308 + j*(338) --88 + j*(-101) -406 + j*(-424) --95 + j*(-590) --412 + j*(-542) --64 + j*(-274) --245 + j*(320) -144 + j*(192) -144 + j*(300) -225 + j*(-187) --200 + j*(352) --576 + j*(-369) -86 + j*(-57) -243 + j*(-177) --106 + j*(-433) -275 + j*(361) -85 + j*(164) --300 + j*(338) --659 + j*(-456) --293 + j*(-298) --453 + j*(209) --493 + j*(165) --635 + j*(-501) --353 + j*(357) --294 + j*(184) -47 + j*(-356) -251 + j*(37) -490 + j*(250) --204 + j*(-330) -344 + j*(291) -110 + j*(165) -97 + j*(18) -540 + j*(-192) --569 + j*(-88) --135 + j*(95) --326 + j*(-617) -115 + j*(-14) -263 + j*(-353) -436 + j*(-301) -83 + j*(265) --94 + j*(269) --194 + j*(-245) --6 + j*(-158) --156 + j*(-540) -476 + j*(313) -308 + j*(-288) --74 + j*(-361) --286 + j*(-144) -332 + j*(-60) -327 + j*(147) --452 + j*(477) -95 + j*(116) -477 + j*(413) -343 + j*(427) -548 + j*(351) --358 + j*(108) --147 + j*(-146) --383 + j*(-209) --431 + j*(-528) -555 + j*(473) -233 + j*(-53) --44 + j*(-122) -339 + j*(626) --10 + j*(-454) --10 + j*(484) --222 + j*(225) --47 + j*(90) -170 + j*(162) -61 + j*(-95) -25 + j*(-11) -74 + j*(269) --2 + j*(243) -3 + j*(30) --267 + j*(-80) -59 + j*(374) --35 + j*(-372) -165 + j*(221) --102 + j*(-175) --34 + j*(-115) --75 + j*(-95) -126 + j*(88) --245 + j*(194) --351 + j*(72) -33 + j*(47) --87 + j*(-266) --95 + j*(165) --56 + j*(42) -179 + j*(123) --30 + j*(170) -5 + j*(-428) -279 + j*(346) --349 + j*(-42) --9 + j*(-86) --62 + j*(293) -344 + j*(-372) -148 + j*(-54) --160 + j*(-57) --57 + j*(109) --88 + j*(128) --73 + j*(156) --130 + j*(60) --206 + j*(472) --129 + j*(4) -231 + j*(-168) --84 + j*(-132) --189 + j*(310) --64 + j*(-107) -274 + j*(-236) --53 + j*(-1) -8 + j*(-197) -327 + j*(-13) -85 + j*(321) -41 + j*(158) -134 + j*(267) -53 + j*(129) -42 + j*(-11) -144 + j*(-164) -216 + j*(29) --70 + j*(-49) --153 + j*(-78) -303 + j*(91) -248 + j*(-240) -60 + j*(191) -51 + j*(51) -38 + j*(30) --110 + j*(72) -395 + j*(-380) --98 + j*(-201) --21 + j*(-40) -26 + j*(122) -6 + j*(268) --85 + j*(78) -105 + j*(49) -152 + j*(-69) -277 + j*(134) -59 + j*(-185) --112 + j*(-143) --12 + j*(275) --103 + j*(-44) --190 + j*(-227) --245 + j*(105) --21 + j*(-148) --67 + j*(45) -154 + j*(128) --110 + j*(-153) --33 + j*(-143) --88 + j*(-81) -163 + j*(-1) -42 + j*(-227) -93 + j*(1) -202 + j*(-52) -305 + j*(58) --170 + j*(-458) --181 + j*(418) -291 + j*(402) --198 + j*(166) -196 + j*(-259) --263 + j*(186) -77 + j*(137) -59 + j*(-204) -379 + j*(-7) --19 + j*(64) -235 + j*(35) -81 + j*(-90) -24 + j*(79) -54 + j*(-92) --119 + j*(-243) -99 + j*(187) --18 + j*(109) -139 + j*(-76) --267 + j*(-52) --111 + j*(92) -6 + j*(-2) -57 + j*(158) -158 + j*(-405) --224 + j*(242) -271 + j*(-42) -131 + j*(-201) -151 + j*(192) --50 + j*(42) -333 + j*(-21) --34 + j*(-134) --121 + j*(110) --480 + j*(-63) -40 + j*(-447) --150 + j*(147) -90 + j*(-212) --186 + j*(-5) -174 + j*(-49) --319 + j*(91) -145 + j*(-51) --251 + j*(-44) -57 + j*(13) --9 + j*(-190) --72 + j*(107) -54 + j*(114) -156 + j*(20) --134 + j*(98) --89 + j*(-16) --120 + j*(-82) --135 + j*(-173) -307 + j*(-235) --24 + j*(-242) -132 + j*(-212) --139 + j*(-104) -349 + j*(-211) -23 + j*(146) -65 + j*(25) --104 + j*(140) --110 + j*(115) --97 + j*(-174) -162 + j*(35) -86 + j*(-174) -222 + j*(48) -136 + j*(279) --100 + j*(-28) --5 + j*(-159) -49 + j*(-167) --3 + j*(230) --57 + j*(12) -136 + j*(-295) -62 + j*(-274) --178 + j*(-213) --34 + j*(284) -102 + j*(174) --112 + j*(83) -99 + j*(161) --141 + j*(-249) -16 + j*(21) -135 + j*(-135) -62 + j*(162) -23 + j*(-67) --128 + j*(-1) --24 + j*(-153) -8 + j*(128) -134 + j*(-47) --240 + j*(185) -18 + j*(310) --136 + j*(108) --266 + j*(-65) -174 + j*(33) --188 + j*(18) --146 + j*(180) -128 + j*(-28) -339 + j*(157) --163 + j*(215) -148 + j*(26) --57 + j*(-83) --116 + j*(82) --91 + j*(110) --258 + j*(1) --128 + j*(-60) -26 + j*(-158) --87 + j*(-183) -1 + j*(12) --73 + j*(313) -265 + j*(-34) --39 + j*(-241) --30 + j*(66) -81 + j*(-78) -97 + j*(-133) --57 + j*(-127) -94 + j*(-61) -228 + j*(-84) --77 + j*(276) -76 + j*(86) --38 + j*(-375) --130 + j*(136) --11 + j*(-57) --182 + j*(25) -40 + j*(-249) --206 + j*(100) -0 + j*(119) --240 + j*(-139) --165 + j*(55) -170 + j*(-28) -361 + j*(-87) -91 + j*(132) -10 + j*(139) --154 + j*(-103) -37 + j*(39) --142 + j*(-283) -181 + j*(207) --1 + j*(-238) --273 + j*(93) -27 + j*(-272) --78 + j*(-228) -322 + j*(-95) --100 + j*(-489) --257 + j*(-308) --112 + j*(302) -145 + j*(243) --69 + j*(88) --78 + j*(-173) -96 + j*(107) --100 + j*(178) --348 + j*(45) --27 + j*(30) -267 + j*(-211) -52 + j*(-66) -236 + j*(-195) -339 + j*(-69) -351 + j*(125) --79 + j*(-368) -71 + j*(4) --151 + j*(159) --47 + j*(-404) --266 + j*(209) -175 + j*(46) --301 + j*(-93) -281 + j*(-106) --25 + j*(-88) --96 + j*(-258) -160 + j*(-1) -128 + j*(28) -11 + j*(43) -137 + j*(412) --276 + j*(141) -64 + j*(-101) --82 + j*(-85) --194 + j*(100) --305 + j*(-136) -45 + j*(175) --28 + j*(-45) -190 + j*(169) -265 + j*(74) -264 + j*(-54) --26 + j*(112) --264 + j*(177) --255 + j*(320) -127 + j*(70) -184 + j*(-347) -132 + j*(244) -298 + j*(-8) --182 + j*(-144) --226 + j*(175) --40 + j*(323) -200 + j*(-257) --293 + j*(282) -11 + j*(-280) --1 + j*(-445) -18 + j*(-180) -134 + j*(10) --3 + j*(-98) -262 + j*(-4) -45 + j*(153) -376 + j*(84) --324 + j*(185) --197 + j*(-124) --152 + j*(-61) --40 + j*(-2) --173 + j*(-68) -98 + j*(108) -261 + j*(-73) -119 + j*(76) -28 + j*(-102) --305 + j*(-276) -243 + j*(180) --221 + j*(128) -64 + j*(-102) --108 + j*(267) --8 + j*(-108) --116 + j*(139) --91 + j*(-62) -24 + j*(25) --83 + j*(98) -45 + j*(-124) -173 + j*(47) --124 + j*(-233) --47 + j*(-125) --88 + j*(-132) --21 + j*(277) --112 + j*(-133) -88 + j*(97) --320 + j*(354) -338 + j*(259) --6 + j*(-208) --8 + j*(-50) -310 + j*(-15) --33 + j*(-134) -93 + j*(-54) -70 + j*(-214) -10 + j*(-65) -123 + j*(78) -317 + j*(147) --209 + j*(-153) -513 + j*(-206) --306 + j*(-128) -27 + j*(-395) -112 + j*(90) --17 + j*(35) --57 + j*(-4) --122 + j*(-385) -30 + j*(-61) --167 + j*(238) -269 + j*(265) -203 + j*(41) -253 + j*(70) -52 + j*(-152) --53 + j*(-49) -96 + j*(49) --202 + j*(-424) -34 + j*(-286) --505 + j*(-199) --190 + j*(166) -308 + j*(-265) --186 + j*(451) --331 + j*(-117) -115 + j*(64) --171 + j*(111) --106 + j*(266) -143 + j*(-148) --13 + j*(16) --168 + j*(375) -211 + j*(150) --470 + j*(104) --274 + j*(-323) -198 + j*(76) -115 + j*(349) --244 + j*(129) --5 + j*(-64) -309 + j*(-34) -18 + j*(107) -482 + j*(76) -136 + j*(245) --91 + j*(-34) --130 + j*(153) -83 + j*(-168) -0 + j*(-32) -23 + j*(-372) --44 + j*(-225) --228 + j*(-75) -28 + j*(244) --141 + j*(82) --149 + j*(-58) --271 + j*(-217) --331 + j*(270) --100 + j*(-6) -185 + j*(-83) -325 + j*(-273) -226 + j*(-206) -240 + j*(86) --154 + j*(-227) --48 + j*(-69) --42 + j*(72) -377 + j*(137) -62 + j*(-402) --53 + j*(-8) -29 + j*(63) --30 + j*(204) --255 + j*(390) -233 + j*(180) --53 + j*(-97) --42 + j*(-55) --32 + j*(-76) -66 + j*(410) -33 + j*(243) -163 + j*(-12) --195 + j*(-38) -254 + j*(98) --132 + j*(-132) -7 + j*(-87) -136 + j*(240) -59 + j*(42) -225 + j*(-68) --159 + j*(152) --129 + j*(-4) -269 + j*(-86) --37 + j*(79) --436 + j*(-71) --23 + j*(211) -163 + j*(176) --89 + j*(-98) --129 + j*(-387) -118 + j*(8) -38 + j*(-47) -337 + j*(-88) --4 + j*(-1) -231 + j*(-82) -54 + j*(366) --73 + j*(138) --8 + j*(-69) --163 + j*(135) --159 + j*(-257) --214 + j*(-268) --60 + j*(-36) -69 + j*(182) -172 + j*(115) --105 + j*(288) -77 + j*(-184) --107 + j*(101) -248 + j*(45) -61 + j*(-101) -292 + j*(-93) -69 + j*(-192) -143 + j*(66) --279 + j*(138) --74 + j*(-21) -371 + j*(-74) -134 + j*(300) --71 + j*(8) -108 + j*(-291) -4 + j*(129) --373 + j*(-51) -59 + j*(-117) -189 + j*(-206) -206 + j*(28) --242 + j*(-433) --98 + j*(-260) --102 + j*(169) --82 + j*(33) --11 + j*(-184) --24 + j*(-47) -77 + j*(-71) --117 + j*(-44) -204 + j*(-164) --10 + j*(-81) -179 + j*(-16) -68 + j*(-293) -22 + j*(37) -202 + j*(104) -30 + j*(45) -192 + j*(180) --136 + j*(-117) -120 + j*(173) --202 + j*(148) --172 + j*(173) --28 + j*(190) -115 + j*(-58) --167 + j*(199) --95 + j*(212) -168 + j*(-260) --250 + j*(-95) --35 + j*(100) --360 + j*(-88) --163 + j*(75) -335 + j*(-58) --14 + j*(151) --169 + j*(104) -334 + j*(105) --157 + j*(102) --45 + j*(316) --64 + j*(-126) --4 + j*(-431) --91 + j*(-217) -13 + j*(-134) -52 + j*(409) -160 + j*(14) -89 + j*(9) --217 + j*(5) --177 + j*(-442) -225 + j*(-34) --110 + j*(-98) -130 + j*(-428) --225 + j*(212) -44 + j*(-217) -40 + j*(-213) --158 + j*(30) -16 + j*(49) -101 + j*(-322) --93 + j*(38) -330 + j*(214) --61 + j*(18) -285 + j*(34) --228 + j*(-156) -146 + j*(83) --427 + j*(-93) --119 + j*(58) --91 + j*(-428) --177 + j*(-75) -62 + j*(-10) --29 + j*(-49) --76 + j*(95) -62 + j*(-320) --144 + j*(88) -197 + j*(-121) -243 + j*(-54) -113 + j*(223) -59 + j*(-157) -136 + j*(-99) -145 + j*(-90) --283 + j*(-42) --247 + j*(-106) -99 + j*(-380) --8 + j*(-124) --28 + j*(-31) -407 + j*(250) --198 + j*(-94) -244 + j*(154) -119 + j*(501) -82 + j*(315) -16 + j*(122) --6 + j*(-247) --162 + j*(300) -103 + j*(-98) -221 + j*(-177) --80 + j*(207) -43 + j*(105) -8 + j*(2) -251 + j*(-303) -143 + j*(-45) -209 + j*(-18) --35 + j*(76) --191 + j*(254) -178 + j*(-18) -66 + j*(-378) -45 + j*(-7) --159 + j*(-144) --282 + j*(-106) --225 + j*(2) --107 + j*(-255) -92 + j*(226) --39 + j*(-218) --102 + j*(139) -184 + j*(77) --78 + j*(134) -56 + j*(-278) --35 + j*(-81) --61 + j*(-204) --65 + j*(-25) --202 + j*(163) -310 + j*(-28) --111 + j*(-95) --2 + j*(141) --173 + j*(-51) --21 + j*(182) --257 + j*(-57) --83 + j*(81) --267 + j*(52) -2 + j*(13) -35 + j*(59) -105 + j*(190) --306 + j*(-253) -19 + j*(88) --3 + j*(-221) -234 + j*(-160) --9 + j*(-108) --325 + j*(356) --71 + j*(268) --308 + j*(364) --308 + j*(183) -193 + j*(-95) -62 + j*(-12) -107 + j*(42) --100 + j*(62) --84 + j*(57) --90 + j*(-427) --73 + j*(-35) --191 + j*(134) --48 + j*(-85) -193 + j*(-242) --80 + j*(61) -225 + j*(-24) --179 + j*(-218) -353 + j*(394) -197 + j*(109) -228 + j*(9) -386 + j*(167) -86 + j*(-8) -55 + j*(-312) --18 + j*(78) --32 + j*(-191) --24 + j*(20) -121 + j*(-126) --80 + j*(16) --161 + j*(367) --64 + j*(109) --22 + j*(37) --145 + j*(65) --197 + j*(-272) -103 + j*(-46) --98 + j*(99) --325 + j*(-251) -43 + j*(-93) --54 + j*(-3) -193 + j*(-82) -91 + j*(57) -80 + j*(-122) -151 + j*(-258) -36 + j*(-443) --69 + j*(-25) --116 + j*(-222) --12 + j*(-306) --298 + j*(-242) -243 + j*(-248) -94 + j*(-47) --65 + j*(103) --246 + j*(128) --27 + j*(52) --165 + j*(235) --88 + j*(41) --21 + j*(-100) --2 + j*(222) --156 + j*(163) -209 + j*(279) -55 + j*(177) --209 + j*(-136) -132 + j*(-42) --221 + j*(-51) -91 + j*(62) --34 + j*(129) --217 + j*(-257) -6 + j*(-36) --353 + j*(-90) --7 + j*(-86) -105 + j*(81) -148 + j*(-40) --20 + j*(-6) -93 + j*(-156) -145 + j*(120) --110 + j*(465) --39 + j*(23) --54 + j*(138) --69 + j*(87) --91 + j*(-74) -361 + j*(26) -513 + j*(-134) --293 + j*(-134) -18 + j*(-93) -424 + j*(177) --22 + j*(40) -173 + j*(74) -2 + j*(-207) --162 + j*(-165) -57 + j*(128) -315 + j*(80) --102 + j*(117) -238 + j*(-75) --107 + j*(134) --204 + j*(-153) --170 + j*(-9) -2 + j*(50) -88 + j*(110) --8 + j*(-115) --92 + j*(-237) --52 + j*(265) --40 + j*(16) --74 + j*(-80) --150 + j*(-26) --33 + j*(-29) -383 + j*(-48) --182 + j*(247) --192 + j*(260) -108 + j*(133) -175 + j*(-317) --12 + j*(-103) --24 + j*(-373) -141 + j*(-220) -170 + j*(-106) --112 + j*(-248) -180 + j*(-78) --252 + j*(-380) --39 + j*(-247) --152 + j*(39) -28 + j*(-119) --47 + j*(-174) -101 + j*(87) -127 + j*(77) -103 + j*(-255) -66 + j*(257) --105 + j*(32) -78 + j*(69) -26 + j*(-54) --31 + j*(73) -346 + j*(346) -8 + j*(26) --37 + j*(-59) -21 + j*(194) --28 + j*(183) -100 + j*(-55) --157 + j*(175) --322 + j*(-137) --33 + j*(132) --477 + j*(-62) -332 + j*(-111) -83 + j*(282) --134 + j*(92) --269 + j*(-296) --4 + j*(5) -69 + j*(-35) --299 + j*(14) -154 + j*(-176) --137 + j*(11) -156 + j*(-180) --66 + j*(-36) --10 + j*(57) --261 + j*(-361) --36 + j*(74) --31 + j*(147) --19 + j*(-169) -149 + j*(256) --332 + j*(29) --293 + j*(-197) -117 + j*(-184) -235 + j*(134) -251 + j*(86) -54 + j*(-310) -13 + j*(-11) --385 + j*(-286) --2 + j*(-37) --115 + j*(-48) -197 + j*(-20) -264 + j*(136) --243 + j*(-59) --187 + j*(30) -92 + j*(28) --91 + j*(-238) --93 + j*(-179) -6 + j*(76) -11 + j*(6) --96 + j*(78) -25 + j*(59) -110 + j*(523) -141 + j*(-14) --94 + j*(-10) -22 + j*(-120) -443 + j*(-14) -95 + j*(-174) --141 + j*(125) --12 + j*(-354) --193 + j*(-144) --156 + j*(-74) -210 + j*(317) -281 + j*(-52) -77 + j*(89) -21 + j*(-80) -332 + j*(-6) -292 + j*(18) -57 + j*(-45) --65 + j*(113) --317 + j*(-109) --378 + j*(-298) -185 + j*(1) --453 + j*(-45) -123 + j*(279) -27 + j*(57) --299 + j*(23) -112 + j*(47) --47 + j*(174) -33 + j*(-227) --288 + j*(9) --153 + j*(5) -250 + j*(52) --119 + j*(-208) -127 + j*(262) --30 + j*(-109) -55 + j*(-247) --112 + j*(-44) --82 + j*(-38) --297 + j*(-16) -59 + j*(60) --198 + j*(-55) -204 + j*(-151) -12 + j*(40) --627 + j*(-236) --112 + j*(-281) --91 + j*(-167) -38 + j*(83) --146 + j*(130) --228 + j*(29) --67 + j*(-216) -100 + j*(30) -137 + j*(190) -173 + j*(337) -252 + j*(-108) -431 + j*(-163) -217 + j*(-54) --156 + j*(-250) -286 + j*(-232) -286 + j*(-181) --103 + j*(-117) --177 + j*(81) --246 + j*(-159) --254 + j*(58) -69 + j*(157) --110 + j*(34) -262 + j*(95) --130 + j*(148) -144 + j*(345) -152 + j*(25) -89 + j*(236) -257 + j*(146) -50 + j*(-297) -109 + j*(207) -105 + j*(-262) -330 + j*(-397) --221 + j*(-162) -60 + j*(-54) -49 + j*(-194) -24 + j*(-104) --45 + j*(-18) --180 + j*(266) --25 + j*(183) -64 + j*(221) -302 + j*(409) --55 + j*(3) -226 + j*(-310) -37 + j*(-49) --116 + j*(66) -115 + j*(-84) --155 + j*(174) --134 + j*(100) --211 + j*(-69) -226 + j*(-11) -397 + j*(43) -170 + j*(81) --107 + j*(-122) -433 + j*(-25) -115 + j*(-77) --235 + j*(-4) --308 + j*(-138) -187 + j*(241) -49 + j*(8) -62 + j*(105) --296 + j*(122) -33 + j*(497) -334 + j*(-1) -194 + j*(41) -204 + j*(-245) --49 + j*(15) --103 + j*(16) --217 + j*(56) -28 + j*(196) -343 + j*(-173) -173 + j*(164) --100 + j*(167) --94 + j*(-25) --79 + j*(-95) -30 + j*(-276) -144 + j*(61) --120 + j*(-195) --213 + j*(-366) -209 + j*(30) -6 + j*(-245) --43 + j*(-83) -28 + j*(61) -4 + j*(-51) --167 + j*(52) --245 + j*(4) --48 + j*(-92) --53 + j*(210) --156 + j*(-160) --82 + j*(-115) --198 + j*(-206) --134 + j*(-6) -203 + j*(-311) --317 + j*(-81) --66 + j*(-54) -67 + j*(-153) --34 + j*(-26) --14 + j*(-69) -91 + j*(163) --6 + j*(-6) --141 + j*(66) --91 + j*(241) --42 + j*(196) --49 + j*(-35) --175 + j*(-137) -16 + j*(267) -49 + j*(-106) -45 + j*(97) --351 + j*(119) --276 + j*(-46) --109 + j*(94) -3 + j*(170) --182 + j*(323) -97 + j*(-124) --203 + j*(307) --233 + j*(231) --134 + j*(78) -282 + j*(8) -124 + j*(319) -119 + j*(-40) --176 + j*(-145) -26 + j*(42) -97 + j*(-273) --319 + j*(-56) --148 + j*(-65) --12 + j*(242) -16 + j*(165) -264 + j*(85) --181 + j*(-34) -1 + j*(-103) -194 + j*(-12) -14 + j*(260) --251 + j*(-40) --280 + j*(81) --42 + j*(-2) --6 + j*(152) -155 + j*(245) --267 + j*(103) --23 + j*(-334) --177 + j*(100) -8 + j*(-99) -104 + j*(-202) -168 + j*(94) -59 + j*(-193) -57 + j*(116) -98 + j*(-116) --96 + j*(-264) --44 + j*(301) -138 + j*(6) --168 + j*(187) --306 + j*(-88) --163 + j*(-206) --222 + j*(52) -319 + j*(32) -45 + j*(-178) --207 + j*(-179) -160 + j*(-24) -84 + j*(460) -91 + j*(-168) -168 + j*(119) -11 + j*(-8) --145 + j*(195) --145 + j*(-81) -39 + j*(247) --66 + j*(203) -208 + j*(-63) -167 + j*(40) --64 + j*(366) -51 + j*(262) -21 + j*(139) --38 + j*(-226) -158 + j*(-107) --109 + j*(566) -100 + j*(-16) -2 + j*(43) -1 + j*(-100) -23 + j*(-98) --48 + j*(-217) --64 + j*(218) -105 + j*(-83) --186 + j*(104) --64 + j*(-268) -1 + j*(131) --219 + j*(-175) --100 + j*(69) -34 + j*(-469) -199 + j*(177) -305 + j*(-176) --184 + j*(-29) --332 + j*(50) -309 + j*(93) --19 + j*(-73) --21 + j*(-3) -56 + j*(81) -171 + j*(-164) -62 + j*(-228) --21 + j*(-373) --88 + j*(-193) -201 + j*(-6) -340 + j*(-322) -207 + j*(7) --89 + j*(-211) --206 + j*(12) --161 + j*(-84) -49 + j*(-272) -132 + j*(-129) --126 + j*(304) -26 + j*(66) --39 + j*(84) --228 + j*(-138) -71 + j*(13) --27 + j*(-319) -157 + j*(104) -98 + j*(291) -187 + j*(-319) -287 + j*(52) --91 + j*(228) --42 + j*(-133) -297 + j*(-35) -28 + j*(-127) -50 + j*(38) -253 + j*(-35) -126 + j*(-69) -153 + j*(-41) --141 + j*(203) --63 + j*(-108) --69 + j*(-134) -274 + j*(273) -255 + j*(-329) -202 + j*(31) --158 + j*(-15) -240 + j*(122) --249 + j*(205) --29 + j*(171) --209 + j*(28) -146 + j*(-77) -124 + j*(-155) --21 + j*(-257) -342 + j*(292) --75 + j*(145) --37 + j*(199) -124 + j*(317) -198 + j*(48) -197 + j*(35) --71 + j*(-55) -235 + j*(-358) --136 + j*(62) --121 + j*(-194) --129 + j*(190) -126 + j*(160) -153 + j*(154) -223 + j*(-95) -78 + j*(-270) -447 + j*(60) --184 + j*(-173) --121 + j*(-134) -141 + j*(-25) -179 + j*(-190) -26 + j*(305) --180 + j*(-13) -123 + j*(-4) -130 + j*(-310) --42 + j*(-91) -71 + j*(286) --192 + j*(33) -130 + j*(206) -147 + j*(2) --38 + j*(-156) -1 + j*(327) --34 + j*(-42) --254 + j*(-168) -189 + j*(227) -143 + j*(32) --211 + j*(-264) --39 + j*(-439) --24 + j*(271) --25 + j*(110) -190 + j*(-4) --102 + j*(-243) --13 + j*(40) --87 + j*(55) -156 + j*(89) -295 + j*(-50) -210 + j*(-263) --303 + j*(70) -86 + j*(-102) --68 + j*(4) -79 + j*(-426) --152 + j*(-158) -93 + j*(36) -52 + j*(-144) -27 + j*(-280) -58 + j*(-16) -82 + j*(2) -57 + j*(-151) --76 + j*(-21) --67 + j*(125) -233 + j*(-44) -72 + j*(-83) -203 + j*(52) --35 + j*(0) -140 + j*(-147) -110 + j*(144) -96 + j*(23) -288 + j*(-122) --67 + j*(85) -300 + j*(-56) --262 + j*(39) -201 + j*(233) --20 + j*(151) --323 + j*(-35) -49 + j*(143) --89 + j*(-158) --66 + j*(-216) --244 + j*(163) -240 + j*(-245) -364 + j*(-71) --205 + j*(280) -66 + j*(-18) --58 + j*(144) -141 + j*(-151) -154 + j*(-25) -202 + j*(-83) -33 + j*(-127) --166 + j*(-157) -451 + j*(-244) --101 + j*(35) -18 + j*(134) -134 + j*(252) --95 + j*(-264) -320 + j*(211) --54 + j*(-52) --145 + j*(122) --10 + j*(247) --359 + j*(164) --93 + j*(-90) --141 + j*(199) --122 + j*(-140) --384 + j*(-230) -34 + j*(2) --190 + j*(276) --49 + j*(185) -197 + j*(-12) --213 + j*(-105) --110 + j*(-62) --1 + j*(163) -54 + j*(12) -74 + j*(-148) --130 + j*(221) --86 + j*(161) -86 + j*(50) --110 + j*(-74) -129 + j*(256) -25 + j*(-84) --35 + j*(-124) -71 + j*(-105) -274 + j*(-267) -298 + j*(-52) --1 + j*(116) -220 + j*(-17) -147 + j*(126) -69 + j*(53) --208 + j*(-60) -197 + j*(115) --140 + j*(13) -122 + j*(-74) -36 + j*(194) --40 + j*(-26) --126 + j*(97) -288 + j*(115) --142 + j*(127) --20 + j*(-21) --117 + j*(79) --73 + j*(308) --430 + j*(132) --129 + j*(161) -83 + j*(56) --63 + j*(-355) --139 + j*(132) -206 + j*(8) -19 + j*(-193) -156 + j*(-25) -20 + j*(-277) -74 + j*(207) --312 + j*(-97) --264 + j*(127) -219 + j*(69) --16 + j*(126) -92 + j*(-206) --227 + j*(164) --172 + j*(-120) -158 + j*(-31) -110 + j*(83) --103 + j*(6) --22 + j*(120) -110 + j*(93) -37 + j*(-170) --148 + j*(136) --23 + j*(12) -59 + j*(61) -117 + j*(119) -163 + j*(283) -263 + j*(95) -334 + j*(65) --169 + j*(80) --129 + j*(543) --163 + j*(179) -46 + j*(193) --177 + j*(232) -206 + j*(13) -203 + j*(67) -42 + j*(31) -119 + j*(-159) --98 + j*(104) -68 + j*(70) -91 + j*(155) -55 + j*(-175) -88 + j*(-54) --148 + j*(-14) -405 + j*(30) -250 + j*(-249) -6 + j*(234) -71 + j*(69) -57 + j*(-92) -194 + j*(44) --104 + j*(175) -136 + j*(-145) -137 + j*(-80) -110 + j*(-363) -240 + j*(-14) --110 + j*(158) --57 + j*(28) --112 + j*(-86) -25 + j*(192) -139 + j*(-252) --250 + j*(-42) -25 + j*(61) --235 + j*(-152) -310 + j*(-206) --341 + j*(-164) --113 + j*(4) --62 + j*(-13) -216 + j*(90) --45 + j*(-161) --129 + j*(-240) -124 + j*(173) -66 + j*(180) -80 + j*(-23) --62 + j*(144) -28 + j*(-5) -115 + j*(184) -75 + j*(-197) --325 + j*(100) -94 + j*(-126) --78 + j*(-344) --107 + j*(302) --243 + j*(-243) -62 + j*(227) --15 + j*(-337) --49 + j*(-74) -88 + j*(134) --91 + j*(81) --34 + j*(103) --112 + j*(233) -253 + j*(151) --45 + j*(-25) -212 + j*(-127) --363 + j*(66) -251 + j*(12) -267 + j*(27) -280 + j*(-414) -136 + j*(131) --32 + j*(-176) -136 + j*(31) --139 + j*(171) -185 + j*(103) -84 + j*(198) -88 + j*(81) -104 + j*(-158) -301 + j*(298) -63 + j*(260) -210 + j*(-169) -112 + j*(-52) --64 + j*(119) --169 + j*(-281) --83 + j*(-310) -274 + j*(-79) -209 + j*(-182) --107 + j*(-240) --86 + j*(4) -202 + j*(16) --387 + j*(75) --81 + j*(85) -17 + j*(260) --348 + j*(-243) --39 + j*(88) -259 + j*(-40) -37 + j*(13) -157 + j*(-121) -40 + j*(-37) -267 + j*(-28) -85 + j*(47) --310 + j*(52) -25 + j*(33) --366 + j*(-264) --58 + j*(120) -36 + j*(-93) -187 + j*(6) -93 + j*(23) -44 + j*(-240) -235 + j*(161) -197 + j*(293) --153 + j*(126) -211 + j*(-71) -213 + j*(-42) -176 + j*(-6) --176 + j*(-40) -33 + j*(64) --81 + j*(-133) -52 + j*(256) -160 + j*(-141) -118 + j*(187) --212 + j*(26) --257 + j*(157) -192 + j*(18) -199 + j*(295) -49 + j*(-94) -2 + j*(208) --83 + j*(-170) --226 + j*(-139) --197 + j*(18) -40 + j*(-130) -144 + j*(-136) -107 + j*(19) --102 + j*(472) --53 + j*(-39) -5 + j*(265) -173 + j*(256) --349 + j*(40) -54 + j*(-140) -66 + j*(132) -64 + j*(73) --141 + j*(95) -327 + j*(-69) --547 + j*(115) -59 + j*(-115) --62 + j*(69) -81 + j*(182) --86 + j*(-208) --100 + j*(-318) -127 + j*(213) -93 + j*(16) -243 + j*(-7) --23 + j*(333) --21 + j*(330) -74 + j*(-50) --40 + j*(-168) -434 + j*(333) -81 + j*(-143) -230 + j*(163) -209 + j*(-187) --33 + j*(270) -132 + j*(-217) --127 + j*(-35) --59 + j*(40) -187 + j*(32) --11 + j*(-143) -156 + j*(245) --18 + j*(-28) --166 + j*(-27) -332 + j*(145) -8 + j*(-192) --11 + j*(-185) --190 + j*(72) --118 + j*(138) -112 + j*(215) --26 + j*(52) -137 + j*(29) --200 + j*(-123) -183 + j*(-187) -93 + j*(35) --336 + j*(-33) -28 + j*(223) --1 + j*(-18) --234 + j*(98) -117 + j*(25) -132 + j*(-174) --430 + j*(-3) -52 + j*(-205) -95 + j*(148) --55 + j*(-199) -20 + j*(-107) --113 + j*(-80) -51 + j*(26) --13 + j*(79) --182 + j*(20) --71 + j*(-19) --16 + j*(-290) --197 + j*(204) -42 + j*(-184) --63 + j*(52) -16 + j*(-112) -164 + j*(-293) --39 + j*(113) -267 + j*(-49) -259 + j*(-80) --65 + j*(55) -151 + j*(112) --21 + j*(113) -64 + j*(-163) -71 + j*(28) -155 + j*(126) -226 + j*(47) -173 + j*(195) -11 + j*(-218) -87 + j*(-64) -126 + j*(-53) -34 + j*(-310) -225 + j*(-183) --148 + j*(-328) -210 + j*(-400) -289 + j*(49) -3 + j*(-170) -231 + j*(54) -136 + j*(21) --83 + j*(273) -108 + j*(251) -429 + j*(277) -6 + j*(294) -103 + j*(207) -16 + j*(-199) -187 + j*(28) -16 + j*(51) -232 + j*(51) --148 + j*(9) -77 + j*(-168) -42 + j*(279) -132 + j*(265) -145 + j*(-90) --49 + j*(-211) -90 + j*(144) -156 + j*(3) -27 + j*(-264) -302 + j*(23) -148 + j*(-5) --119 + j*(-27) --100 + j*(-138) --182 + j*(-56) --303 + j*(333) --101 + j*(162) -311 + j*(-143) --27 + j*(-283) --215 + j*(-93) --64 + j*(120) --10 + j*(-337) --204 + j*(48) --91 + j*(-95) -113 + j*(-223) --68 + j*(-86) -91 + j*(-162) -383 + j*(534) -331 + j*(-151) -296 + j*(-125) --534 + j*(195) -68 + j*(341) --64 + j*(338) -202 + j*(199) -277 + j*(-187) -10 + j*(-149) --89 + j*(-287) -356 + j*(-535) -136 + j*(225) -221 + j*(-13) -245 + j*(105) --55 + j*(-260) --246 + j*(-332) --146 + j*(315) --602 + j*(-237) --329 + j*(238) --173 + j*(-174) -562 + j*(83) --189 + j*(-310) -339 + j*(361) --309 + j*(-162) -81 + j*(317) -445 + j*(-265) --183 + j*(343) --302 + j*(33) --663 + j*(180) --257 + j*(-70) -515 + j*(252) -192 + j*(334) --560 + j*(68) -214 + j*(11) --463 + j*(-437) -66 + j*(286) --305 + j*(236) --332 + j*(40) --180 + j*(-321) -420 + j*(-76) -63 + j*(-168) -243 + j*(-251) -176 + j*(-378) -328 + j*(303) --270 + j*(353) --407 + j*(-240) -257 + j*(207) --107 + j*(-203) --100 + j*(-153) -635 + j*(335) -45 + j*(52) -251 + j*(-25) -238 + j*(232) --268 + j*(-144) -183 + j*(-70) --237 + j*(-222) -231 + j*(274) --132 + j*(372) -383 + j*(50) --187 + j*(195) -81 + j*(156) --145 + j*(-689) -139 + j*(312) --162 + j*(419) -387 + j*(-187) --168 + j*(-233) --344 + j*(184) --337 + j*(-478) -737 + j*(-88) --106 + j*(486) -44 + j*(226) --293 + j*(100) -532 + j*(-33) -534 + j*(-52) --527 + j*(431) --438 + j*(-312) -223 + j*(-175) -149 + j*(367) -132 + j*(-694) -406 + j*(306) -222 + j*(-339) --68 + j*(493) -348 + j*(123) -16 + j*(-402) -125 + j*(-231) --468 + j*(-245) -304 + j*(74) -439 + j*(423) --438 + j*(18) --686 + j*(327) --150 + j*(98) -303 + j*(147) -411 + j*(-9) --298 + j*(103) --185 + j*(-97) --288 + j*(-369) -393 + j*(-370) -491 + j*(433) -412 + j*(146) --167 + j*(-435) -199 + j*(-350) -316 + j*(-90) -204 + j*(-154) --333 + j*(-12) -682 + j*(-197) --139 + j*(439) --306 + j*(49) --281 + j*(-679) -454 + j*(-212) -444 + j*(508) -106 + j*(-67) --122 + j*(-80) -268 + j*(196) -587 + j*(-342) --275 + j*(379) -443 + j*(-190) --606 + j*(199) --108 + j*(524) --202 + j*(201) --395 + j*(-388) -511 + j*(-591) --265 + j*(-98) -224 + j*(189) -231 + j*(-250) -45 + j*(-397) --286 + j*(-167) -230 + j*(40) -346 + j*(395) --400 + j*(635) -43 + j*(-228) -397 + j*(149) --160 + j*(520) -204 + j*(213) -335 + j*(398) -344 + j*(504) --11 + j*(-309) -59 + j*(-37) --390 + j*(-374) --361 + j*(518) -386 + j*(131) -233 + j*(-187) -356 + j*(23) --157 + j*(-261) --451 + j*(-523) -167 + j*(593) -209 + j*(119) --730 + j*(-56) --219 + j*(-598) -29 + j*(250) -79 + j*(392) -300 + j*(158) -276 + j*(-165) -72 + j*(-346) --245 + j*(-170) -455 + j*(-394) -48 + j*(315) -33 + j*(-81) -201 + j*(127) --37 + j*(51) -196 + j*(180) --62 + j*(416) -267 + j*(252) --242 + j*(-452) --8 + j*(397) -124 + j*(40) --264 + j*(-126) -42 + j*(404) -558 + j*(103) --327 + j*(35) --510 + j*(528) --561 + j*(-597) --349 + j*(-397) -41 + j*(214) --334 + j*(462) -98 + j*(-105) --75 + j*(229) -245 + j*(-116) -330 + j*(186) --81 + j*(434) -488 + j*(200) --124 + j*(-164) --8 + j*(68) --88 + j*(373) --312 + j*(-402) -103 + j*(267) -683 + j*(217) --341 + j*(67) --280 + j*(350) -492 + j*(-231) --211 + j*(-218) -240 + j*(316) -364 + j*(272) -370 + j*(453) -253 + j*(171) -184 + j*(663) --333 + j*(-392) --192 + j*(-409) -384 + j*(-292) -220 + j*(-143) --284 + j*(242) -118 + j*(-272) -170 + j*(-47) -422 + j*(-353) -494 + j*(-685) --88 + j*(95) -264 + j*(232) -153 + j*(175) -168 + j*(205) --126 + j*(-213) --51 + j*(390) --283 + j*(40) --361 + j*(689) -171 + j*(-141) -435 + j*(-318) --141 + j*(-260) -220 + j*(-144) -286 + j*(155) --310 + j*(299) -78 + j*(-204) -373 + j*(273) --321 + j*(723) -707 + j*(-203) -324 + j*(102) --177 + j*(-383) -245 + j*(-99) --380 + j*(339) -235 + j*(-375) --292 + j*(77) -23 + j*(-351) -330 + j*(-171) -211 + j*(167) -455 + j*(-540) --448 + j*(-230) -215 + j*(263) -137 + j*(373) --66 + j*(-47) --300 + j*(-85) -302 + j*(177) --442 + j*(197) --46 + j*(132) --419 + j*(214) --166 + j*(92) --184 + j*(447) -94 + j*(342) --328 + j*(-42) --552 + j*(-458) -374 + j*(-177) -300 + j*(404) -40 + j*(219) --228 + j*(-505) -272 + j*(266) --192 + j*(200) -213 + j*(-150) -274 + j*(-355) -492 + j*(54) -541 + j*(-602) -460 + j*(-52) -98 + j*(449) -382 + j*(-380) --153 + j*(-241) --250 + j*(-45) --245 + j*(-315) -264 + j*(-289) -154 + j*(-177) -146 + j*(-441) --336 + j*(285) --102 + j*(388) -236 + j*(-18) --115 + j*(335) --532 + j*(421) -484 + j*(450) -354 + j*(738) --416 + j*(523) --293 + j*(-193) -115 + j*(-764) --327 + j*(-238) --425 + j*(-378) --269 + j*(-413) --642 + j*(-380) --43 + j*(-7) -206 + j*(424) -244 + j*(-416) -453 + j*(-545) --165 + j*(-64) --138 + j*(-312) --499 + j*(484) --307 + j*(-119) -122 + j*(578) --266 + j*(-390) --218 + j*(395) --188 + j*(-14) -373 + j*(-118) -86 + j*(629) --435 + j*(-107) -390 + j*(-469) -197 + j*(-99) -343 + j*(-344) --137 + j*(-218) --252 + j*(354) --261 + j*(329) --214 + j*(393) --247 + j*(274) -214 + j*(158) -74 + j*(315) -434 + j*(-211) --228 + j*(-161) --86 + j*(482) -41 + j*(197) --110 + j*(217) -182 + j*(16) -437 + j*(-583) -446 + j*(-162) --139 + j*(122) -117 + j*(368) -173 + j*(179) -245 + j*(-228) -78 + j*(450) --484 + j*(-112) --375 + j*(-177) --265 + j*(-155) -185 + j*(-10) -635 + j*(-213) --59 + j*(223) -306 + j*(-93) -8 + j*(-310) -201 + j*(333) -482 + j*(-70) --78 + j*(115) -390 + j*(564) -433 + j*(280) -52 + j*(25) -185 + j*(328) -273 + j*(-367) --156 + j*(255) -177 + j*(-170) --181 + j*(207) --466 + j*(-256) --279 + j*(-97) -444 + j*(-466) --105 + j*(308) -71 + j*(-127) --1 + j*(6) -171 + j*(163) --357 + j*(440) -346 + j*(97) --366 + j*(-355) --149 + j*(-342) --72 + j*(-146) -120 + j*(185) -190 + j*(237) --53 + j*(-444) -340 + j*(68) -103 + j*(7) -210 + j*(183) -282 + j*(-173) -240 + j*(373) --112 + j*(463) --187 + j*(262) --260 + j*(-234) --33 + j*(217) --347 + j*(2) -229 + j*(-414) -163 + j*(284) -121 + j*(61) --286 + j*(439) -403 + j*(112) --290 + j*(122) -339 + j*(151) -339 + j*(-290) -349 + j*(-248) --403 + j*(315) --318 + j*(-601) --293 + j*(-348) -279 + j*(-15) -79 + j*(-222) --458 + j*(-433) -625 + j*(-496) --81 + j*(204) --222 + j*(-499) --486 + j*(-186) --113 + j*(-105) --199 + j*(-497) -351 + j*(174) -347 + j*(-373) -233 + j*(49) --64 + j*(-416) -264 + j*(-139) -33 + j*(494) -281 + j*(180) --412 + j*(-375) --318 + j*(502) --265 + j*(274) --260 + j*(175) -167 + j*(-491) -647 + j*(236) --25 + j*(238) --326 + j*(-495) -100 + j*(-313) -173 + j*(-786) --98 + j*(231) --238 + j*(409) -361 + j*(-446) -538 + j*(-350) --127 + j*(-153) --576 + j*(-199) --72 + j*(-510) -363 + j*(-360) --482 + j*(-238) --352 + j*(-363) --295 + j*(-104) --119 + j*(212) -297 + j*(351) --268 + j*(-371) -97 + j*(53) -235 + j*(90) -209 + j*(298) --212 + j*(-276) --309 + j*(551) --54 + j*(-273) -225 + j*(457) -37 + j*(-149) --81 + j*(202) -345 + j*(300) --322 + j*(247) -202 + j*(425) --215 + j*(-173) --123 + j*(297) --227 + j*(19) --170 + j*(-366) -344 + j*(-305) -369 + j*(-191) --318 + j*(525) -332 + j*(-325) --337 + j*(-318) --655 + j*(564) -595 + j*(-511) -436 + j*(384) --515 + j*(40) -243 + j*(-459) --21 + j*(156) -258 + j*(-438) --357 + j*(-326) --433 + j*(583) --357 + j*(-489) -171 + j*(-34) -122 + j*(402) --289 + j*(339) -160 + j*(189) -94 + j*(-71) -453 + j*(-301) -292 + j*(-117) -338 + j*(216) -363 + j*(400) --43 + j*(-35) -217 + j*(85) -33 + j*(241) -173 + j*(-141) --266 + j*(-306) --264 + j*(-451) -226 + j*(-296) -350 + j*(-16) -30 + j*(312) --566 + j*(-133) --195 + j*(219) -478 + j*(-61) --612 + j*(-527) --189 + j*(-585) --466 + j*(-600) --288 + j*(445) --460 + j*(245) -171 + j*(-448) --258 + j*(520) --379 + j*(-194) -369 + j*(-410) --213 + j*(144) -128 + j*(-40) -308 + j*(277) --37 + j*(-508) -226 + j*(-127) -290 + j*(285) --506 + j*(-353) --356 + j*(-194) -298 + j*(307) -161 + j*(499) -267 + j*(157) -117 + j*(-136) -494 + j*(-658) -103 + j*(-286) -415 + j*(465) -233 + j*(-156) -110 + j*(-371) --428 + j*(196) --377 + j*(269) --234 + j*(127) --321 + j*(-78) -282 + j*(-223) --310 + j*(-246) -45 + j*(146) -5 + j*(38) --182 + j*(239) --430 + j*(453) -414 + j*(-105) --527 + j*(147) --12 + j*(554) --296 + j*(-168) --147 + j*(-170) --504 + j*(-331) --313 + j*(-380) -453 + j*(429) --463 + j*(-119) --175 + j*(-387) -251 + j*(403) --143 + j*(187) -208 + j*(-498) -434 + j*(-214) -600 + j*(-360) --251 + j*(28) -373 + j*(-204) --305 + j*(-288) --243 + j*(356) -53 + j*(-467) -127 + j*(226) --412 + j*(-91) -325 + j*(371) -347 + j*(-487) -332 + j*(327) --226 + j*(-306) -482 + j*(-47) --62 + j*(397) -363 + j*(-184) -192 + j*(257) --390 + j*(-347) --15 + j*(-159) -434 + j*(-467) -347 + j*(-162) -374 + j*(-216) --197 + j*(-21) -195 + j*(679) -317 + j*(451) -206 + j*(400) -420 + j*(421) --190 + j*(-107) --141 + j*(192) -452 + j*(364) --550 + j*(44) --141 + j*(-274) --459 + j*(409) -466 + j*(-351) --178 + j*(103) --378 + j*(351) --213 + j*(132) --322 + j*(102) --244 + j*(-537) --252 + j*(-467) --266 + j*(483) -433 + j*(-273) --180 + j*(-474) -69 + j*(-356) -412 + j*(-295) --36 + j*(-529) --588 + j*(194) --10 + j*(-25) --446 + j*(-204) --380 + j*(1) --481 + j*(-128) --271 + j*(151) --303 + j*(-184) -272 + j*(-253) -102 + j*(284) --153 + j*(66) -100 + j*(-302) -385 + j*(-581) -259 + j*(605) -205 + j*(-482) --288 + j*(-276) -197 + j*(-288) --398 + j*(325) -358 + j*(-357) -104 + j*(-474) -735 + j*(38) -306 + j*(-162) -121 + j*(-267) --480 + j*(272) --13 + j*(-94) --146 + j*(131) --484 + j*(-257) --64 + j*(227) -178 + j*(19) -212 + j*(450) -17 + j*(-184) --406 + j*(-301) --424 + j*(252) --194 + j*(444) --550 + j*(-138) -361 + j*(424) --308 + j*(-156) --251 + j*(-183) -293 + j*(-98) --271 + j*(249) --317 + j*(-79) --42 + j*(276) --88 + j*(217) -1 + j*(327) --53 + j*(250) --42 + j*(-334) -154 + j*(70) -262 + j*(-33) --1 + j*(-104) -35 + j*(-118) -57 + j*(455) -247 + j*(-148) -0 + j*(62) --200 + j*(193) -62 + j*(-139) -95 + j*(111) -291 + j*(-154) --135 + j*(118) -66 + j*(-148) --337 + j*(192) --247 + j*(-26) --13 + j*(-40) --412 + j*(-91) --66 + j*(-206) -91 + j*(179) --189 + j*(407) --152 + j*(35) -187 + j*(28) -206 + j*(7) -242 + j*(-28) --71 + j*(-75) --187 + j*(-48) -240 + j*(-105) --122 + j*(-187) --156 + j*(163) -225 + j*(102) -52 + j*(198) --62 + j*(3) -171 + j*(-147) --84 + j*(-253) --1 + j*(-402) -264 + j*(140) --2 + j*(-152) -75 + j*(-168) --134 + j*(-34) -45 + j*(155) --164 + j*(135) -334 + j*(281) --71 + j*(-170) -296 + j*(-413) -44 + j*(260) -197 + j*(204) -71 + j*(2) -119 + j*(-129) -169 + j*(68) --196 + j*(198) -170 + j*(-124) --120 + j*(-8) -102 + j*(-120) --578 + j*(93) -71 + j*(239) --218 + j*(91) --206 + j*(9) --287 + j*(-461) --260 + j*(-65) -28 + j*(-45) --26 + j*(132) --86 + j*(-8) -0 + j*(-16) --86 + j*(499) --49 + j*(352) -14 + j*(108) -299 + j*(-55) --255 + j*(-81) --375 + j*(228) --125 + j*(66) --107 + j*(159) --199 + j*(-283) -158 + j*(-206) -241 + j*(-91) --44 + j*(4) --288 + j*(127) --19 + j*(-119) -83 + j*(-223) -76 + j*(-191) --19 + j*(64) -205 + j*(-267) -209 + j*(100) -290 + j*(175) -96 + j*(12) -71 + j*(15) -231 + j*(70) -127 + j*(-37) --153 + j*(195) -29 + j*(189) --30 + j*(-94) --55 + j*(-209) -338 + j*(-214) -122 + j*(-64) --234 + j*(172) -160 + j*(-110) -142 + j*(114) -157 + j*(136) --189 + j*(-197) -28 + j*(-45) --42 + j*(-143) -171 + j*(-12) --168 + j*(163) --199 + j*(194) --265 + j*(-212) -181 + j*(-21) --267 + j*(-224) --191 + j*(110) --77 + j*(-215) -83 + j*(-106) --52 + j*(451) --60 + j*(92) --171 + j*(-199) -233 + j*(-231) --107 + j*(39) -151 + j*(42) -120 + j*(-6) --257 + j*(-182) -110 + j*(-52) --208 + j*(-26) --130 + j*(-157) -153 + j*(267) -494 + j*(-45) -178 + j*(-91) --59 + j*(-184) -137 + j*(318) --315 + j*(254) --264 + j*(-67) -42 + j*(-4) -102 + j*(62) --43 + j*(-23) --132 + j*(79) --163 + j*(-138) --132 + j*(-232) -106 + j*(50) -264 + j*(56) --172 + j*(-100) -318 + j*(147) -84 + j*(-246) -274 + j*(-330) -177 + j*(19) -185 + j*(81) -201 + j*(18) --306 + j*(110) -81 + j*(-6) -65 + j*(-186) --278 + j*(-66) -175 + j*(55) -8 + j*(107) --85 + j*(14) -300 + j*(395) --65 + j*(-403) -293 + j*(-56) --187 + j*(103) -66 + j*(-240) -66 + j*(-302) --82 + j*(-214) -194 + j*(-47) -64 + j*(-235) --372 + j*(-222) -119 + j*(-341) --323 + j*(40) --114 + j*(293) --208 + j*(-158) --95 + j*(183) -161 + j*(231) -47 + j*(-131) -102 + j*(-31) -205 + j*(-180) --40 + j*(-127) -175 + j*(-288) -79 + j*(-272) --245 + j*(3) -251 + j*(-3) --119 + j*(243) --123 + j*(-339) --290 + j*(85) --100 + j*(-175) --205 + j*(477) --24 + j*(-71) -342 + j*(-185) -66 + j*(13) --56 + j*(78) -175 + j*(-124) --228 + j*(117) --122 + j*(-62) -72 + j*(308) -222 + j*(-223) -85 + j*(47) --59 + j*(173) --97 + j*(142) -141 + j*(-108) --278 + j*(107) --141 + j*(75) -211 + j*(74) -319 + j*(-107) --98 + j*(209) --350 + j*(45) --468 + j*(-308) -332 + j*(-157) --10 + j*(-57) -21 + j*(-37) -1 + j*(-71) -151 + j*(18) --356 + j*(361) -7 + j*(-8) --87 + j*(-148) -205 + j*(-86) --9 + j*(85) -419 + j*(64) -80 + j*(60) -199 + j*(197) --187 + j*(-205) --119 + j*(228) -11 + j*(187) --212 + j*(-21) --160 + j*(121) -45 + j*(-420) --158 + j*(-173) -49 + j*(286) -204 + j*(54) -158 + j*(206) --1 + j*(-63) -119 + j*(9) -169 + j*(-116) -325 + j*(145) --106 + j*(6) --96 + j*(44) --140 + j*(253) -138 + j*(23) --431 + j*(-37) --72 + j*(5) --35 + j*(128) --165 + j*(75) --45 + j*(-158) -298 + j*(119) -105 + j*(119) -162 + j*(-16) -64 + j*(-173) --269 + j*(37) -110 + j*(-21) --16 + j*(30) -113 + j*(129) --164 + j*(-238) --189 + j*(62) -66 + j*(-142) -418 + j*(20) --264 + j*(-245) --251 + j*(76) -24 + j*(-4) -310 + j*(-84) --112 + j*(-76) --20 + j*(27) -270 + j*(-126) --241 + j*(46) --258 + j*(123) --195 + j*(-302) -294 + j*(-168) -83 + j*(-46) --121 + j*(-111) --297 + j*(-122) --269 + j*(32) --171 + j*(-107) --89 + j*(336) --180 + j*(-263) --163 + j*(-48) -265 + j*(-103) -33 + j*(22) -448 + j*(99) --49 + j*(85) -259 + j*(-72) -13 + j*(7) --156 + j*(11) --112 + j*(186) -91 + j*(-44) -127 + j*(110) -190 + j*(-151) -26 + j*(-373) -115 + j*(177) -99 + j*(-327) -60 + j*(-87) --42 + j*(-71) -80 + j*(132) -173 + j*(276) -6 + j*(177) -46 + j*(-154) -6 + j*(115) -132 + j*(156) --303 + j*(257) -105 + j*(-506) -293 + j*(82) -23 + j*(62) --563 + j*(397) -308 + j*(17) --16 + j*(-53) --22 + j*(-210) -256 + j*(190) --40 + j*(308) -181 + j*(37) --179 + j*(-71) --42 + j*(37) --258 + j*(375) --81 + j*(115) --59 + j*(287) --66 + j*(122) --1 + j*(-218) -258 + j*(-6) -78 + j*(-95) -97 + j*(-148) --255 + j*(165) -226 + j*(0) -39 + j*(-141) -175 + j*(111) -21 + j*(110) --93 + j*(288) --240 + j*(-11) --163 + j*(77) -25 + j*(110) -70 + j*(78) -51 + j*(425) --74 + j*(-186) -121 + j*(-54) -270 + j*(64) -115 + j*(-173) --143 + j*(281) -88 + j*(-247) --20 + j*(-112) -156 + j*(-362) -33 + j*(-128) -97 + j*(-328) -28 + j*(-41) -58 + j*(47) -45 + j*(13) -206 + j*(560) -94 + j*(-16) -81 + j*(41) -270 + j*(13) -68 + j*(95) --33 + j*(-120) --173 + j*(-166) --64 + j*(124) -17 + j*(-88) -99 + j*(13) --380 + j*(6) --65 + j*(219) --16 + j*(-51) -35 + j*(146) -138 + j*(74) -453 + j*(-59) -337 + j*(-5) --218 + j*(-105) --360 + j*(-43) -99 + j*(-1) --12 + j*(-76) --183 + j*(221) -52 + j*(13) -86 + j*(-76) --265 + j*(-12) -61 + j*(-264) --29 + j*(91) -20 + j*(-177) -89 + j*(-281) -276 + j*(-13) -243 + j*(-251) --140 + j*(-55) -173 + j*(23) --14 + j*(-109) -59 + j*(57) -238 + j*(-78) -50 + j*(124) -132 + j*(70) --358 + j*(21) --228 + j*(51) --16 + j*(-243) --40 + j*(267) -49 + j*(231) -309 + j*(8) -32 + j*(-109) --147 + j*(190) -232 + j*(-166) --190 + j*(-117) -18 + j*(-43) --54 + j*(129) -145 + j*(110) --202 + j*(-232) --16 + j*(64) --320 + j*(354) -69 + j*(-96) --233 + j*(165) --93 + j*(-98) --182 + j*(-310) -144 + j*(-146) -192 + j*(6) -112 + j*(146) -214 + j*(352) --153 + j*(44) --218 + j*(-5) --76 + j*(110) -18 + j*(-194) --23 + j*(-85) --4 + j*(-256) -8 + j*(1) -49 + j*(111) --108 + j*(-100) --47 + j*(214) --72 + j*(143) --351 + j*(212) --51 + j*(62) --96 + j*(173) --56 + j*(-223) -101 + j*(-143) -245 + j*(-344) --74 + j*(103) -381 + j*(-153) -76 + j*(271) --126 + j*(-9) -62 + j*(90) -72 + j*(459) --132 + j*(-227) --57 + j*(161) --294 + j*(48) --158 + j*(65) --154 + j*(-49) -21 + j*(156) --289 + j*(226) -45 + j*(79) --156 + j*(61) -50 + j*(15) --368 + j*(-200) --202 + j*(64) -344 + j*(190) -31 + j*(139) -101 + j*(95) --446 + j*(74) -254 + j*(-9) -175 + j*(28) --158 + j*(115) --173 + j*(-316) --88 + j*(-179) --18 + j*(-386) -112 + j*(144) --368 + j*(250) --233 + j*(-171) --165 + j*(16) --188 + j*(71) --41 + j*(-57) -422 + j*(47) -62 + j*(-120) -18 + j*(4) --103 + j*(-131) --21 + j*(-190) --205 + j*(-158) -268 + j*(151) --250 + j*(156) --142 + j*(-12) -99 + j*(237) -363 + j*(78) -108 + j*(-13) -291 + j*(-148) --243 + j*(486) -177 + j*(33) -117 + j*(15) --126 + j*(-1) --185 + j*(-149) -115 + j*(108) -1 + j*(-47) -58 + j*(-262) -275 + j*(-234) --83 + j*(155) -291 + j*(72) --187 + j*(147) -57 + j*(14) -25 + j*(280) -318 + j*(23) --229 + j*(223) -164 + j*(86) -293 + j*(100) --52 + j*(-40) -87 + j*(118) --8 + j*(4) -134 + j*(47) -250 + j*(376) --73 + j*(64) -104 + j*(-39) --305 + j*(-147) --419 + j*(-16) --41 + j*(8) --83 + j*(-453) --19 + j*(201) --124 + j*(-91) --175 + j*(-139) -25 + j*(144) --28 + j*(303) --339 + j*(57) --139 + j*(319) --141 + j*(11) --109 + j*(-14) --6 + j*(-254) --8 + j*(80) -319 + j*(101) -94 + j*(-40) --202 + j*(-161) --329 + j*(-263) --115 + j*(-208) -250 + j*(-221) -214 + j*(29) -297 + j*(-151) -21 + j*(-16) -3 + j*(204) -8 + j*(-18) -302 + j*(-215) --216 + j*(-25) --54 + j*(-63) --113 + j*(-21) --218 + j*(-19) -102 + j*(-134) -303 + j*(-272) --199 + j*(-87) --115 + j*(-137) --52 + j*(16) --153 + j*(-173) -228 + j*(428) --43 + j*(-187) -149 + j*(-149) --83 + j*(373) --158 + j*(512) --306 + j*(64) --59 + j*(54) --94 + j*(-110) -240 + j*(-116) -99 + j*(52) -262 + j*(-194) --152 + j*(85) --105 + j*(218) --30 + j*(-55) -187 + j*(98) -308 + j*(-119) -54 + j*(-221) -103 + j*(175) -16 + j*(129) -149 + j*(-23) -95 + j*(7) --267 + j*(-37) -2 + j*(283) --237 + j*(30) --28 + j*(-204) -18 + j*(10) --25 + j*(-262) --252 + j*(45) --7 + j*(64) -139 + j*(325) --44 + j*(-243) --94 + j*(194) -132 + j*(192) -74 + j*(-332) -212 + j*(-189) --20 + j*(83) -56 + j*(-45) --371 + j*(-122) -10 + j*(134) --163 + j*(69) --305 + j*(35) -27 + j*(-186) -106 + j*(54) -226 + j*(8) --185 + j*(50) --3 + j*(-26) -11 + j*(136) --360 + j*(-132) -192 + j*(-67) -189 + j*(-46) --23 + j*(122) --119 + j*(-45) -187 + j*(-186) -24 + j*(78) -21 + j*(-125) -433 + j*(-60) -180 + j*(-35) --166 + j*(3) -44 + j*(134) -79 + j*(26) --82 + j*(103) --180 + j*(-40) -11 + j*(49) -147 + j*(132) -10 + j*(-36) -53 + j*(-157) -170 + j*(163) -71 + j*(213) -82 + j*(-135) --56 + j*(-138) -41 + j*(-115) --190 + j*(-4) -55 + j*(199) --144 + j*(-113) --397 + j*(-207) --165 + j*(-22) -46 + j*(122) --151 + j*(-102) -124 + j*(-79) -1 + j*(-262) -313 + j*(-66) -117 + j*(54) -110 + j*(-117) --254 + j*(-152) --2 + j*(-24) --199 + j*(25) --178 + j*(-133) --164 + j*(88) --18 + j*(-30) --166 + j*(83) -18 + j*(-286) -230 + j*(100) -153 + j*(-115) -49 + j*(-59) --39 + j*(-12) --412 + j*(-168) --151 + j*(293) -81 + j*(-356) -106 + j*(11) -101 + j*(-76) --103 + j*(489) -60 + j*(327) --254 + j*(-398) --96 + j*(-74) -115 + j*(-133) --114 + j*(91) -105 + j*(23) --334 + j*(-8) -421 + j*(-191) --281 + j*(-4) -49 + j*(-26) -83 + j*(-13) -102 + j*(202) -115 + j*(214) --18 + j*(322) -201 + j*(161) -34 + j*(-37) --204 + j*(181) -412 + j*(-41) -187 + j*(-15) --11 + j*(95) --8 + j*(-322) --364 + j*(40) --148 + j*(-52) -351 + j*(-114) -244 + j*(175) --123 + j*(-182) --59 + j*(-103) --60 + j*(98) --166 + j*(83) --192 + j*(71) --187 + j*(223) --24 + j*(-272) -209 + j*(-320) --45 + j*(-89) -438 + j*(-54) --64 + j*(-235) --346 + j*(-112) --12 + j*(142) --331 + j*(-138) -78 + j*(-123) --274 + j*(28) --6 + j*(-132) --64 + j*(258) -159 + j*(-135) -146 + j*(-85) --69 + j*(-122) -12 + j*(394) --24 + j*(-233) -194 + j*(144) -105 + j*(-107) -47 + j*(33) -30 + j*(-122) --27 + j*(-21) --48 + j*(-248) -354 + j*(91) --3 + j*(54) --440 + j*(-37) --127 + j*(198) -99 + j*(-142) -252 + j*(139) --150 + j*(-184) --355 + j*(-5) -192 + j*(243) --107 + j*(259) --95 + j*(81) --345 + j*(40) --207 + j*(-141) -47 + j*(76) --118 + j*(66) --161 + j*(128) --1 + j*(186) --45 + j*(-187) -106 + j*(224) --48 + j*(-237) -35 + j*(-229) --55 + j*(-293) --54 + j*(-86) --183 + j*(79) --15 + j*(-41) --122 + j*(231) -69 + j*(-17) -100 + j*(279) -320 + j*(76) --68 + j*(-83) -107 + j*(-70) --94 + j*(158) --93 + j*(122) --141 + j*(22) -65 + j*(91) --390 + j*(-91) --216 + j*(35) -37 + j*(-191) --57 + j*(14) -57 + j*(-288) -378 + j*(344) -42 + j*(448) -38 + j*(66) --76 + j*(-260) -298 + j*(-250) -13 + j*(-370) -156 + j*(-169) -72 + j*(-215) -173 + j*(289) -194 + j*(130) --23 + j*(202) --22 + j*(298) -148 + j*(-113) --131 + j*(-168) -339 + j*(107) -172 + j*(245) --136 + j*(-105) --186 + j*(-156) --67 + j*(221) --139 + j*(-42) -151 + j*(247) --13 + j*(24) -41 + j*(139) --165 + j*(185) --55 + j*(-143) -35 + j*(-252) --148 + j*(349) --147 + j*(-26) -36 + j*(-332) --58 + j*(-306) --152 + j*(107) -157 + j*(-163) --195 + j*(68) -241 + j*(282) -18 + j*(-115) -211 + j*(-32) -185 + j*(309) --76 + j*(122) -114 + j*(6) --58 + j*(-52) --161 + j*(-116) -6 + j*(159) -141 + j*(173) --134 + j*(-146) --243 + j*(250) -38 + j*(221) --122 + j*(-24) --37 + j*(454) --119 + j*(-127) -122 + j*(-71) -52 + j*(-101) -63 + j*(-133) -8 + j*(-279) -214 + j*(-154) --467 + j*(110) -78 + j*(6) --216 + j*(-87) --147 + j*(-160) --38 + j*(161) -124 + j*(245) --56 + j*(-250) --70 + j*(-132) --235 + j*(117) --25 + j*(36) -67 + j*(-18) -115 + j*(-83) -88 + j*(278) --175 + j*(-8) -285 + j*(-65) -29 + j*(-49) --42 + j*(-153) --23 + j*(-26) -153 + j*(-66) --218 + j*(251) --37 + j*(228) --21 + j*(30) -101 + j*(-76) --5 + j*(-206) -49 + j*(37) --100 + j*(-129) -3 + j*(-216) -9 + j*(49) -247 + j*(13) --20 + j*(99) --19 + j*(134) --2 + j*(144) -153 + j*(112) -362 + j*(91) --74 + j*(-28) -211 + j*(-182) -105 + j*(226) --100 + j*(130) -37 + j*(16) -130 + j*(167) --88 + j*(-218) -143 + j*(84) -31 + j*(35) -212 + j*(390) -1 + j*(-293) --12 + j*(-161) --49 + j*(-143) --91 + j*(-130) -6 + j*(-74) --59 + j*(185) --177 + j*(92) --19 + j*(25) --232 + j*(-138) -110 + j*(103) --40 + j*(131) -3 + j*(-152) --55 + j*(105) -260 + j*(-247) -286 + j*(-23) -98 + j*(-16) -54 + j*(33) --358 + j*(-16) --146 + j*(107) --249 + j*(-199) --158 + j*(87) --72 + j*(-110) -133 + j*(-196) --141 + j*(354) -71 + j*(-152) -159 + j*(192) --162 + j*(62) -182 + j*(344) --2 + j*(14) --293 + j*(321) --41 + j*(-82) --24 + j*(225) --17 + j*(-158) --37 + j*(103) -42 + j*(-50) --33 + j*(229) --22 + j*(54) --105 + j*(-125) -343 + j*(298) --211 + j*(231) -75 + j*(-85) -181 + j*(-33) -194 + j*(205) --36 + j*(103) --325 + j*(-103) --148 + j*(-293) --143 + j*(-52) --294 + j*(16) --147 + j*(-192) --132 + j*(64) --75 + j*(-105) --279 + j*(-113) -15 + j*(-10) -103 + j*(-361) -45 + j*(315) --8 + j*(-119) --352 + j*(-97) --8 + j*(-74) --363 + j*(112) --196 + j*(67) -226 + j*(-40) -235 + j*(117) --140 + j*(47) -33 + j*(161) -149 + j*(162) --468 + j*(-17) --270 + j*(-72) --335 + j*(-178) --23 + j*(184) -156 + j*(361) -184 + j*(177) -151 + j*(141) --100 + j*(-231) --2 + j*(71) --3 + j*(103) -230 + j*(105) -50 + j*(306) --194 + j*(216) -101 + j*(-252) --187 + j*(88) --114 + j*(43) -6 + j*(124) --143 + j*(-50) --237 + j*(33) -115 + j*(144) --112 + j*(-465) -86 + j*(-54) --125 + j*(-146) -127 + j*(-179) -175 + j*(-162) -146 + j*(-141) --272 + j*(-158) -107 + j*(168) -48 + j*(143) --42 + j*(-18) -33 + j*(83) --213 + j*(269) -58 + j*(-211) --140 + j*(100) -29 + j*(-171) -311 + j*(-104) --13 + j*(127) --55 + j*(110) --191 + j*(4) --16 + j*(93) --338 + j*(255) -103 + j*(55) --88 + j*(-111) -41 + j*(49) -191 + j*(124) -145 + j*(163) -18 + j*(-132) --46 + j*(81) --59 + j*(-154) -277 + j*(179) -199 + j*(104) -40 + j*(4) --46 + j*(28) --13 + j*(-26) -89 + j*(11) --56 + j*(91) --228 + j*(-152) --7 + j*(64) -122 + j*(-274) -151 + j*(-303) --273 + j*(-251) --60 + j*(264) -49 + j*(-74) --56 + j*(-255) -445 + j*(210) -33 + j*(-155) --271 + j*(-182) --36 + j*(-136) -8 + j*(-16) --204 + j*(-123) --124 + j*(33) --139 + j*(32) -90 + j*(-192) -282 + j*(83) -48 + j*(-245) -129 + j*(98) --54 + j*(344) --18 + j*(252) --279 + j*(-146) --115 + j*(-52) -79 + j*(192) -132 + j*(22) --103 + j*(-162) --42 + j*(64) -9 + j*(-185) --132 + j*(-54) -9 + j*(129) -211 + j*(50) --164 + j*(-13) -258 + j*(-100) -194 + j*(145) --420 + j*(-276) -27 + j*(-30) --106 + j*(74) --71 + j*(378) --296 + j*(178) -190 + j*(175) -217 + j*(-64) -455 + j*(-68) -69 + j*(144) -216 + j*(6) -25 + j*(39) -39 + j*(78) --31 + j*(134) -165 + j*(-6) --160 + j*(-95) -185 + j*(-281) -71 + j*(402) --155 + j*(414) -159 + j*(-88) -302 + j*(-307) -73 + j*(-36) --81 + j*(215) -142 + j*(-110) -103 + j*(-156) -195 + j*(-28) -185 + j*(167) --89 + j*(117) --147 + j*(-75) -118 + j*(-332) --7 + j*(104) -211 + j*(-114) -201 + j*(-291) -49 + j*(88) -159 + j*(-75) --327 + j*(-508) -26 + j*(13) --387 + j*(-252) -148 + j*(-234) -23 + j*(-49) -78 + j*(-138) -189 + j*(-103) --20 + j*(117) --33 + j*(6) -149 + j*(-153) --85 + j*(-231) --127 + j*(135) --136 + j*(-206) --73 + j*(69) --134 + j*(7) --264 + j*(-69) --82 + j*(89) --248 + j*(127) -30 + j*(-12) --138 + j*(-164) -123 + j*(-185) -237 + j*(-33) --187 + j*(-103) --115 + j*(-215) -28 + j*(347) -220 + j*(131) -281 + j*(-134) --107 + j*(110) -133 + j*(-53) -204 + j*(132) --85 + j*(289) -235 + j*(-135) --145 + j*(153) --87 + j*(332) --213 + j*(-73) --153 + j*(-220) --214 + j*(-223) -59 + j*(-12) -48 + j*(-79) -11 + j*(8) --46 + j*(-181) -94 + j*(141) -39 + j*(-21) -70 + j*(-293) -145 + j*(13) -32 + j*(-18) -134 + j*(129) --110 + j*(-243) --127 + j*(292) -4 + j*(209) --139 + j*(-44) --21 + j*(-40) -35 + j*(-84) --316 + j*(-268) --195 + j*(166) --95 + j*(-24) -233 + j*(-18) -240 + j*(-88) --66 + j*(-143) -155 + j*(9) -266 + j*(235) --94 + j*(-28) -117 + j*(35) --189 + j*(9) --205 + j*(40) --74 + j*(252) --141 + j*(150) --29 + j*(-57) -49 + j*(103) --57 + j*(251) -109 + j*(95) -284 + j*(-16) -11 + j*(-96) --289 + j*(-351) --6 + j*(-222) -355 + j*(118) --139 + j*(179) --143 + j*(137) -88 + j*(-86) -243 + j*(-131) -117 + j*(-6) --489 + j*(70) -74 + j*(245) -93 + j*(88) --62 + j*(54) -218 + j*(176) --146 + j*(-126) -28 + j*(-53) -86 + j*(13) -203 + j*(153) -150 + j*(74) -200 + j*(320) -95 + j*(142) -58 + j*(156) -345 + j*(-52) --59 + j*(462) --22 + j*(-43) --160 + j*(141) -313 + j*(-104) --190 + j*(-67) -25 + j*(-103) --305 + j*(17) -53 + j*(-52) --36 + j*(-101) --67 + j*(-47) --198 + j*(202) -231 + j*(-218) --62 + j*(146) -68 + j*(-172) --148 + j*(-134) --32 + j*(-184) --378 + j*(88) --248 + j*(12) --37 + j*(-68) -11 + j*(44) --19 + j*(-67) -215 + j*(262) --190 + j*(229) --277 + j*(62) -140 + j*(-204) --219 + j*(-9) -78 + j*(-64) -249 + j*(16) --1 + j*(-115) -58 + j*(276) --94 + j*(-193) -80 + j*(-61) -333 + j*(77) -150 + j*(233) --251 + j*(-255) -0 + j*(340) --205 + j*(-45) -80 + j*(-305) -112 + j*(-45) --28 + j*(-1) --1 + j*(22) -125 + j*(-304) --276 + j*(-24) --28 + j*(-177) -117 + j*(197) -192 + j*(-29) -40 + j*(158) --304 + j*(-122) --84 + j*(-35) -160 + j*(-28) -36 + j*(110) -119 + j*(7) --35 + j*(-127) -8 + j*(33) -161 + j*(48) --65 + j*(158) --237 + j*(-220) --65 + j*(-294) -157 + j*(155) --8 + j*(-296) -18 + j*(-273) -173 + j*(-16) -136 + j*(23) -85 + j*(156) -1 + j*(144) -147 + j*(-281) --95 + j*(94) --69 + j*(-103) -165 + j*(-25) --196 + j*(257) -80 + j*(195) -31 + j*(-11) --267 + j*(-69) --208 + j*(-127) --180 + j*(-87) --90 + j*(48) -69 + j*(-47) --163 + j*(-314) --4 + j*(-166) --45 + j*(460) --5 + j*(-4) -105 + j*(-238) --240 + j*(158) --145 + j*(72) -95 + j*(-35) --4 + j*(-213) -14 + j*(182) --33 + j*(123) --385 + j*(170) -32 + j*(-27) --19 + j*(-164) --245 + j*(68) --16 + j*(-67) -226 + j*(88) --130 + j*(-112) -4 + j*(-4) --320 + j*(54) --154 + j*(-131) -184 + j*(33) -137 + j*(-269) -148 + j*(-68) --93 + j*(-13) -94 + j*(-280) -35 + j*(98) --104 + j*(-165) --71 + j*(-84) -293 + j*(-71) -247 + j*(159) --91 + j*(-63) --95 + j*(246) --124 + j*(49) --158 + j*(227) --146 + j*(-84) --185 + j*(-206) -101 + j*(129) --45 + j*(-361) --140 + j*(115) -8 + j*(-83) --426 + j*(-45) -365 + j*(-120) --115 + j*(98) --247 + j*(192) -23 + j*(39) --22 + j*(205) -30 + j*(40) -196 + j*(-71) --74 + j*(193) -76 + j*(-51) --123 + j*(-93) --37 + j*(-251) --26 + j*(170) --263 + j*(43) --42 + j*(-224) -214 + j*(153) --33 + j*(86) --137 + j*(158) -148 + j*(122) -68 + j*(26) -341 + j*(-75) -121 + j*(96) -74 + j*(-235) -25 + j*(-41) -50 + j*(141) --183 + j*(69) -74 + j*(-94) -119 + j*(-129) -55 + j*(5) --132 + j*(267) --167 + j*(-24) --273 + j*(139) -270 + j*(59) --114 + j*(-62) -46 + j*(63) --74 + j*(42) -378 + j*(-223) -27 + j*(122) -121 + j*(372) -278 + j*(116) --33 + j*(-276) -9 + j*(-49) --403 + j*(138) --5 + j*(342) --109 + j*(-95) --31 + j*(-43) -62 + j*(-186) -163 + j*(-233) --28 + j*(144) -194 + j*(93) -69 + j*(-206) -180 + j*(-120) --72 + j*(-62) --52 + j*(-166) -81 + j*(128) -239 + j*(-315) -30 + j*(-97) -194 + j*(-300) -26 + j*(197) -12 + j*(-54) --13 + j*(146) -322 + j*(55) --341 + j*(-282) -29 + j*(-225) --91 + j*(7) --160 + j*(64) -7 + j*(-127) -28 + j*(-158) --97 + j*(283) --276 + j*(62) --53 + j*(-362) -59 + j*(18) -227 + j*(-390) --86 + j*(132) --105 + j*(-513) --87 + j*(29) -35 + j*(-110) -18 + j*(47) -180 + j*(-45) --112 + j*(5) -44 + j*(-31) --144 + j*(66) --284 + j*(187) --373 + j*(183) -66 + j*(-160) -378 + j*(209) --360 + j*(-33) --181 + j*(-174) -31 + j*(-209) -66 + j*(-187) --224 + j*(-27) --118 + j*(-124) -16 + j*(156) --29 + j*(163) --112 + j*(69) --10 + j*(191) -114 + j*(-103) -8 + j*(16) --132 + j*(105) --221 + j*(211) --187 + j*(-11) -100 + j*(-49) --27 + j*(52) --62 + j*(1) -48 + j*(-86) --243 + j*(296) --307 + j*(-22) -47 + j*(-23) --126 + j*(-111) --93 + j*(-12) --46 + j*(-265) -71 + j*(-1) --52 + j*(42) --180 + j*(344) -78 + j*(-95) --167 + j*(-28) --293 + j*(196) -247 + j*(63) -112 + j*(383) -225 + j*(-232) -97 + j*(-60) --57 + j*(-233) --180 + j*(-136) -130 + j*(-187) --62 + j*(-65) -13 + j*(14) --9 + j*(267) --243 + j*(-458) -21 + j*(267) --57 + j*(-45) --148 + j*(130) -86 + j*(251) --366 + j*(93) --375 + j*(302) -107 + j*(-11) --12 + j*(-207) -198 + j*(-397) --346 + j*(15) --19 + j*(177) -28 + j*(-23) --87 + j*(-81) --164 + j*(-117) --184 + j*(42) --43 + j*(231) --49 + j*(-143) --209 + j*(-252) --344 + j*(171) -261 + j*(200) -210 + j*(2) --78 + j*(18) -120 + j*(-31) --46 + j*(37) -105 + j*(228) -252 + j*(-62) -76 + j*(190) --200 + j*(-88) -112 + j*(31) -97 + j*(46) --14 + j*(191) -122 + j*(70) --110 + j*(132) -52 + j*(-151) --161 + j*(69) -74 + j*(228) --170 + j*(41) --59 + j*(-354) --98 + j*(325) -64 + j*(-64) --235 + j*(175) --230 + j*(-93) -83 + j*(-48) --274 + j*(-86) -133 + j*(-92) --118 + j*(190) --192 + j*(232) -107 + j*(226) --178 + j*(-91) --45 + j*(35) -212 + j*(194) -38 + j*(-66) -2 + j*(142) -156 + j*(296) --62 + j*(38) -34 + j*(-358) --133 + j*(-114) -94 + j*(80) --299 + j*(41) -23 + j*(264) --223 + j*(515) --82 + j*(-98) --180 + j*(175) --160 + j*(-163) --42 + j*(81) --110 + j*(-93) --95 + j*(-186) --182 + j*(-190) -29 + j*(-227) -36 + j*(107) --25 + j*(-239) --147 + j*(-128) -214 + j*(178) --144 + j*(-26) --162 + j*(210) --1 + j*(-170) --182 + j*(76) --214 + j*(272) -209 + j*(112) --335 + j*(199) -202 + j*(93) -192 + j*(-119) --160 + j*(65) -231 + j*(-61) --37 + j*(-151) -77 + j*(114) -293 + j*(34) --203 + j*(-176) --164 + j*(142) --233 + j*(269) --45 + j*(227) -313 + j*(74) --52 + j*(210) --396 + j*(-31) --111 + j*(-95) --11 + j*(83) -112 + j*(246) --59 + j*(95) -196 + j*(121) --364 + j*(-285) -139 + j*(284) --301 + j*(-78) --274 + j*(-334) --413 + j*(-324) -25 + j*(-57) --251 + j*(-60) -552 + j*(-140) -98 + j*(559) -452 + j*(-165) -334 + j*(-16) --477 + j*(-221) --273 + j*(82) --170 + j*(127) -600 + j*(348) -412 + j*(187) -392 + j*(393) -356 + j*(-431) --303 + j*(-270) --383 + j*(388) -107 + j*(-441) --371 + j*(155) -385 + j*(398) --262 + j*(-58) -244 + j*(-265) -494 + j*(359) --245 + j*(214) -141 + j*(-274) -281 + j*(-645) -252 + j*(222) --252 + j*(-163) --350 + j*(371) -143 + j*(-293) --426 + j*(-419) -107 + j*(-83) --183 + j*(-363) -431 + j*(-91) --557 + j*(-171) --7 + j*(576) -393 + j*(-195) --415 + j*(387) -95 + j*(-383) -56 + j*(156) -223 + j*(433) --670 + j*(232) --78 + j*(192) -327 + j*(187) --47 + j*(-198) --47 + j*(379) -158 + j*(-204) -170 + j*(40) -120 + j*(-402) --57 + j*(-609) -363 + j*(197) -572 + j*(240) -159 + j*(277) -51 + j*(594) -284 + j*(-165) --221 + j*(406) --83 + j*(-173) -248 + j*(-268) --106 + j*(67) --233 + j*(330) --208 + j*(-184) -414 + j*(-62) --170 + j*(609) --309 + j*(177) -278 + j*(-119) -611 + j*(251) --67 + j*(438) -354 + j*(87) -344 + j*(225) -388 + j*(190) -386 + j*(273) --235 + j*(-399) -450 + j*(89) --129 + j*(-380) -307 + j*(-317) -6 + j*(454) --21 + j*(683) -382 + j*(607) -26 + j*(269) -397 + j*(394) -525 + j*(-202) --373 + j*(-337) -607 + j*(363) -142 + j*(235) -320 + j*(-230) -276 + j*(223) --82 + j*(-39) --41 + j*(374) -298 + j*(313) --453 + j*(136) --487 + j*(-484) --50 + j*(214) --265 + j*(259) --185 + j*(-32) --268 + j*(6) -335 + j*(414) --385 + j*(-177) --438 + j*(-168) --153 + j*(475) --93 + j*(223) --279 + j*(283) -481 + j*(-119) -2 + j*(-363) -571 + j*(346) -342 + j*(143) --379 + j*(175) --30 + j*(-334) --431 + j*(237) -113 + j*(-408) -420 + j*(-398) --101 + j*(-35) --363 + j*(77) --421 + j*(129) -378 + j*(166) --316 + j*(-40) -402 + j*(-251) -22 + j*(-351) -223 + j*(-376) -273 + j*(599) --213 + j*(30) -269 + j*(-317) -209 + j*(357) --156 + j*(517) -97 + j*(504) -296 + j*(-239) -65 + j*(1) -278 + j*(342) --175 + j*(-567) -325 + j*(-247) --455 + j*(-64) -512 + j*(-163) -148 + j*(542) -183 + j*(273) --224 + j*(53) -327 + j*(256) -124 + j*(-139) -63 + j*(124) --57 + j*(-381) -112 + j*(-13) -269 + j*(-236) --104 + j*(-487) --227 + j*(-422) -434 + j*(-423) -387 + j*(-274) --118 + j*(110) -197 + j*(342) --96 + j*(300) -413 + j*(-33) --184 + j*(-374) -451 + j*(68) -435 + j*(-132) --244 + j*(-332) -482 + j*(296) -500 + j*(-520) -41 + j*(-66) --137 + j*(678) --433 + j*(361) --573 + j*(576) --350 + j*(255) --185 + j*(-711) -491 + j*(403) --203 + j*(-359) -36 + j*(-153) --199 + j*(-299) -312 + j*(-607) -17 + j*(82) --284 + j*(311) --651 + j*(349) --317 + j*(-525) -461 + j*(-175) --272 + j*(-30) --433 + j*(392) --204 + j*(242) --132 + j*(330) -37 + j*(-193) -461 + j*(-472) --188 + j*(-404) -136 + j*(434) -489 + j*(-688) --261 + j*(-331) --79 + j*(323) --181 + j*(-231) -236 + j*(483) -294 + j*(-152) -118 + j*(-52) -286 + j*(299) -353 + j*(-41) --250 + j*(262) --332 + j*(385) --1 + j*(-199) -547 + j*(-29) -135 + j*(307) -150 + j*(348) --211 + j*(386) --124 + j*(-317) -197 + j*(289) -6 + j*(224) --571 + j*(327) --127 + j*(-331) -164 + j*(-490) --211 + j*(428) -507 + j*(99) -1 + j*(-32) --378 + j*(-261) -396 + j*(-520) --180 + j*(332) -318 + j*(119) --143 + j*(364) --177 + j*(527) --141 + j*(47) -180 + j*(104) --38 + j*(-321) -185 + j*(353) --414 + j*(250) -29 + j*(-441) --202 + j*(247) -16 + j*(62) -432 + j*(467) --206 + j*(175) -94 + j*(-132) -321 + j*(369) -705 + j*(170) -346 + j*(512) --368 + j*(-420) -53 + j*(117) -98 + j*(-211) --267 + j*(251) -366 + j*(144) -630 + j*(144) --187 + j*(333) --271 + j*(566) --344 + j*(-87) -437 + j*(316) --181 + j*(423) --280 + j*(90) -497 + j*(226) --191 + j*(-57) -334 + j*(122) --228 + j*(309) -412 + j*(-351) -289 + j*(193) -194 + j*(124) -293 + j*(-198) --175 + j*(343) --222 + j*(-327) -40 + j*(-205) -357 + j*(-335) --131 + j*(-187) -5 + j*(-491) -38 + j*(330) -6 + j*(274) -207 + j*(113) --339 + j*(-238) -245 + j*(-246) --46 + j*(-59) --375 + j*(-393) --231 + j*(515) -53 + j*(262) --224 + j*(190) --363 + j*(-43) -224 + j*(150) -122 + j*(-337) --296 + j*(-264) -73 + j*(445) --217 + j*(359) --270 + j*(-305) --342 + j*(526) -286 + j*(-655) --216 + j*(410) -606 + j*(368) -540 + j*(347) --66 + j*(-136) -149 + j*(342) -64 + j*(-315) --483 + j*(-236) --313 + j*(-325) --150 + j*(238) --175 + j*(-165) --239 + j*(409) -166 + j*(-18) -282 + j*(-151) --202 + j*(-446) -452 + j*(360) --205 + j*(-263) --283 + j*(320) --358 + j*(266) -170 + j*(28) --288 + j*(-393) -97 + j*(423) -122 + j*(425) --6 + j*(146) -144 + j*(-282) -368 + j*(413) --320 + j*(410) --513 + j*(-503) -237 + j*(-528) --398 + j*(254) --237 + j*(474) --128 + j*(499) -233 + j*(396) -262 + j*(404) -240 + j*(-390) --372 + j*(245) --313 + j*(-37) --99 + j*(-187) --301 + j*(-677) --321 + j*(120) -294 + j*(-131) -276 + j*(-228) --313 + j*(-604) --140 + j*(-262) --437 + j*(-173) -98 + j*(192) -235 + j*(394) -256 + j*(-503) -336 + j*(383) -138 + j*(277) --56 + j*(260) --305 + j*(-528) -206 + j*(59) -221 + j*(191) -552 + j*(-141) -15 + j*(434) -223 + j*(24) -56 + j*(325) --49 + j*(238) --410 + j*(270) -11 + j*(-322) --91 + j*(-492) --315 + j*(-44) --165 + j*(-332) -242 + j*(108) -29 + j*(226) -95 + j*(-47) --218 + j*(-109) -251 + j*(-426) --332 + j*(213) -33 + j*(443) -207 + j*(-475) -148 + j*(-1) --147 + j*(-504) --158 + j*(1) -378 + j*(15) --612 + j*(-174) -255 + j*(182) -240 + j*(-387) --206 + j*(176) -523 + j*(-181) -241 + j*(-255) --362 + j*(-265) -84 + j*(100) --299 + j*(165) -291 + j*(192) --109 + j*(-377) --72 + j*(532) --86 + j*(-276) -250 + j*(489) --301 + j*(-421) -187 + j*(401) --241 + j*(58) --369 + j*(-199) -23 + j*(501) --194 + j*(-318) --278 + j*(578) -552 + j*(223) --197 + j*(-253) -231 + j*(-304) --33 + j*(-308) -296 + j*(437) --462 + j*(445) -57 + j*(-146) --127 + j*(94) -98 + j*(21) -392 + j*(-337) --290 + j*(244) --216 + j*(434) -112 + j*(-111) -1 + j*(-450) -294 + j*(115) --486 + j*(-211) --293 + j*(-436) --181 + j*(315) -231 + j*(375) -192 + j*(-240) -200 + j*(-343) --310 + j*(34) --459 + j*(-279) --173 + j*(-120) -391 + j*(-253) --197 + j*(-226) -224 + j*(-334) --604 + j*(325) --18 + j*(-379) -269 + j*(-285) -454 + j*(483) --172 + j*(-185) --479 + j*(135) -319 + j*(275) -423 + j*(-495) --319 + j*(315) -22 + j*(466) --86 + j*(-120) -224 + j*(198) -210 + j*(-262) -106 + j*(170) --293 + j*(220) -491 + j*(524) -128 + j*(525) --318 + j*(419) -352 + j*(-143) --196 + j*(130) --222 + j*(317) -302 + j*(-421) -388 + j*(-199) --243 + j*(395) -87 + j*(397) --383 + j*(296) -99 + j*(-499) --97 + j*(-214) -279 + j*(-408) --428 + j*(-327) -250 + j*(-131) -260 + j*(110) --346 + j*(323) --204 + j*(341) --344 + j*(-276) -266 + j*(-33) --482 + j*(-466) --284 + j*(10) --331 + j*(236) -66 + j*(272) --415 + j*(227) -16 + j*(81) --647 + j*(671) --20 + j*(93) --130 + j*(-244) --272 + j*(74) --243 + j*(379) -168 + j*(-558) --49 + j*(264) --257 + j*(231) --298 + j*(231) -235 + j*(496) -263 + j*(77) --192 + j*(250) -110 + j*(87) --301 + j*(49) -391 + j*(-658) -482 + j*(-317) -267 + j*(-197) -89 + j*(-107) -240 + j*(-375) --354 + j*(-299) --441 + j*(-1) -113 + j*(-134) -530 + j*(-79) -405 + j*(-101) -476 + j*(45) -460 + j*(145) -332 + j*(-77) --86 + j*(-153) -74 + j*(-574) --298 + j*(-58) --220 + j*(-371) -438 + j*(192) --325 + j*(175) --132 + j*(-379) -225 + j*(96) -307 + j*(-55) --137 + j*(303) --112 + j*(423) --327 + j*(-241) --329 + j*(351) -62 + j*(-287) -372 + j*(-214) -426 + j*(-216) -176 + j*(-170) --449 + j*(-296) -522 + j*(-1) --66 + j*(396) --223 + j*(92) -228 + j*(165) --233 + j*(105) --272 + j*(-164) -248 + j*(121) --518 + j*(20) --65 + j*(-497) --272 + j*(118) -166 + j*(-117) --279 + j*(-284) -426 + j*(-590) --317 + j*(346) -197 + j*(421) -552 + j*(181) --163 + j*(290) -253 + j*(-554) -60 + j*(16) --336 + j*(-438) --154 + j*(-322) --202 + j*(188) --177 + j*(-8) --427 + j*(-361) --353 + j*(27) -406 + j*(119) --326 + j*(-155) -170 + j*(-190) --235 + j*(59) --67 + j*(287) -106 + j*(438) -192 + j*(-505) -173 + j*(-77) --147 + j*(-275) --683 + j*(342) --411 + j*(433) -307 + j*(4) --506 + j*(44) -322 + j*(-171) -337 + j*(-151) -276 + j*(332) --269 + j*(293) --8 + j*(151) --552 + j*(216) --168 + j*(-276) -195 + j*(-460) -287 + j*(645) --132 + j*(-112) -681 + j*(355) -336 + j*(-137) --539 + j*(-412) -82 + j*(433) --363 + j*(-254) --175 + j*(311) --180 + j*(155) -759 + j*(222) --756 + j*(387) -598 + j*(11) --66 + j*(47) -354 + j*(-71) --262 + j*(-247) --397 + j*(14) -400 + j*(-116) -141 + j*(132) -387 + j*(38) -269 + j*(-296) -457 + j*(54) --173 + j*(85) --370 + j*(191) -53 + j*(-285) --457 + j*(-389) -60 + j*(-470) -384 + j*(-293) --405 + j*(139) --138 + j*(168) --107 + j*(-69) -334 + j*(-50) -210 + j*(-148) -268 + j*(-327) --325 + j*(316) --157 + j*(3) --202 + j*(-96) --214 + j*(244) --336 + j*(-150) -495 + j*(-384) -380 + j*(283) --184 + j*(-419) -293 + j*(339) -178 + j*(67) --156 + j*(249) --563 + j*(407) --561 + j*(185) --93 + j*(-275) --299 + j*(363) -356 + j*(482) -301 + j*(163) --518 + j*(-438) --379 + j*(-109) --474 + j*(438) -486 + j*(180) -204 + j*(648) --122 + j*(190) --387 + j*(-214) -10 + j*(238) -124 + j*(406) -420 + j*(-313) --163 + j*(110) --330 + j*(-315) -303 + j*(262) -371 + j*(189) -452 + j*(-500) -430 + j*(-48) --10 + j*(129) --278 + j*(136) --366 + j*(420) -163 + j*(-250) -337 + j*(-217) -326 + j*(473) --353 + j*(-308) --11 + j*(-25) -106 + j*(-86) -237 + j*(325) -368 + j*(340) -53 + j*(-92) -116 + j*(-206) -163 + j*(206) --122 + j*(185) -282 + j*(-407) --41 + j*(35) --279 + j*(110) --204 + j*(4) -42 + j*(236) --190 + j*(66) -2 + j*(-25) --112 + j*(-47) -35 + j*(-76) -165 + j*(293) --218 + j*(-17) --69 + j*(-71) --158 + j*(48) -88 + j*(-57) --67 + j*(-9) --144 + j*(-40) --216 + j*(218) --161 + j*(88) -100 + j*(89) -226 + j*(219) --10 + j*(0) -96 + j*(-326) -79 + j*(-63) --82 + j*(219) -345 + j*(69) -486 + j*(-264) --37 + j*(11) -373 + j*(-105) --292 + j*(-99) -214 + j*(-145) --187 + j*(-156) --96 + j*(-194) --200 + j*(-57) --134 + j*(-142) -152 + j*(-251) --112 + j*(25) --33 + j*(179) --177 + j*(-7) --245 + j*(1) --114 + j*(122) --9 + j*(-83) --157 + j*(132) --173 + j*(-385) --25 + j*(308) -280 + j*(-180) --240 + j*(-129) --286 + j*(-115) --184 + j*(161) -180 + j*(-82) --2 + j*(383) --139 + j*(192) -112 + j*(-71) -178 + j*(-163) -104 + j*(15) --103 + j*(-185) --207 + j*(197) --78 + j*(108) -86 + j*(60) -52 + j*(296) --240 + j*(-98) --9 + j*(150) -107 + j*(-222) -281 + j*(223) --79 + j*(-42) -49 + j*(-105) --157 + j*(84) -42 + j*(-150) -80 + j*(-23) -178 + j*(-237) -269 + j*(119) --438 + j*(-72) --51 + j*(-114) --279 + j*(-76) -130 + j*(97) --125 + j*(138) -100 + j*(-168) --332 + j*(155) -112 + j*(413) -175 + j*(-136) --450 + j*(77) -34 + j*(51) --140 + j*(257) -170 + j*(-117) --275 + j*(-221) -30 + j*(361) -0 + j*(35) --165 + j*(-214) -227 + j*(186) -326 + j*(363) -175 + j*(11) --52 + j*(51) -153 + j*(-244) -0 + j*(-8) --78 + j*(68) -25 + j*(-67) -88 + j*(7) --204 + j*(216) -117 + j*(127) --214 + j*(-161) -192 + j*(285) --366 + j*(13) -185 + j*(92) --117 + j*(-243) -132 + j*(0) -141 + j*(9) --138 + j*(-232) --107 + j*(147) -175 + j*(-41) -35 + j*(47) -175 + j*(-52) -109 + j*(-82) --18 + j*(-75) -94 + j*(47) -76 + j*(111) -59 + j*(-148) -137 + j*(168) --24 + j*(171) --44 + j*(262) --299 + j*(-66) -130 + j*(-274) -64 + j*(-99) -10 + j*(-214) --251 + j*(330) --77 + j*(-100) --239 + j*(226) --83 + j*(-61) --240 + j*(162) --475 + j*(173) --32 + j*(-143) -112 + j*(238) --8 + j*(-178) --95 + j*(247) --33 + j*(87) --302 + j*(298) -202 + j*(69) -33 + j*(-87) --184 + j*(-31) -234 + j*(220) -122 + j*(-123) --64 + j*(155) -106 + j*(115) -161 + j*(56) -72 + j*(243) --27 + j*(47) --3 + j*(-138) --302 + j*(-216) -156 + j*(-93) --139 + j*(-104) --316 + j*(45) --161 + j*(345) --354 + j*(110) --79 + j*(155) -193 + j*(21) -31 + j*(-125) --119 + j*(-205) -35 + j*(21) --75 + j*(241) -23 + j*(-146) -224 + j*(-222) --171 + j*(231) --61 + j*(-42) --372 + j*(102) --19 + j*(-151) -368 + j*(89) -318 + j*(-52) --327 + j*(-301) -47 + j*(57) --243 + j*(-231) --461 + j*(59) -118 + j*(-65) -67 + j*(202) -402 + j*(-226) --123 + j*(-42) --127 + j*(325) --24 + j*(-166) -185 + j*(161) -111 + j*(-74) --44 + j*(-95) --290 + j*(137) --125 + j*(-220) -54 + j*(-77) -70 + j*(46) -153 + j*(-112) -17 + j*(170) --185 + j*(77) -193 + j*(140) --388 + j*(150) --381 + j*(-216) --11 + j*(262) --130 + j*(8) -149 + j*(-19) -240 + j*(134) -101 + j*(-161) -147 + j*(-86) -101 + j*(51) -110 + j*(-91) -67 + j*(126) -122 + j*(-72) --100 + j*(-166) -146 + j*(-159) --175 + j*(208) --90 + j*(-16) --288 + j*(-130) --256 + j*(-168) --29 + j*(62) -68 + j*(95) -18 + j*(95) -147 + j*(-91) --11 + j*(162) -136 + j*(35) -98 + j*(33) --180 + j*(308) -171 + j*(-5) --114 + j*(25) --30 + j*(-217) --88 + j*(184) -45 + j*(91) -214 + j*(-21) -91 + j*(348) --92 + j*(-296) --58 + j*(96) -38 + j*(-119) --202 + j*(135) --28 + j*(-60) --123 + j*(31) -102 + j*(12) --132 + j*(217) --28 + j*(245) --267 + j*(5) -41 + j*(249) --21 + j*(-147) -102 + j*(-320) --274 + j*(-25) -156 + j*(-100) -100 + j*(-124) --136 + j*(275) -320 + j*(-35) --115 + j*(104) --11 + j*(-205) --254 + j*(-291) --9 + j*(-318) --97 + j*(195) -279 + j*(29) -269 + j*(227) -67 + j*(-39) --136 + j*(241) --96 + j*(-19) -250 + j*(-127) -84 + j*(-129) -228 + j*(90) --98 + j*(23) --46 + j*(-4) -42 + j*(47) --15 + j*(-37) --122 + j*(-230) -67 + j*(163) -176 + j*(-43) -82 + j*(-132) -115 + j*(157) -86 + j*(33) --325 + j*(-20) --115 + j*(77) --33 + j*(-4) -197 + j*(161) -88 + j*(33) --55 + j*(72) -113 + j*(-60) -135 + j*(132) -9 + j*(291) --468 + j*(99) -122 + j*(-105) -95 + j*(-26) -29 + j*(-37) -40 + j*(-100) --100 + j*(26) --369 + j*(228) -86 + j*(-67) --47 + j*(-98) -52 + j*(-129) -271 + j*(-58) -131 + j*(-315) --78 + j*(361) --2 + j*(-98) -143 + j*(-180) -78 + j*(123) --77 + j*(-190) --92 + j*(-76) -151 + j*(71) --47 + j*(13) -246 + j*(-71) --178 + j*(59) -134 + j*(-88) -243 + j*(-98) --51 + j*(11) -244 + j*(45) --66 + j*(127) -44 + j*(223) -145 + j*(-98) --129 + j*(173) --226 + j*(330) -264 + j*(168) --93 + j*(27) --146 + j*(-133) --203 + j*(-310) -8 + j*(11) -378 + j*(112) -385 + j*(281) -182 + j*(-64) -35 + j*(158) --199 + j*(-1) --168 + j*(120) -192 + j*(-133) --127 + j*(59) --130 + j*(-279) -1 + j*(-224) --70 + j*(-42) -61 + j*(80) --13 + j*(-11) --8 + j*(-95) -132 + j*(-240) --215 + j*(-160) -191 + j*(133) -124 + j*(-373) --161 + j*(-139) -110 + j*(-134) --245 + j*(1) --267 + j*(103) --13 + j*(-384) -226 + j*(-58) -21 + j*(121) --45 + j*(-400) -120 + j*(76) -69 + j*(35) --111 + j*(40) -105 + j*(190) -164 + j*(161) --268 + j*(-40) -177 + j*(-25) --61 + j*(-80) -185 + j*(310) --110 + j*(141) -20 + j*(187) --299 + j*(-25) --24 + j*(326) --92 + j*(-335) -52 + j*(-324) --342 + j*(-267) --91 + j*(-10) -332 + j*(-119) -18 + j*(-219) -54 + j*(140) -333 + j*(237) --201 + j*(207) --99 + j*(294) --49 + j*(-26) -306 + j*(-37) --404 + j*(277) -22 + j*(-156) -348 + j*(-117) -62 + j*(197) -80 + j*(240) --317 + j*(402) -226 + j*(-252) --26 + j*(-31) --107 + j*(65) --45 + j*(7) --237 + j*(-146) --102 + j*(-73) --199 + j*(63) --196 + j*(-39) -68 + j*(50) -111 + j*(-71) -86 + j*(-13) --69 + j*(44) -163 + j*(-116) -181 + j*(-127) --115 + j*(527) -112 + j*(16) --135 + j*(122) -124 + j*(28) -140 + j*(-145) --149 + j*(-218) -51 + j*(-5) -66 + j*(315) -249 + j*(-198) -54 + j*(60) -283 + j*(227) -272 + j*(237) -228 + j*(53) -296 + j*(212) --255 + j*(-52) -252 + j*(93) -49 + j*(-134) -279 + j*(54) --21 + j*(-343) --116 + j*(206) --52 + j*(-47) -69 + j*(187) -21 + j*(93) --28 + j*(-166) --97 + j*(-161) -367 + j*(-90) --39 + j*(53) -400 + j*(92) -381 + j*(-169) --303 + j*(219) -2 + j*(58) -21 + j*(248) --160 + j*(-125) -379 + j*(-387) -62 + j*(-31) --126 + j*(-76) --17 + j*(47) -29 + j*(45) --286 + j*(-181) -21 + j*(103) --117 + j*(29) -86 + j*(386) --132 + j*(-129) -83 + j*(178) -243 + j*(-298) -144 + j*(-295) -111 + j*(-109) --201 + j*(168) -55 + j*(-192) --13 + j*(41) --129 + j*(147) --8 + j*(-37) --39 + j*(32) -28 + j*(90) -323 + j*(-245) -107 + j*(-77) --8 + j*(-421) -187 + j*(-118) --54 + j*(-160) --91 + j*(54) -215 + j*(267) -239 + j*(-159) -106 + j*(-174) --106 + j*(349) --153 + j*(33) -45 + j*(98) --145 + j*(134) --101 + j*(-190) --331 + j*(40) --167 + j*(-255) -129 + j*(-113) -112 + j*(250) -10 + j*(-317) -125 + j*(-106) -96 + j*(102) -238 + j*(-6) --108 + j*(222) --82 + j*(122) --453 + j*(-377) --97 + j*(139) -103 + j*(-56) --425 + j*(28) -164 + j*(154) -152 + j*(-62) -74 + j*(320) -85 + j*(-80) -146 + j*(-23) --291 + j*(-153) --5 + j*(-3) --155 + j*(23) -153 + j*(294) -59 + j*(-132) -5 + j*(153) -59 + j*(-105) -54 + j*(-325) -177 + j*(170) --223 + j*(-124) -183 + j*(-128) -119 + j*(-180) -332 + j*(71) --14 + j*(93) -199 + j*(81) --101 + j*(-75) -7 + j*(-35) --101 + j*(52) -219 + j*(-284) --102 + j*(-143) -16 + j*(-176) -132 + j*(-16) -76 + j*(-266) -24 + j*(-6) --81 + j*(8) --240 + j*(362) --54 + j*(-95) -490 + j*(-91) -201 + j*(-194) --127 + j*(-102) -48 + j*(4) -250 + j*(-54) -146 + j*(-409) -260 + j*(-20) --40 + j*(50) --119 + j*(-64) -319 + j*(-222) --88 + j*(-216) -157 + j*(191) -112 + j*(-34) --222 + j*(-145) --129 + j*(175) -71 + j*(134) -27 + j*(-133) --87 + j*(-340) --175 + j*(126) -76 + j*(54) --261 + j*(172) -64 + j*(-37) --10 + j*(-211) -30 + j*(169) -23 + j*(-247) --204 + j*(-54) -67 + j*(63) -191 + j*(-223) -22 + j*(454) --156 + j*(91) --45 + j*(-122) --23 + j*(-189) --31 + j*(139) -138 + j*(-201) --324 + j*(-299) --88 + j*(158) --8 + j*(-104) -93 + j*(-129) -112 + j*(-8) -75 + j*(-82) -279 + j*(182) -118 + j*(-400) --162 + j*(89) --398 + j*(58) -4 + j*(101) --133 + j*(-206) --42 + j*(-1) --276 + j*(322) --385 + j*(5) -56 + j*(43) -281 + j*(107) --91 + j*(70) -31 + j*(33) -57 + j*(4) -71 + j*(-126) -129 + j*(175) -565 + j*(-270) --211 + j*(40) --54 + j*(216) -57 + j*(-281) -255 + j*(-197) --21 + j*(190) -183 + j*(110) --123 + j*(46) -111 + j*(45) --381 + j*(100) --296 + j*(153) --214 + j*(-46) --221 + j*(-68) -348 + j*(231) -247 + j*(24) --38 + j*(263) --146 + j*(-361) -51 + j*(271) -146 + j*(-119) --86 + j*(-81) --163 + j*(-21) -92 + j*(70) -159 + j*(139) --301 + j*(54) --13 + j*(-272) --105 + j*(25) --95 + j*(-56) -222 + j*(54) -250 + j*(-56) -354 + j*(-152) -139 + j*(59) --126 + j*(-175) -332 + j*(-244) --88 + j*(-8) --214 + j*(-261) --282 + j*(-13) -75 + j*(49) --180 + j*(-13) --69 + j*(66) --161 + j*(-1) -51 + j*(-62) -26 + j*(-37) --54 + j*(323) -264 + j*(-8) --52 + j*(-44) -86 + j*(341) --48 + j*(-54) --469 + j*(167) --436 + j*(-108) --132 + j*(-14) --134 + j*(74) -364 + j*(258) -22 + j*(156) --40 + j*(293) -41 + j*(98) --83 + j*(-12) -117 + j*(59) -89 + j*(216) --9 + j*(146) -40 + j*(-132) -35 + j*(-151) --178 + j*(-33) --194 + j*(-57) --85 + j*(206) --134 + j*(256) -110 + j*(214) -204 + j*(-109) -236 + j*(-13) -113 + j*(-40) --409 + j*(52) --37 + j*(223) -139 + j*(61) --145 + j*(212) --97 + j*(161) -340 + j*(-211) --184 + j*(13) -235 + j*(-4) --237 + j*(-257) -81 + j*(49) -196 + j*(79) -84 + j*(131) -6 + j*(-95) --291 + j*(426) -221 + j*(89) --31 + j*(116) -74 + j*(260) --156 + j*(47) --261 + j*(-265) --8 + j*(-291) -23 + j*(129) -89 + j*(87) -71 + j*(-16) -217 + j*(293) --402 + j*(-98) --1 + j*(4) -84 + j*(-253) -39 + j*(108) -175 + j*(301) --257 + j*(81) --289 + j*(-86) --313 + j*(-76) -39 + j*(-79) -146 + j*(136) -218 + j*(33) --217 + j*(31) --11 + j*(237) --117 + j*(56) -130 + j*(100) -178 + j*(416) -99 + j*(84) -165 + j*(-202) -61 + j*(-320) --215 + j*(186) --78 + j*(220) --235 + j*(-151) --60 + j*(107) --40 + j*(45) --119 + j*(-298) -250 + j*(-164) --129 + j*(-186) -247 + j*(182) -52 + j*(238) --23 + j*(165) -122 + j*(78) -161 + j*(-262) --313 + j*(44) -1 + j*(-35) -1 + j*(-36) -13 + j*(-135) --223 + j*(-115) --320 + j*(303) --268 + j*(-66) --19 + j*(52) --12 + j*(-124) --28 + j*(42) -219 + j*(-94) --272 + j*(-265) --114 + j*(-81) --107 + j*(28) --129 + j*(-131) --139 + j*(-63) -55 + j*(-259) -241 + j*(-81) --159 + j*(43) --125 + j*(221) -119 + j*(-114) -95 + j*(-36) --213 + j*(-377) -109 + j*(-205) -332 + j*(69) -71 + j*(-182) --28 + j*(-100) -95 + j*(-33) -134 + j*(201) --81 + j*(245) --41 + j*(-175) --55 + j*(-212) -235 + j*(-14) -123 + j*(21) --86 + j*(207) --156 + j*(71) --115 + j*(363) -339 + j*(-28) --325 + j*(262) -188 + j*(-102) -112 + j*(189) -19 + j*(-39) -35 + j*(-77) -181 + j*(-13) --77 + j*(-12) -202 + j*(66) --254 + j*(-63) -150 + j*(131) --136 + j*(42) --238 + j*(-233) -467 + j*(-366) --125 + j*(202) --333 + j*(52) --27 + j*(-125) --224 + j*(4) --52 + j*(246) -362 + j*(-105) --151 + j*(-169) -175 + j*(36) --5 + j*(-147) --59 + j*(23) -222 + j*(86) --9 + j*(-178) -95 + j*(-159) --40 + j*(-3) -298 + j*(158) --94 + j*(354) -48 + j*(33) --42 + j*(-237) -120 + j*(115) --9 + j*(-30) -172 + j*(42) -158 + j*(153) --320 + j*(-88) -22 + j*(-382) --199 + j*(-37) -234 + j*(-310) --208 + j*(2) -40 + j*(16) -309 + j*(-85) -123 + j*(-172) -77 + j*(77) --30 + j*(135) --95 + j*(-40) -72 + j*(-25) --43 + j*(37) -237 + j*(-185) --68 + j*(-187) --298 + j*(55) -105 + j*(-116) -82 + j*(81) --107 + j*(-53) -18 + j*(156) --170 + j*(257) --93 + j*(128) -70 + j*(83) --8 + j*(-257) --46 + j*(-182) --496 + j*(-38) --16 + j*(-24) --5 + j*(-170) -152 + j*(-168) --338 + j*(-136) --75 + j*(104) -265 + j*(119) --146 + j*(231) --310 + j*(0) --7 + j*(-157) --48 + j*(-255) -254 + j*(-21) -134 + j*(-4) --101 + j*(146) --236 + j*(-372) --164 + j*(32) -122 + j*(177) --180 + j*(108) -57 + j*(-165) --6 + j*(255) --75 + j*(123) -13 + j*(100) --170 + j*(-28) --135 + j*(173) -83 + j*(151) --379 + j*(16) --8 + j*(44) --325 + j*(57) -186 + j*(129) -46 + j*(-37) --185 + j*(39) -45 + j*(8) --170 + j*(156) -95 + j*(231) -180 + j*(-313) --371 + j*(-122) --106 + j*(112) -23 + j*(303) --59 + j*(-170) -45 + j*(84) -62 + j*(169) --292 + j*(-88) -60 + j*(-78) --204 + j*(-129) --61 + j*(18) --118 + j*(-74) --98 + j*(227) -170 + j*(201) -86 + j*(254) -119 + j*(98) --173 + j*(129) --62 + j*(71) -7 + j*(-236) -216 + j*(161) --129 + j*(-50) --182 + j*(43) --54 + j*(-159) -113 + j*(-342) -107 + j*(-122) --175 + j*(-31) -30 + j*(112) -42 + j*(-136) -123 + j*(-122) -46 + j*(-36) -22 + j*(-10) -124 + j*(356) -297 + j*(-171) --27 + j*(284) -317 + j*(-117) --34 + j*(-349) -177 + j*(16) --259 + j*(112) --161 + j*(-250) --232 + j*(43) --240 + j*(-83) --162 + j*(370) --13 + j*(253) --77 + j*(-49) --6 + j*(-209) --88 + j*(219) --211 + j*(107) -147 + j*(25) --273 + j*(36) --139 + j*(-117) --177 + j*(52) -223 + j*(170) -139 + j*(-26) -168 + j*(-164) -124 + j*(143) -23 + j*(-224) --54 + j*(-113) -243 + j*(-158) --97 + j*(42) --169 + j*(-34) --30 + j*(110) -317 + j*(6) -173 + j*(317) --210 + j*(-268) --126 + j*(11) -56 + j*(-126) -78 + j*(-158) --82 + j*(133) --133 + j*(-240) --180 + j*(-79) --80 + j*(115) --25 + j*(-201) -371 + j*(11) --68 + j*(202) --231 + j*(-102) --69 + j*(-87) --294 + j*(327) --95 + j*(-16) --231 + j*(-69) -53 + j*(240) --58 + j*(84) --94 + j*(90) -141 + j*(176) --90 + j*(-110) --153 + j*(-4) --58 + j*(126) --67 + j*(13) -92 + j*(-43) --13 + j*(-36) --139 + j*(-202) --228 + j*(-331) -180 + j*(34) --257 + j*(458) --211 + j*(111) --337 + j*(83) -40 + j*(-76) -40 + j*(-325) --4 + j*(-22) --124 + j*(2) -112 + j*(-317) -204 + j*(82) --4 + j*(-29) -112 + j*(-193) --70 + j*(-98) --99 + j*(144) -241 + j*(3) --74 + j*(-40) -224 + j*(148) -216 + j*(69) -36 + j*(-23) --28 + j*(-166) -40 + j*(157) -198 + j*(52) --225 + j*(69) -77 + j*(-260) --32 + j*(-78) --313 + j*(-35) -138 + j*(28) --10 + j*(102) -92 + j*(-91) -267 + j*(-384) -148 + j*(211) --44 + j*(170) --30 + j*(207) -125 + j*(51) -175 + j*(-47) --23 + j*(-171) --165 + j*(-109) -176 + j*(83) --62 + j*(148) -124 + j*(-119) --121 + j*(-276) -54 + j*(-243) --163 + j*(-109) -1 + j*(-34) --83 + j*(182) -35 + j*(146) -322 + j*(53) --175 + j*(34) --156 + j*(-173) -83 + j*(428) -195 + j*(-110) -70 + j*(-187) -259 + j*(107) -99 + j*(233) --73 + j*(-90) --73 + j*(52) -48 + j*(327) -108 + j*(-49) -218 + j*(-158) --22 + j*(-165) -296 + j*(-61) --22 + j*(91) --109 + j*(92) -26 + j*(-6) --75 + j*(41) -52 + j*(187) -82 + j*(184) -42 + j*(116) --71 + j*(228) --72 + j*(190) --218 + j*(-179) -156 + j*(284) --151 + j*(0) -191 + j*(-107) --35 + j*(-240) -245 + j*(-145) --96 + j*(-74) -146 + j*(168) --59 + j*(-107) --114 + j*(115) -60 + j*(-71) -93 + j*(5) -46 + j*(142) --16 + j*(63) --232 + j*(151) --312 + j*(-18) -182 + j*(-24) -227 + j*(221) --200 + j*(-145) -251 + j*(254) -25 + j*(-163) --110 + j*(-184) --256 + j*(173) --83 + j*(56) -184 + j*(-23) --12 + j*(-21) --228 + j*(15) -35 + j*(-117) --6 + j*(25) -77 + j*(-12) --243 + j*(-4) -29 + j*(-12) --221 + j*(71) --30 + j*(40) -100 + j*(-631) --146 + j*(-156) -310 + j*(94) -33 + j*(76) --184 + j*(168) --2 + j*(56) --76 + j*(57) --37 + j*(93) -266 + j*(3) -127 + j*(-191) -284 + j*(-4) -63 + j*(248) -327 + j*(-94) --276 + j*(119) --351 + j*(2) -379 + j*(6) --80 + j*(163) -135 + j*(59) --156 + j*(0) -228 + j*(-18) -566 + j*(-95) -375 + j*(-13) --68 + j*(-289) --250 + j*(-154) -98 + j*(79) --4 + j*(0) --165 + j*(153) --36 + j*(285) -70 + j*(-14) --155 + j*(74) -45 + j*(8) -123 + j*(14) --197 + j*(232) --250 + j*(58) --124 + j*(319) -125 + j*(0) -10 + j*(-142) -137 + j*(-70) --180 + j*(146) -280 + j*(77) --252 + j*(-92) -35 + j*(13) --135 + j*(366) -104 + j*(37) --84 + j*(-117) -11 + j*(-238) -74 + j*(-181) -134 + j*(21) --64 + j*(-122) --344 + j*(-146) -194 + j*(-158) --59 + j*(-111) --286 + j*(-121) --225 + j*(71) --93 + j*(-153) -94 + j*(21) -1 + j*(323) -1 + j*(138) --59 + j*(-13) -5 + j*(-44) --55 + j*(47) --45 + j*(126) --136 + j*(105) --420 + j*(-415) --1 + j*(-133) --259 + j*(-263) --106 + j*(-181) --112 + j*(-18) -18 + j*(318) --173 + j*(162) --166 + j*(7) -11 + j*(-161) -326 + j*(3) -90 + j*(301) --198 + j*(-94) -151 + j*(-48) --272 + j*(103) -97 + j*(15) --125 + j*(52) -378 + j*(-346) -40 + j*(-30) --98 + j*(-186) -207 + j*(339) -42 + j*(-130) --16 + j*(13) --33 + j*(49) -140 + j*(193) --49 + j*(233) --106 + j*(-242) --207 + j*(-18) -177 + j*(-38) --520 + j*(-117) -60 + j*(40) --327 + j*(279) -342 + j*(-58) --39 + j*(-69) --127 + j*(-42) -235 + j*(-59) --267 + j*(46) -71 + j*(130) --88 + j*(45) -282 + j*(-4) -219 + j*(-82) --122 + j*(-25) --76 + j*(169) -284 + j*(124) -4 + j*(-43) -83 + j*(-349) -43 + j*(342) -31 + j*(-173) -345 + j*(250) --18 + j*(177) --81 + j*(155) -355 + j*(156) --93 + j*(-11) -141 + j*(3) --83 + j*(77) -340 + j*(-164) --117 + j*(59) -94 + j*(189) -127 + j*(-243) --284 + j*(-161) --19 + j*(-133) -182 + j*(86) --153 + j*(97) --16 + j*(-69) -197 + j*(-16) --18 + j*(29) -8 + j*(-72) --95 + j*(312) --76 + j*(-127) -93 + j*(-103) --127 + j*(16) -78 + j*(329) --69 + j*(111) -182 + j*(192) -43 + j*(-180) --77 + j*(81) --91 + j*(-274) --136 + j*(57) -29 + j*(-122) -291 + j*(-81) --227 + j*(127) --165 + j*(227) -61 + j*(-100) --80 + j*(-31) --211 + j*(-145) --168 + j*(-113) --40 + j*(68) -259 + j*(121) -111 + j*(-69) -245 + j*(47) -11 + j*(-61) --136 + j*(104) -3 + j*(-161) --105 + j*(-15) -122 + j*(-453) --36 + j*(-18) --148 + j*(243) -78 + j*(-107) -181 + j*(276) -276 + j*(-42) -179 + j*(-117) --103 + j*(397) -250 + j*(-53) --25 + j*(184) -108 + j*(-56) -171 + j*(-1) -217 + j*(178) --149 + j*(-189) --134 + j*(-218) -76 + j*(402) --10 + j*(139) -100 + j*(236) -61 + j*(-177) -27 + j*(9) -151 + j*(38) --110 + j*(-92) -222 + j*(-115) -118 + j*(-158) -94 + j*(118) -494 + j*(197) --16 + j*(-27) --307 + j*(-13) --81 + j*(262) -231 + j*(192) -278 + j*(21) -56 + j*(-35) --328 + j*(316) -130 + j*(32) --37 + j*(209) -306 + j*(51) -113 + j*(114) --228 + j*(-101) --45 + j*(22) --106 + j*(-86) --188 + j*(-74) -124 + j*(57) --70 + j*(-83) --216 + j*(-23) --87 + j*(-109) -97 + j*(-263) -78 + j*(90) --15 + j*(256) --103 + j*(350) -21 + j*(-25) -32 + j*(115) -76 + j*(-270) -190 + j*(-41) -8 + j*(195) -127 + j*(-100) --8 + j*(-132) -253 + j*(-117) --100 + j*(5) --57 + j*(-319) --18 + j*(82) -163 + j*(231) --127 + j*(-271) --74 + j*(-243) -39 + j*(-278) --88 + j*(179) --100 + j*(-33) --373 + j*(-333) --182 + j*(-299) --117 + j*(-78) -34 + j*(-185) --117 + j*(155) --28 + j*(56) --161 + j*(-70) --97 + j*(-310) --30 + j*(13) --254 + j*(33) -119 + j*(8) -333 + j*(46) --383 + j*(27) -83 + j*(188) -73 + j*(-217) -59 + j*(60) --166 + j*(266) --177 + j*(123) --356 + j*(-55) --339 + j*(-30) --143 + j*(49) -105 + j*(-224) --173 + j*(305) --35 + j*(202) --185 + j*(-152) --221 + j*(132) --244 + j*(-58) -104 + j*(276) --182 + j*(21) -117 + j*(-134) -285 + j*(-66) -33 + j*(-86) -91 + j*(-28) -6 + j*(50) -83 + j*(-8) --185 + j*(60) --32 + j*(-94) --179 + j*(9) --323 + j*(136) -15 + j*(-417) -197 + j*(-105) --71 + j*(74) -6 + j*(-117) -184 + j*(407) -123 + j*(-37) -57 + j*(12) --52 + j*(168) --188 + j*(-119) -28 + j*(-129) --78 + j*(-1) --104 + j*(-83) -1 + j*(-223) --468 + j*(42) -157 + j*(52) --144 + j*(-72) -75 + j*(296) -45 + j*(-285) --221 + j*(301) --103 + j*(163) --341 + j*(-457) -105 + j*(23) --23 + j*(-88) --264 + j*(-552) -81 + j*(4) --274 + j*(-131) -214 + j*(-18) -151 + j*(-214) --1 + j*(-205) -103 + j*(-49) -81 + j*(-8) --80 + j*(16) -246 + j*(-183) -136 + j*(-100) -35 + j*(-69) --217 + j*(254) -252 + j*(-156) --47 + j*(-160) --162 + j*(167) --148 + j*(-201) -265 + j*(-240) --141 + j*(-8) -35 + j*(33) --99 + j*(-95) --4 + j*(124) -65 + j*(-206) --175 + j*(279) --1 + j*(114) --52 + j*(71) --103 + j*(47) --164 + j*(-41) -206 + j*(216) --148 + j*(19) --161 + j*(-187) --200 + j*(223) -131 + j*(238) -18 + j*(101) -229 + j*(22) -71 + j*(53) -509 + j*(-293) -139 + j*(161) --322 + j*(180) -119 + j*(196) -12 + j*(103) -10 + j*(-187) -104 + j*(-28) -82 + j*(50) -86 + j*(125) -117 + j*(59) --225 + j*(129) -167 + j*(-177) --125 + j*(-100) --178 + j*(-124) --144 + j*(-262) -457 + j*(-237) --267 + j*(22) -240 + j*(22) -155 + j*(89) --6 + j*(-361) -266 + j*(-358) --180 + j*(110) --73 + j*(69) --42 + j*(93) --257 + j*(-151) -3 + j*(141) -192 + j*(356) -26 + j*(-76) -103 + j*(340) -83 + j*(70) -75 + j*(-245) -206 + j*(340) --144 + j*(360) -344 + j*(76) --74 + j*(325) --7 + j*(208) --238 + j*(-206) -25 + j*(83) -57 + j*(-286) --82 + j*(232) -251 + j*(-76) --218 + j*(-234) --170 + j*(-219) --75 + j*(-252) --112 + j*(259) -24 + j*(31) --226 + j*(59) --67 + j*(-4) --344 + j*(-240) --86 + j*(143) -37 + j*(-59) -54 + j*(-173) --264 + j*(-52) -78 + j*(104) --337 + j*(-103) -115 + j*(-144) -228 + j*(4) -93 + j*(-54) -15 + j*(-245) -118 + j*(-70) --8 + j*(-69) -195 + j*(-202) -110 + j*(172) --214 + j*(-326) --74 + j*(199) -81 + j*(124) -59 + j*(141) -88 + j*(-178) --28 + j*(22) -132 + j*(144) -71 + j*(-90) -101 + j*(-243) --191 + j*(32) --12 + j*(-52) -134 + j*(18) --416 + j*(338) -98 + j*(-92) --122 + j*(-18) --123 + j*(-100) --405 + j*(86) -59 + j*(260) --272 + j*(201) --129 + j*(320) --214 + j*(35) --24 + j*(9) --137 + j*(88) --46 + j*(-113) --99 + j*(105) --4 + j*(51) --59 + j*(-19) -267 + j*(56) -77 + j*(-30) -66 + j*(61) -6 + j*(-23) -0 + j*(198) --4 + j*(-117) --58 + j*(5) --141 + j*(143) --4 + j*(100) --150 + j*(-117) -88 + j*(-301) --90 + j*(-31) -247 + j*(58) --84 + j*(-112) -387 + j*(-145) --50 + j*(-57) --117 + j*(-25) --103 + j*(102) -113 + j*(294) -248 + j*(142) --61 + j*(-134) --152 + j*(129) -106 + j*(-170) --332 + j*(-23) --168 + j*(206) -240 + j*(36) --196 + j*(-146) --400 + j*(67) -40 + j*(-26) -110 + j*(213) --288 + j*(252) -53 + j*(206) -253 + j*(-489) --428 + j*(390) --426 + j*(339) -162 + j*(-463) -278 + j*(159) --35 + j*(426) --375 + j*(323) --243 + j*(186) -230 + j*(325) --340 + j*(-334) --193 + j*(148) --640 + j*(75) --14 + j*(106) --49 + j*(233) -93 + j*(225) --23 + j*(-235) --560 + j*(-476) --494 + j*(412) -302 + j*(424) -122 + j*(255) --317 + j*(320) --47 + j*(-134) --411 + j*(412) --241 + j*(107) --639 + j*(-566) -427 + j*(-136) --165 + j*(-217) -515 + j*(471) --91 + j*(-151) -405 + j*(221) -139 + j*(-260) --82 + j*(151) -228 + j*(514) --165 + j*(231) -425 + j*(-11) --210 + j*(117) --475 + j*(247) --291 + j*(500) -18 + j*(-106) -443 + j*(57) --283 + j*(348) -226 + j*(-305) --211 + j*(-33) -412 + j*(-233) --272 + j*(237) --378 + j*(8) -299 + j*(-136) -182 + j*(-98) --489 + j*(183) -41 + j*(286) --64 + j*(226) -102 + j*(351) -375 + j*(471) --121 + j*(252) -310 + j*(-366) -194 + j*(-442) -67 + j*(-332) -190 + j*(-188) -467 + j*(-81) --313 + j*(-344) --49 + j*(-161) --589 + j*(85) --91 + j*(187) -127 + j*(11) --212 + j*(551) -350 + j*(7) -170 + j*(327) --387 + j*(-363) --190 + j*(-612) -207 + j*(319) --121 + j*(315) --401 + j*(161) --432 + j*(209) --467 + j*(-334) -276 + j*(90) -185 + j*(-222) --506 + j*(490) --455 + j*(-293) --49 + j*(-448) -224 + j*(293) -427 + j*(-559) --267 + j*(-164) --23 + j*(-156) --324 + j*(-267) --215 + j*(-33) -98 + j*(-173) --209 + j*(-255) --197 + j*(431) -238 + j*(367) -47 + j*(-198) --308 + j*(-1) --173 + j*(119) --134 + j*(-357) --186 + j*(71) -198 + j*(-59) -66 + j*(298) --412 + j*(45) -416 + j*(426) -127 + j*(231) -285 + j*(-231) -81 + j*(-380) -228 + j*(52) --291 + j*(436) --28 + j*(91) -331 + j*(-356) --12 + j*(800) --144 + j*(303) --334 + j*(206) -316 + j*(250) -272 + j*(-503) --192 + j*(-511) -298 + j*(-80) -23 + j*(-566) -480 + j*(-347) -222 + j*(-330) -148 + j*(256) -505 + j*(-419) -270 + j*(-203) -409 + j*(-450) --115 + j*(325) --101 + j*(-471) --74 + j*(23) --163 + j*(-351) --3 + j*(354) -8 + j*(-183) --196 + j*(132) -329 + j*(-443) -342 + j*(334) --338 + j*(-366) --143 + j*(-636) -464 + j*(-245) --168 + j*(204) -216 + j*(252) -252 + j*(-243) --81 + j*(342) --196 + j*(233) -277 + j*(-301) -367 + j*(-276) -59 + j*(58) -163 + j*(398) --68 + j*(144) -47 + j*(335) -504 + j*(-647) --169 + j*(-404) -343 + j*(-343) --452 + j*(90) --189 + j*(175) --70 + j*(322) -354 + j*(-152) -422 + j*(262) --247 + j*(-209) -569 + j*(157) -75 + j*(-52) --169 + j*(-175) --334 + j*(16) -177 + j*(605) -434 + j*(-502) --339 + j*(37) -57 + j*(-246) -437 + j*(249) --235 + j*(-141) --247 + j*(-356) --54 + j*(-366) --305 + j*(-142) --237 + j*(164) -8 + j*(-373) -204 + j*(107) --617 + j*(136) -429 + j*(-337) --337 + j*(-326) -506 + j*(477) -161 + j*(-22) -149 + j*(231) -202 + j*(-274) --176 + j*(-391) --252 + j*(-400) --28 + j*(167) -256 + j*(-452) -419 + j*(188) --142 + j*(-805) -417 + j*(-392) -10 + j*(197) --335 + j*(105) --114 + j*(149) --170 + j*(265) --387 + j*(-233) --444 + j*(-151) -119 + j*(451) -270 + j*(422) -591 + j*(-421) --250 + j*(-196) -62 + j*(-338) -266 + j*(28) --476 + j*(69) -71 + j*(-97) --52 + j*(-268) --136 + j*(-214) -223 + j*(633) --518 + j*(220) -595 + j*(184) -160 + j*(124) --304 + j*(-202) -246 + j*(187) -64 + j*(300) -368 + j*(108) -255 + j*(-130) --220 + j*(-389) --424 + j*(41) -508 + j*(16) --334 + j*(-446) --89 + j*(81) --685 + j*(169) -273 + j*(-25) -110 + j*(374) -355 + j*(250) --29 + j*(-200) --298 + j*(-629) --508 + j*(144) -319 + j*(-343) -103 + j*(-57) --59 + j*(373) -282 + j*(-14) --102 + j*(350) -147 + j*(14) --185 + j*(35) --260 + j*(220) --337 + j*(-359) -357 + j*(182) -192 + j*(-279) --293 + j*(-5) -257 + j*(217) -247 + j*(-105) --5 + j*(-358) -252 + j*(-95) -69 + j*(-534) --95 + j*(-283) -147 + j*(-37) -170 + j*(409) -394 + j*(452) --110 + j*(-421) --257 + j*(190) --450 + j*(-209) -77 + j*(-546) -161 + j*(16) -337 + j*(-32) -543 + j*(145) --306 + j*(-438) --64 + j*(159) --234 + j*(-197) --445 + j*(-51) --208 + j*(-62) --275 + j*(228) --445 + j*(-221) -524 + j*(-37) -204 + j*(516) -246 + j*(-404) -624 + j*(-243) --118 + j*(264) -61 + j*(194) --132 + j*(-127) -220 + j*(298) --222 + j*(-282) -167 + j*(-286) -330 + j*(466) -501 + j*(0) -620 + j*(414) -134 + j*(-269) --212 + j*(193) -373 + j*(-335) --107 + j*(40) -342 + j*(-279) --286 + j*(138) -190 + j*(238) --321 + j*(-240) --409 + j*(-247) -371 + j*(505) -247 + j*(272) --223 + j*(-23) -111 + j*(349) --177 + j*(306) -466 + j*(92) --267 + j*(322) -301 + j*(231) -460 + j*(-168) --155 + j*(-254) --320 + j*(-181) -50 + j*(-330) -283 + j*(-357) -163 + j*(-354) -67 + j*(379) --105 + j*(-199) -245 + j*(-296) -387 + j*(371) -56 + j*(57) -453 + j*(279) --324 + j*(33) --327 + j*(-474) --238 + j*(308) --28 + j*(-187) --252 + j*(-229) -165 + j*(194) -509 + j*(434) --337 + j*(518) -3 + j*(-243) -275 + j*(378) -237 + j*(-86) -245 + j*(192) -225 + j*(-257) --325 + j*(-468) --482 + j*(291) --266 + j*(63) --496 + j*(315) -408 + j*(-185) --536 + j*(102) --320 + j*(-224) --404 + j*(16) -302 + j*(246) --263 + j*(19) -308 + j*(-209) -8 + j*(363) --605 + j*(-448) -266 + j*(347) -602 + j*(-82) --276 + j*(-238) -296 + j*(111) -293 + j*(-229) --233 + j*(-84) -186 + j*(-148) -193 + j*(365) -99 + j*(-303) -117 + j*(454) --98 + j*(288) --508 + j*(-424) --370 + j*(650) -324 + j*(375) -415 + j*(-221) --211 + j*(40) -258 + j*(-7) --519 + j*(-225) --303 + j*(112) -247 + j*(-286) -303 + j*(-456) -179 + j*(244) -29 + j*(-155) -321 + j*(458) -144 + j*(226) --195 + j*(-434) --52 + j*(-276) --339 + j*(203) --531 + j*(35) --82 + j*(57) --717 + j*(-362) --407 + j*(227) -257 + j*(343) -140 + j*(-224) -403 + j*(195) --177 + j*(469) -158 + j*(-312) -15 + j*(-269) --363 + j*(262) --36 + j*(-339) -342 + j*(-153) --56 + j*(696) -298 + j*(197) --93 + j*(134) --14 + j*(501) -511 + j*(228) --98 + j*(269) -235 + j*(417) -274 + j*(-367) --327 + j*(228) --27 + j*(148) -404 + j*(-207) -411 + j*(332) -449 + j*(276) -716 + j*(725) -42 + j*(429) --163 + j*(527) -156 + j*(274) --593 + j*(-375) -496 + j*(419) -277 + j*(-330) -513 + j*(-36) -175 + j*(-386) -134 + j*(-376) --95 + j*(-299) --179 + j*(57) -465 + j*(416) -342 + j*(317) -158 + j*(47) --141 + j*(248) --173 + j*(206) --394 + j*(119) -392 + j*(136) --315 + j*(195) -335 + j*(450) -176 + j*(8) -613 + j*(-317) -150 + j*(-186) --403 + j*(-643) -133 + j*(-279) -41 + j*(-164) -276 + j*(-46) -298 + j*(396) --260 + j*(-488) --390 + j*(114) -32 + j*(375) --470 + j*(216) -585 + j*(298) --443 + j*(-373) -251 + j*(306) --372 + j*(318) --371 + j*(408) --92 + j*(-80) --286 + j*(14) --351 + j*(59) --21 + j*(366) --197 + j*(-182) --267 + j*(-47) -177 + j*(-265) --443 + j*(-212) -470 + j*(0) -90 + j*(315) --68 + j*(-222) --506 + j*(-289) --236 + j*(-293) -131 + j*(-98) --257 + j*(174) --37 + j*(-494) --486 + j*(35) -195 + j*(-247) -325 + j*(-836) --73 + j*(-497) --91 + j*(531) -642 + j*(-362) -344 + j*(124) --120 + j*(-199) --50 + j*(-488) -1 + j*(-345) -285 + j*(103) -206 + j*(452) -176 + j*(433) --323 + j*(427) --442 + j*(340) --362 + j*(-361) -417 + j*(-184) --148 + j*(251) --289 + j*(-111) --426 + j*(-202) --597 + j*(-365) -409 + j*(199) -227 + j*(339) --284 + j*(-69) -282 + j*(-156) -40 + j*(473) --271 + j*(-76) --228 + j*(-424) --44 + j*(-64) -28 + j*(371) -494 + j*(-400) --192 + j*(368) -199 + j*(211) --148 + j*(-41) -77 + j*(-412) -13 + j*(139) -350 + j*(-71) -40 + j*(117) --59 + j*(320) -240 + j*(-369) -193 + j*(180) -25 + j*(-484) -416 + j*(-252) -323 + j*(-39) -201 + j*(-394) --221 + j*(351) -375 + j*(-190) -249 + j*(562) -197 + j*(-238) -235 + j*(336) -296 + j*(-149) --493 + j*(-477) -310 + j*(-543) -495 + j*(38) --320 + j*(308) --496 + j*(130) --392 + j*(-78) --478 + j*(103) --346 + j*(-525) --134 + j*(-368) --247 + j*(-150) --472 + j*(-18) --354 + j*(40) -349 + j*(131) --284 + j*(312) -308 + j*(189) -67 + j*(-427) --1 + j*(-159) -362 + j*(-454) -219 + j*(262) --53 + j*(-28) --501 + j*(-225) --359 + j*(547) -369 + j*(315) --344 + j*(-361) --492 + j*(403) -500 + j*(-291) -260 + j*(191) -194 + j*(-170) -324 + j*(280) -595 + j*(120) -185 + j*(123) -222 + j*(670) --309 + j*(219) --237 + j*(-138) -338 + j*(-388) --223 + j*(100) --140 + j*(-430) -685 + j*(115) -339 + j*(-9) --100 + j*(-745) --561 + j*(-101) -360 + j*(446) -191 + j*(-467) --243 + j*(-378) --107 + j*(-345) -21 + j*(620) --223 + j*(-322) -409 + j*(-306) --23 + j*(499) --259 + j*(-576) -493 + j*(658) -180 + j*(118) --378 + j*(198) -378 + j*(-53) --554 + j*(-61) --305 + j*(305) -95 + j*(415) -455 + j*(-305) --275 + j*(-77) -390 + j*(-62) --15 + j*(151) --238 + j*(191) --94 + j*(390) -369 + j*(262) -441 + j*(67) -439 + j*(-121) -315 + j*(66) -282 + j*(216) --193 + j*(-280) --194 + j*(625) --240 + j*(231) --228 + j*(68) -245 + j*(144) --467 + j*(64) -23 + j*(523) -46 + j*(-216) --248 + j*(390) -98 + j*(462) --378 + j*(329) -410 + j*(211) --81 + j*(277) -293 + j*(-16) -204 + j*(-506) --78 + j*(151) --88 + j*(455) -242 + j*(-62) --426 + j*(-105) --320 + j*(221) -84 + j*(-386) -398 + j*(565) -50 + j*(248) --254 + j*(-37) --179 + j*(479) --59 + j*(30) --225 + j*(253) -630 + j*(-185) --76 + j*(-363) -136 + j*(-498) -289 + j*(-79) -315 + j*(-177) -367 + j*(60) --131 + j*(-190) --482 + j*(-127) --68 + j*(220) -204 + j*(16) --175 + j*(45) -421 + j*(180) -231 + j*(-324) -93 + j*(334) --344 + j*(-599) --257 + j*(-276) --134 + j*(-98) -384 + j*(-203) -290 + j*(-177) --82 + j*(-226) --367 + j*(-1) -154 + j*(-307) --155 + j*(576) -216 + j*(279) -229 + j*(196) -35 + j*(138) --52 + j*(-210) -24 + j*(231) -153 + j*(-117) --125 + j*(-174) -23 + j*(-64) --96 + j*(-199) --167 + j*(16) -158 + j*(93) --180 + j*(-331) --42 + j*(-5) -6 + j*(521) --161 + j*(197) --6 + j*(-6) -268 + j*(107) --275 + j*(156) -245 + j*(-13) --52 + j*(-217) --221 + j*(355) -84 + j*(-42) -31 + j*(-204) --117 + j*(523) -211 + j*(268) --86 + j*(104) --181 + j*(-62) --45 + j*(-198) -141 + j*(82) --373 + j*(122) --151 + j*(5) --33 + j*(-191) -69 + j*(21) --124 + j*(30) --153 + j*(-206) --49 + j*(-235) --246 + j*(-214) --224 + j*(-144) --77 + j*(-115) --242 + j*(-233) -56 + j*(127) --137 + j*(-156) --108 + j*(-163) --60 + j*(-140) --91 + j*(73) --85 + j*(-101) --141 + j*(30) --144 + j*(34) -82 + j*(-5) -52 + j*(187) --285 + j*(-59) -62 + j*(271) --29 + j*(-113) --1 + j*(225) -101 + j*(-23) --143 + j*(196) --168 + j*(158) --211 + j*(-158) -71 + j*(-28) --115 + j*(-99) --49 + j*(-183) --58 + j*(8) --187 + j*(303) --6 + j*(-127) -188 + j*(-136) --66 + j*(-156) -134 + j*(-123) --78 + j*(41) --134 + j*(-218) --33 + j*(194) --33 + j*(-91) -15 + j*(326) -187 + j*(336) -9 + j*(21) -143 + j*(-202) -64 + j*(388) --179 + j*(-59) -149 + j*(-228) -62 + j*(255) --161 + j*(-35) --98 + j*(-286) --282 + j*(243) --2 + j*(112) --168 + j*(-325) --197 + j*(180) -182 + j*(-438) --193 + j*(-105) -103 + j*(-26) -168 + j*(135) --91 + j*(266) --94 + j*(-79) -165 + j*(228) -215 + j*(-136) --76 + j*(-318) --177 + j*(-263) --272 + j*(156) -337 + j*(-240) -310 + j*(95) -116 + j*(-1) -243 + j*(-195) -223 + j*(-48) --231 + j*(-1) -16 + j*(21) --153 + j*(66) -16 + j*(176) --52 + j*(136) -144 + j*(-22) -89 + j*(-197) -161 + j*(252) --122 + j*(-67) --258 + j*(127) --168 + j*(-146) --155 + j*(-39) -101 + j*(303) -60 + j*(-25) --305 + j*(67) --253 + j*(-231) -91 + j*(-173) -71 + j*(81) -23 + j*(186) --260 + j*(208) --2 + j*(149) --95 + j*(-175) -21 + j*(204) -402 + j*(-2) --8 + j*(-16) --175 + j*(150) -45 + j*(-235) -200 + j*(260) --375 + j*(-325) -179 + j*(166) -152 + j*(246) -6 + j*(80) -212 + j*(-17) --207 + j*(125) --6 + j*(12) -119 + j*(61) --115 + j*(320) -35 + j*(342) --184 + j*(-132) -62 + j*(-43) --151 + j*(125) -117 + j*(-96) -2 + j*(59) --90 + j*(-66) --18 + j*(239) --175 + j*(-296) -112 + j*(-147) -68 + j*(92) -61 + j*(-134) -8 + j*(-170) -59 + j*(225) -150 + j*(135) --108 + j*(-182) -120 + j*(340) --10 + j*(-316) -54 + j*(4) --40 + j*(29) -7 + j*(58) --280 + j*(143) --206 + j*(197) --183 + j*(181) --90 + j*(177) --115 + j*(26) --42 + j*(168) --34 + j*(-195) -32 + j*(125) -272 + j*(-323) --118 + j*(22) -125 + j*(-72) --164 + j*(296) -260 + j*(37) -133 + j*(228) -30 + j*(-123) -90 + j*(167) -39 + j*(83) -63 + j*(445) -7 + j*(-14) --21 + j*(83) --139 + j*(302) --600 + j*(137) --149 + j*(-34) -305 + j*(-392) -208 + j*(151) -26 + j*(16) -135 + j*(-170) --183 + j*(215) --78 + j*(1) --131 + j*(206) -202 + j*(356) -187 + j*(-204) -147 + j*(-86) -283 + j*(107) -30 + j*(-57) -182 + j*(36) --154 + j*(-84) -24 + j*(36) -124 + j*(52) --237 + j*(114) --218 + j*(39) --40 + j*(-302) --456 + j*(4) -136 + j*(63) --20 + j*(33) -81 + j*(-118) --52 + j*(140) -46 + j*(56) -146 + j*(-45) --85 + j*(-44) -33 + j*(-86) --76 + j*(-269) -143 + j*(91) --121 + j*(23) -12 + j*(93) --57 + j*(-215) -47 + j*(-370) -317 + j*(22) --103 + j*(16) -179 + j*(-135) -57 + j*(0) --30 + j*(88) -131 + j*(-74) -207 + j*(-72) --234 + j*(179) --226 + j*(-16) -226 + j*(161) -143 + j*(108) --95 + j*(-100) --24 + j*(-88) -380 + j*(102) -187 + j*(57) --23 + j*(188) -174 + j*(-252) -93 + j*(498) -194 + j*(196) -72 + j*(-33) --112 + j*(20) --106 + j*(-163) --93 + j*(-49) -98 + j*(100) --79 + j*(-144) --322 + j*(-298) --160 + j*(-301) -144 + j*(-13) -262 + j*(-20) --250 + j*(-38) -59 + j*(-44) --1 + j*(219) -234 + j*(-99) --3 + j*(-152) -160 + j*(-97) -359 + j*(152) --6 + j*(-20) --209 + j*(183) --36 + j*(192) --5 + j*(74) --171 + j*(-285) -11 + j*(49) --6 + j*(103) -18 + j*(147) --27 + j*(161) -4 + j*(-77) -193 + j*(-27) -81 + j*(89) --20 + j*(140) --253 + j*(-40) -246 + j*(104) -83 + j*(87) -160 + j*(-54) -277 + j*(4) -129 + j*(-228) -89 + j*(-37) -222 + j*(-259) -4 + j*(-252) --135 + j*(-66) --7 + j*(228) -190 + j*(133) --67 + j*(-235) -157 + j*(-184) -126 + j*(-25) --321 + j*(46) --291 + j*(-25) --365 + j*(-303) -83 + j*(-93) --286 + j*(77) --1 + j*(-198) --246 + j*(-414) -64 + j*(-129) -142 + j*(105) -188 + j*(-168) --139 + j*(-209) --58 + j*(330) --16 + j*(-140) --33 + j*(157) --77 + j*(-275) --151 + j*(-147) --37 + j*(-271) -206 + j*(254) -419 + j*(39) -156 + j*(-215) --33 + j*(86) -164 + j*(-355) --202 + j*(231) --162 + j*(-66) --112 + j*(-197) --72 + j*(-170) --66 + j*(-123) -70 + j*(245) --182 + j*(-83) -173 + j*(-288) -148 + j*(158) -38 + j*(324) -67 + j*(-69) -18 + j*(-21) -49 + j*(-88) -54 + j*(-108) --49 + j*(200) --228 + j*(-81) --436 + j*(-100) --21 + j*(-150) --58 + j*(-40) -368 + j*(-151) --32 + j*(-195) -30 + j*(-35) -190 + j*(21) -191 + j*(-153) --322 + j*(95) --42 + j*(-115) -103 + j*(-181) --110 + j*(183) -76 + j*(-199) --103 + j*(285) -81 + j*(271) -214 + j*(81) -10 + j*(6) -19 + j*(7) -149 + j*(42) --22 + j*(10) -211 + j*(-118) -126 + j*(-46) -276 + j*(163) -86 + j*(155) --108 + j*(19) --16 + j*(-174) -104 + j*(-542) -70 + j*(125) -168 + j*(128) --215 + j*(305) --2 + j*(35) --87 + j*(150) -50 + j*(-389) -111 + j*(136) --211 + j*(-159) --20 + j*(-172) -240 + j*(-195) -205 + j*(57) --98 + j*(43) -194 + j*(-65) --37 + j*(153) -30 + j*(123) --52 + j*(29) --266 + j*(8) --146 + j*(-105) -158 + j*(15) -69 + j*(-259) -304 + j*(176) -96 + j*(160) --39 + j*(-62) -5 + j*(80) --24 + j*(214) -152 + j*(61) -119 + j*(-291) --44 + j*(168) -48 + j*(431) --17 + j*(66) --4 + j*(264) --88 + j*(33) --160 + j*(-226) --238 + j*(-113) -42 + j*(-112) -75 + j*(30) -130 + j*(-27) -100 + j*(175) -106 + j*(-87) --320 + j*(-256) -122 + j*(-37) --141 + j*(-22) -80 + j*(-106) -301 + j*(-71) -117 + j*(-21) -93 + j*(419) -46 + j*(-291) --59 + j*(-177) --76 + j*(47) --64 + j*(-56) --12 + j*(74) --79 + j*(-18) -214 + j*(-89) -122 + j*(-144) --142 + j*(-150) --199 + j*(-298) -13 + j*(-134) --366 + j*(21) --2 + j*(-26) --30 + j*(139) --328 + j*(-211) --141 + j*(235) -253 + j*(-21) --219 + j*(-209) --71 + j*(-62) -82 + j*(-146) --127 + j*(261) --319 + j*(-255) --121 + j*(86) -585 + j*(32) --54 + j*(-60) -282 + j*(58) --122 + j*(221) -84 + j*(110) --153 + j*(1) -44 + j*(209) -229 + j*(110) -313 + j*(69) -202 + j*(-211) -39 + j*(21) -194 + j*(177) -209 + j*(69) --30 + j*(-167) -127 + j*(38) --177 + j*(11) --41 + j*(86) --15 + j*(243) -78 + j*(11) --79 + j*(-228) --116 + j*(-86) -23 + j*(47) -383 + j*(73) -203 + j*(-68) -111 + j*(140) --63 + j*(68) --82 + j*(-229) --157 + j*(-313) --190 + j*(279) --104 + j*(61) --180 + j*(-204) -265 + j*(-153) --42 + j*(-48) -100 + j*(172) --147 + j*(-308) -267 + j*(54) --112 + j*(272) --264 + j*(-36) -29 + j*(-332) -140 + j*(-86) -400 + j*(-38) --121 + j*(-231) --42 + j*(344) -129 + j*(-81) --111 + j*(226) -3 + j*(150) --37 + j*(18) -0 + j*(-82) -153 + j*(151) -81 + j*(91) --136 + j*(184) -503 + j*(-113) --49 + j*(319) -70 + j*(77) -197 + j*(-66) --62 + j*(149) -254 + j*(-122) -45 + j*(-32) -3 + j*(9) -25 + j*(89) -6 + j*(-45) --22 + j*(161) --40 + j*(83) -103 + j*(23) -110 + j*(278) -8 + j*(-61) --57 + j*(37) --99 + j*(86) --64 + j*(339) --37 + j*(214) --84 + j*(6) -303 + j*(-178) -205 + j*(97) -11 + j*(194) -129 + j*(11) -687 + j*(-100) -187 + j*(-238) -40 + j*(-74) -332 + j*(-25) --94 + j*(165) -64 + j*(246) --291 + j*(-108) --121 + j*(-284) -216 + j*(-104) -159 + j*(23) -75 + j*(-47) -70 + j*(4) --10 + j*(-34) --155 + j*(34) --35 + j*(89) --13 + j*(-134) --99 + j*(40) --463 + j*(-13) --252 + j*(172) --22 + j*(-351) --69 + j*(88) --284 + j*(-21) -13 + j*(-6) --35 + j*(-71) --40 + j*(317) -405 + j*(-60) --358 + j*(104) -56 + j*(-119) --135 + j*(-156) --66 + j*(-23) -168 + j*(59) -148 + j*(-76) --213 + j*(-190) --190 + j*(-27) -103 + j*(392) -52 + j*(110) -211 + j*(-61) --165 + j*(218) -3 + j*(-231) -69 + j*(-161) --263 + j*(54) -98 + j*(-191) -30 + j*(167) -45 + j*(9) --373 + j*(181) -69 + j*(105) --23 + j*(-100) --127 + j*(-9) --64 + j*(287) -202 + j*(290) -115 + j*(-109) --72 + j*(-205) -166 + j*(238) -151 + j*(-25) -186 + j*(290) --108 + j*(33) --163 + j*(-180) -148 + j*(124) -94 + j*(-270) --52 + j*(27) -161 + j*(134) --61 + j*(-25) --23 + j*(-233) -93 + j*(-245) -57 + j*(162) --172 + j*(-354) -133 + j*(129) -339 + j*(107) -12 + j*(65) -6 + j*(-80) --51 + j*(-17) --13 + j*(-37) --18 + j*(-258) --54 + j*(-141) -295 + j*(6) --215 + j*(-192) --109 + j*(-73) -105 + j*(43) --277 + j*(-251) -57 + j*(188) --38 + j*(390) --117 + j*(-390) -107 + j*(233) -131 + j*(98) -366 + j*(-215) --136 + j*(-154) -45 + j*(-112) --10 + j*(-6) -27 + j*(-114) --119 + j*(8) --163 + j*(-4) -78 + j*(261) -221 + j*(-37) --92 + j*(-23) -4 + j*(221) --2 + j*(-153) --76 + j*(-158) -66 + j*(141) --182 + j*(136) --446 + j*(-88) -71 + j*(-145) --75 + j*(-87) -101 + j*(-97) --177 + j*(146) -93 + j*(21) -324 + j*(397) -281 + j*(-229) --138 + j*(117) --188 + j*(112) -39 + j*(-66) -163 + j*(-98) -71 + j*(57) --65 + j*(187) -125 + j*(197) --135 + j*(141) --105 + j*(47) -19 + j*(-86) -66 + j*(-235) --480 + j*(225) -76 + j*(28) -342 + j*(47) -0 + j*(-366) --140 + j*(74) -193 + j*(144) --126 + j*(-43) --191 + j*(158) --180 + j*(-55) -63 + j*(-255) --98 + j*(-2) --13 + j*(308) --183 + j*(207) -144 + j*(37) --51 + j*(-175) -28 + j*(-29) --211 + j*(356) --132 + j*(173) --173 + j*(199) -36 + j*(329) --139 + j*(228) --311 + j*(177) -65 + j*(-343) --217 + j*(-20) -119 + j*(18) -29 + j*(-58) -156 + j*(129) --41 + j*(23) -202 + j*(-163) -224 + j*(196) --47 + j*(25) -15 + j*(-122) --182 + j*(280) --170 + j*(21) -8 + j*(-144) -20 + j*(246) --148 + j*(143) -91 + j*(93) -168 + j*(44) --100 + j*(270) --51 + j*(-167) --285 + j*(125) --93 + j*(63) --1 + j*(-290) --214 + j*(-47) --78 + j*(243) --156 + j*(-314) -152 + j*(57) -163 + j*(267) -8 + j*(-167) --262 + j*(114) -132 + j*(49) -199 + j*(-85) -3 + j*(228) -57 + j*(-151) -104 + j*(-98) --45 + j*(-381) -238 + j*(-59) --62 + j*(-158) --96 + j*(-87) -8 + j*(279) --84 + j*(260) -276 + j*(127) --142 + j*(-42) --119 + j*(-185) -67 + j*(134) --20 + j*(129) --47 + j*(-30) --250 + j*(156) -200 + j*(108) --450 + j*(49) --30 + j*(87) -205 + j*(-137) --165 + j*(217) -100 + j*(-165) --52 + j*(-71) --232 + j*(-131) --289 + j*(-36) -310 + j*(-194) --88 + j*(127) -17 + j*(-71) -50 + j*(232) -181 + j*(21) --65 + j*(-333) -158 + j*(-238) -176 + j*(-210) --279 + j*(173) --21 + j*(-192) --363 + j*(-361) -6 + j*(185) --25 + j*(-4) -62 + j*(-21) -33 + j*(-59) -2 + j*(-121) --192 + j*(-84) -32 + j*(204) -23 + j*(57) --186 + j*(341) -1 + j*(-191) --262 + j*(-313) -121 + j*(13) --211 + j*(-185) --470 + j*(23) --221 + j*(94) -50 + j*(25) --277 + j*(53) -174 + j*(29) --26 + j*(-297) --1 + j*(-285) -90 + j*(-249) -50 + j*(214) -72 + j*(-9) --107 + j*(-288) --98 + j*(-368) --146 + j*(-28) --135 + j*(-53) --245 + j*(240) --88 + j*(134) -211 + j*(-91) --175 + j*(42) -117 + j*(212) -179 + j*(-4) --96 + j*(202) --119 + j*(-134) -22 + j*(291) --515 + j*(119) -36 + j*(-319) -190 + j*(-428) -128 + j*(-48) -458 + j*(-10) --104 + j*(-23) --51 + j*(173) -93 + j*(95) --222 + j*(47) --141 + j*(-39) --175 + j*(-116) -35 + j*(-10) -56 + j*(-146) -275 + j*(14) -14 + j*(31) --105 + j*(-30) -105 + j*(64) -21 + j*(-163) --33 + j*(-29) --56 + j*(-397) --235 + j*(-142) --91 + j*(-166) --112 + j*(-132) -342 + j*(116) -76 + j*(-300) --118 + j*(71) --137 + j*(196) -83 + j*(204) -89 + j*(-214) -78 + j*(-142) --82 + j*(-71) --301 + j*(-57) -141 + j*(111) --74 + j*(4) --76 + j*(179) --545 + j*(209) -121 + j*(-37) -303 + j*(121) --182 + j*(47) -83 + j*(-137) -251 + j*(118) -60 + j*(36) -134 + j*(221) -257 + j*(245) -30 + j*(-115) -192 + j*(-68) --280 + j*(-52) --197 + j*(255) --106 + j*(23) --2 + j*(-309) -175 + j*(305) -78 + j*(31) -86 + j*(-110) --37 + j*(-164) --28 + j*(135) -29 + j*(-107) -161 + j*(228) -269 + j*(167) --46 + j*(-32) --175 + j*(-12) -244 + j*(-436) --118 + j*(276) --151 + j*(-311) --127 + j*(91) -27 + j*(182) -71 + j*(-19) -170 + j*(-5) --67 + j*(75) -196 + j*(233) -253 + j*(47) --23 + j*(-124) -10 + j*(-184) --90 + j*(-4) --13 + j*(-43) --248 + j*(-177) --4 + j*(-153) -192 + j*(-52) --232 + j*(-206) -238 + j*(138) --165 + j*(55) --158 + j*(-70) -77 + j*(55) --6 + j*(47) -227 + j*(-101) -7 + j*(281) --52 + j*(156) -137 + j*(-203) -56 + j*(64) -71 + j*(16) --171 + j*(-17) --127 + j*(325) -8 + j*(91) --107 + j*(197) --25 + j*(22) --203 + j*(-243) -120 + j*(57) -205 + j*(-311) -117 + j*(30) --167 + j*(149) -202 + j*(27) --257 + j*(177) --293 + j*(76) --211 + j*(-262) --106 + j*(-71) --43 + j*(-121) --140 + j*(-146) --118 + j*(138) -114 + j*(-126) -114 + j*(35) --208 + j*(59) -177 + j*(34) --18 + j*(-115) -60 + j*(9) --24 + j*(-62) -288 + j*(66) --176 + j*(-223) -94 + j*(69) -334 + j*(-168) -281 + j*(-23) --40 + j*(139) --59 + j*(-4) --45 + j*(-16) -100 + j*(-16) -216 + j*(-39) -30 + j*(-128) --351 + j*(161) -67 + j*(-194) --213 + j*(-55) -102 + j*(-107) -236 + j*(-30) -317 + j*(-180) -66 + j*(-140) --4 + j*(157) --191 + j*(-49) --101 + j*(-248) --21 + j*(-175) --9 + j*(-108) --268 + j*(-51) -158 + j*(168) -11 + j*(117) --4 + j*(78) -77 + j*(186) -72 + j*(-84) --88 + j*(-228) --66 + j*(-83) --272 + j*(-322) --123 + j*(-65) --105 + j*(25) -368 + j*(-404) -0 + j*(-161) -162 + j*(-31) -96 + j*(232) -236 + j*(-275) -40 + j*(-96) -250 + j*(-218) --234 + j*(-142) --10 + j*(63) --264 + j*(210) -40 + j*(-186) --290 + j*(4) -176 + j*(-90) -109 + j*(282) -13 + j*(465) -40 + j*(7) -129 + j*(-70) --30 + j*(7) --151 + j*(71) --240 + j*(152) --238 + j*(-159) -50 + j*(-19) --81 + j*(76) -132 + j*(-339) -7 + j*(190) -68 + j*(-272) --231 + j*(199) --6 + j*(-153) --71 + j*(224) --362 + j*(203) -122 + j*(-11) -125 + j*(-11) -40 + j*(-13) -69 + j*(370) -128 + j*(-18) --73 + j*(77) --194 + j*(-13) -144 + j*(33) -168 + j*(331) --224 + j*(-53) -18 + j*(-140) --47 + j*(232) -20 + j*(-175) -235 + j*(-91) -241 + j*(-113) --290 + j*(-156) --180 + j*(-276) --187 + j*(69) --25 + j*(-264) --29 + j*(-21) --70 + j*(-210) --301 + j*(-95) --34 + j*(-162) --252 + j*(10) -80 + j*(-33) --62 + j*(-161) -14 + j*(29) -83 + j*(170) -154 + j*(-146) -50 + j*(-245) -112 + j*(82) --60 + j*(132) -257 + j*(174) --10 + j*(-168) -147 + j*(-98) --224 + j*(-255) --240 + j*(-171) -155 + j*(-137) --81 + j*(138) --325 + j*(-52) -247 + j*(141) --365 + j*(16) -385 + j*(-28) -165 + j*(-25) --62 + j*(60) --140 + j*(-218) -426 + j*(178) --83 + j*(156) -163 + j*(-32) -263 + j*(13) --159 + j*(45) --7 + j*(-478) --43 + j*(221) -37 + j*(-121) -57 + j*(-92) -4 + j*(207) --91 + j*(-10) --173 + j*(31) -182 + j*(-86) -153 + j*(59) --259 + j*(-192) -185 + j*(-95) -155 + j*(169) -136 + j*(-41) --330 + j*(-250) --178 + j*(-422) -218 + j*(307) -264 + j*(-365) -317 + j*(-4) -424 + j*(-73) --162 + j*(-162) --238 + j*(-79) --28 + j*(270) --309 + j*(224) -230 + j*(42) -168 + j*(66) -243 + j*(-93) --57 + j*(248) --28 + j*(131) --1 + j*(173) --61 + j*(-118) --35 + j*(104) -156 + j*(-25) -20 + j*(182) --57 + j*(-141) --115 + j*(-38) -68 + j*(-209) -97 + j*(-191) -170 + j*(226) -70 + j*(42) --115 + j*(105) --105 + j*(167) --153 + j*(-176) -1 + j*(214) -144 + j*(404) -76 + j*(303) -220 + j*(2) --428 + j*(-21) --53 + j*(49) --35 + j*(262) -29 + j*(-51) -104 + j*(-71) -161 + j*(-219) -57 + j*(-207) --167 + j*(200) --170 + j*(174) --46 + j*(-60) -4 + j*(-160) -117 + j*(50) -390 + j*(21) --37 + j*(16) -3 + j*(-183) --27 + j*(194) -93 + j*(42) --457 + j*(214) -310 + j*(-107) --8 + j*(-76) -282 + j*(183) --30 + j*(56) -201 + j*(322) -421 + j*(227) -230 + j*(-49) -156 + j*(-142) --208 + j*(-272) --81 + j*(-156) --293 + j*(-89) --108 + j*(-82) -225 + j*(73) --69 + j*(91) --227 + j*(-105) -350 + j*(-50) -8 + j*(-212) --149 + j*(234) --61 + j*(139) -134 + j*(-105) -177 + j*(-169) --113 + j*(113) -178 + j*(44) -120 + j*(62) --1 + j*(253) --45 + j*(-24) -240 + j*(-194) -23 + j*(90) -237 + j*(68) --13 + j*(83) --148 + j*(-37) -136 + j*(-278) --175 + j*(334) -160 + j*(-148) -153 + j*(-133) -60 + j*(124) --221 + j*(-114) -96 + j*(116) --43 + j*(30) -38 + j*(-186) --302 + j*(-27) -93 + j*(-78) --64 + j*(274) --75 + j*(-1) -66 + j*(232) -199 + j*(22) --64 + j*(40) --199 + j*(66) -168 + j*(-209) -122 + j*(-142) -305 + j*(71) --11 + j*(-146) --418 + j*(5) -24 + j*(133) -203 + j*(-218) -394 + j*(165) --156 + j*(-112) -93 + j*(-129) --204 + j*(59) -95 + j*(317) --151 + j*(-274) --122 + j*(-175) --115 + j*(-29) --50 + j*(-112) -224 + j*(-140) -47 + j*(-1) --80 + j*(-177) --244 + j*(-238) --102 + j*(45) --117 + j*(-63) -62 + j*(8) --85 + j*(20) --209 + j*(-100) --118 + j*(-187) --158 + j*(57) --174 + j*(-190) --23 + j*(389) --24 + j*(110) --163 + j*(-100) -45 + j*(234) --49 + j*(76) --349 + j*(193) --40 + j*(-93) -162 + j*(120) --119 + j*(-11) --126 + j*(322) -42 + j*(240) -49 + j*(-10) -445 + j*(175) --243 + j*(78) -95 + j*(-86) -237 + j*(66) -148 + j*(-190) --105 + j*(37) -112 + j*(40) --134 + j*(-176) -241 + j*(-241) --398 + j*(185) --57 + j*(36) -323 + j*(36) -206 + j*(-162) --100 + j*(231) --121 + j*(192) -52 + j*(68) -113 + j*(-16) --312 + j*(-42) -185 + j*(-37) --140 + j*(124) -252 + j*(-82) -74 + j*(-66) --182 + j*(-21) --168 + j*(-48) --198 + j*(-36) --100 + j*(-97) -108 + j*(-23) -16 + j*(-69) --303 + j*(-143) --182 + j*(-119) -149 + j*(-485) -279 + j*(110) --151 + j*(-129) -263 + j*(-245) -166 + j*(28) -216 + j*(74) -25 + j*(96) --122 + j*(146) -81 + j*(103) -129 + j*(-6) --167 + j*(-17) --351 + j*(-259) -3 + j*(-125) --163 + j*(68) -279 + j*(91) --49 + j*(-257) -195 + j*(-93) -47 + j*(118) --197 + j*(-392) --125 + j*(-238) -284 + j*(48) -218 + j*(-397) -72 + j*(-14) --46 + j*(223) --140 + j*(-227) -182 + j*(-205) --218 + j*(-226) --57 + j*(-305) --48 + j*(-37) --199 + j*(-303) -16 + j*(-168) -38 + j*(-11) --73 + j*(-53) --142 + j*(-253) --83 + j*(246) -77 + j*(-91) --128 + j*(-83) --315 + j*(-84) --229 + j*(-173) --238 + j*(-5) -118 + j*(-53) --119 + j*(124) -57 + j*(-78) -33 + j*(-105) --52 + j*(-35) --11 + j*(87) --172 + j*(18) --40 + j*(-88) --42 + j*(188) -3 + j*(-257) --205 + j*(97) -244 + j*(337) --30 + j*(35) -52 + j*(-91) --379 + j*(-11) --187 + j*(-46) --99 + j*(-209) --197 + j*(-16) --168 + j*(-129) --429 + j*(34) --54 + j*(-23) --110 + j*(-78) -328 + j*(98) --142 + j*(139) --204 + j*(124) --123 + j*(-131) --110 + j*(-260) -47 + j*(-187) -138 + j*(121) --160 + j*(91) --414 + j*(-91) --73 + j*(169) --91 + j*(-195) --343 + j*(-139) --105 + j*(-62) -127 + j*(308) -43 + j*(147) --381 + j*(40) --107 + j*(197) -264 + j*(-93) --170 + j*(122) -156 + j*(-71) --37 + j*(233) -77 + j*(51) -152 + j*(14) --35 + j*(76) --259 + j*(124) --253 + j*(10) -234 + j*(-71) -562 + j*(-276) -0 + j*(88) -45 + j*(115) --56 + j*(-43) -262 + j*(25) --69 + j*(119) --143 + j*(-172) -176 + j*(-386) --144 + j*(38) --18 + j*(170) -259 + j*(-262) --8 + j*(88) --113 + j*(-90) -139 + j*(74) -141 + j*(-67) -208 + j*(-146) -118 + j*(46) --156 + j*(-5) --69 + j*(-154) --252 + j*(115) -93 + j*(6) -55 + j*(257) -19 + j*(62) -211 + j*(129) --421 + j*(107) -120 + j*(77) --86 + j*(-219) --292 + j*(-37) --13 + j*(-209) --185 + j*(-60) --71 + j*(163) --301 + j*(-11) --138 + j*(188) -110 + j*(6) -310 + j*(356) -101 + j*(-104) --11 + j*(125) -107 + j*(81) -157 + j*(-269) --98 + j*(-77) -427 + j*(-223) --159 + j*(154) -11 + j*(148) --168 + j*(-61) -19 + j*(-80) --69 + j*(276) --376 + j*(283) -23 + j*(91) --237 + j*(41) --194 + j*(11) --209 + j*(-356) --21 + j*(170) --204 + j*(92) -180 + j*(89) --72 + j*(52) --102 + j*(128) -155 + j*(-105) --308 + j*(215) --206 + j*(187) --31 + j*(27) --264 + j*(33) -192 + j*(50) --184 + j*(-98) --213 + j*(-190) --296 + j*(-141) -42 + j*(-74) -59 + j*(153) --2 + j*(-122) -124 + j*(-98) -37 + j*(-61) --5 + j*(-226) --327 + j*(-73) -187 + j*(238) --193 + j*(145) --49 + j*(199) -12 + j*(-103) -254 + j*(-51) -138 + j*(-86) -166 + j*(-317) -61 + j*(-37) --264 + j*(37) --108 + j*(-327) --274 + j*(312) --293 + j*(146) --120 + j*(-36) -153 + j*(-57) -91 + j*(205) --26 + j*(432) --310 + j*(168) -137 + j*(171) --57 + j*(11) -233 + j*(-103) --19 + j*(-187) --33 + j*(-207) --239 + j*(153) -250 + j*(-412) -23 + j*(-238) -218 + j*(-332) -284 + j*(-149) -68 + j*(37) --3 + j*(303) -145 + j*(90) -7 + j*(-6) -93 + j*(-117) -218 + j*(-139) --204 + j*(30) --51 + j*(-193) --52 + j*(-139) --104 + j*(-123) --164 + j*(55) -169 + j*(12) --155 + j*(-104) -230 + j*(26) --1 + j*(93) --243 + j*(-438) --313 + j*(98) -22 + j*(-40) --18 + j*(166) -116 + j*(-16) --221 + j*(156) -10 + j*(-282) --21 + j*(41) --111 + j*(-107) -78 + j*(68) --165 + j*(14) --99 + j*(16) -315 + j*(66) -11 + j*(-98) -65 + j*(97) --82 + j*(227) -35 + j*(-300) --29 + j*(30) -222 + j*(-175) -89 + j*(91) -133 + j*(-55) --165 + j*(26) -294 + j*(-19) --134 + j*(173) --6 + j*(-123) -265 + j*(316) --37 + j*(-37) -37 + j*(-9) --28 + j*(54) -66 + j*(52) --2 + j*(-216) -111 + j*(-18) -144 + j*(153) -46 + j*(17) --18 + j*(184) --277 + j*(-111) -136 + j*(-34) -181 + j*(-19) --358 + j*(42) -112 + j*(24) --58 + j*(-71) -21 + j*(89) -250 + j*(2) --151 + j*(7) --45 + j*(29) --100 + j*(-1) --96 + j*(148) -197 + j*(52) --18 + j*(-540) -7 + j*(-98) --18 + j*(27) -74 + j*(166) --16 + j*(-130) -62 + j*(108) -37 + j*(88) --97 + j*(-153) --11 + j*(36) --204 + j*(48) -70 + j*(115) --161 + j*(142) --72 + j*(-76) -156 + j*(112) -149 + j*(317) --163 + j*(193) -353 + j*(-178) -160 + j*(-74) -67 + j*(201) --218 + j*(146) -111 + j*(42) --27 + j*(28) --207 + j*(-126) -115 + j*(68) -178 + j*(95) -110 + j*(-12) -74 + j*(-181) --38 + j*(-50) -147 + j*(321) -132 + j*(110) -297 + j*(158) --107 + j*(59) -100 + j*(142) --35 + j*(252) -122 + j*(69) -105 + j*(-229) -34 + j*(-2) -479 + j*(-9) --16 + j*(96) -201 + j*(-258) --104 + j*(133) -129 + j*(-23) -194 + j*(134) --106 + j*(-35) --281 + j*(-300) -36 + j*(-212) --175 + j*(21) --287 + j*(86) -79 + j*(-139) -173 + j*(133) -16 + j*(-117) --152 + j*(33) -201 + j*(-59) --149 + j*(150) --75 + j*(-175) --416 + j*(-181) --64 + j*(-284) -0 + j*(401) --170 + j*(425) --214 + j*(-47) --211 + j*(247) --98 + j*(8) --129 + j*(447) -271 + j*(272) -9 + j*(-279) --64 + j*(-25) -176 + j*(240) --462 + j*(-388) --25 + j*(391) -132 + j*(-235) -173 + j*(-240) -371 + j*(-346) -230 + j*(-164) --228 + j*(18) --81 + j*(323) -150 + j*(89) -197 + j*(-226) -387 + j*(-117) -170 + j*(-281) --300 + j*(-19) --4 + j*(-175) -428 + j*(-17) -523 + j*(419) -168 + j*(455) --202 + j*(-57) --372 + j*(-344) --133 + j*(-50) -87 + j*(-18) --21 + j*(347) -237 + j*(446) --267 + j*(-60) --407 + j*(-203) --99 + j*(-204) -259 + j*(247) --342 + j*(342) -273 + j*(330) --400 + j*(238) -365 + j*(-625) -400 + j*(-322) -5 + j*(168) -371 + j*(329) -148 + j*(443) -134 + j*(-100) --497 + j*(272) --395 + j*(400) --403 + j*(267) -411 + j*(-407) --341 + j*(-416) -155 + j*(-460) -332 + j*(-323) --194 + j*(42) --268 + j*(133) -224 + j*(-124) -535 + j*(478) -143 + j*(-390) -368 + j*(-152) --110 + j*(-284) --693 + j*(-241) --386 + j*(450) --215 + j*(373) --156 + j*(189) -349 + j*(-105) -390 + j*(61) -269 + j*(-430) -183 + j*(-207) --150 + j*(-489) -518 + j*(531) -186 + j*(692) -395 + j*(-305) -166 + j*(249) -243 + j*(-417) --135 + j*(-226) -103 + j*(46) -281 + j*(125) -182 + j*(351) --250 + j*(40) --157 + j*(-467) --240 + j*(178) -170 + j*(-20) --379 + j*(-303) --149 + j*(295) -444 + j*(-149) -595 + j*(231) --92 + j*(-199) --362 + j*(-141) --561 + j*(33) -588 + j*(-375) --267 + j*(-479) -327 + j*(100) --598 + j*(-174) --42 + j*(406) -342 + j*(-147) -336 + j*(-131) -140 + j*(115) -438 + j*(119) --50 + j*(100) -277 + j*(402) --230 + j*(-449) -202 + j*(367) -388 + j*(-771) -288 + j*(-619) -204 + j*(-395) --47 + j*(-322) --293 + j*(322) --315 + j*(-171) --141 + j*(127) --414 + j*(-54) -36 + j*(366) --325 + j*(466) -471 + j*(-397) --284 + j*(-148) --380 + j*(111) -277 + j*(-126) -252 + j*(220) -81 + j*(-233) -241 + j*(-114) --260 + j*(417) -462 + j*(-177) --95 + j*(398) --182 + j*(-351) --76 + j*(-392) --268 + j*(-288) -351 + j*(-228) -501 + j*(62) -51 + j*(273) --418 + j*(-262) -385 + j*(198) --156 + j*(497) -185 + j*(-89) --111 + j*(-339) --297 + j*(260) -141 + j*(-395) -202 + j*(-265) -291 + j*(-190) -344 + j*(83) --349 + j*(64) --132 + j*(284) -361 + j*(363) -212 + j*(241) -527 + j*(514) -69 + j*(530) -403 + j*(281) --375 + j*(-121) --355 + j*(-482) -177 + j*(158) -187 + j*(-8) -696 + j*(-346) -132 + j*(-311) -1 + j*(213) -395 + j*(-237) -303 + j*(246) -320 + j*(-262) -308 + j*(187) -527 + j*(18) --641 + j*(192) --265 + j*(-494) -703 + j*(446) -412 + j*(116) --544 + j*(392) -219 + j*(387) --129 + j*(351) --192 + j*(187) --379 + j*(-465) -322 + j*(-293) -192 + j*(-500) -22 + j*(351) --387 + j*(-301) --67 + j*(456) -194 + j*(450) -218 + j*(-581) --276 + j*(-107) -187 + j*(198) -28 + j*(-418) --85 + j*(292) --156 + j*(-344) --214 + j*(-260) --151 + j*(-267) -41 + j*(-289) -347 + j*(329) --33 + j*(-435) -76 + j*(298) -202 + j*(222) --78 + j*(284) -575 + j*(-494) -291 + j*(204) -197 + j*(523) --494 + j*(-342) -86 + j*(328) -257 + j*(600) -236 + j*(-177) --128 + j*(-152) --214 + j*(-280) -251 + j*(352) --202 + j*(17) -74 + j*(424) --280 + j*(276) --160 + j*(293) -337 + j*(310) --448 + j*(-120) --243 + j*(-566) --279 + j*(-2) -298 + j*(483) --263 + j*(459) --253 + j*(-158) --312 + j*(-397) --192 + j*(228) --249 + j*(-423) -51 + j*(-308) -526 + j*(-261) -74 + j*(446) --124 + j*(-276) --95 + j*(444) -16 + j*(163) --301 + j*(110) -457 + j*(-303) --216 + j*(-169) -429 + j*(-260) --603 + j*(436) -57 + j*(324) --115 + j*(-294) -313 + j*(295) -470 + j*(-225) -518 + j*(129) --504 + j*(-204) --540 + j*(-33) --177 + j*(-329) -253 + j*(-247) --467 + j*(-372) -185 + j*(-238) -267 + j*(186) --384 + j*(141) -250 + j*(-291) --3 + j*(-309) --214 + j*(-30) -118 + j*(635) --256 + j*(327) -312 + j*(-137) -197 + j*(-70) -18 + j*(-503) -317 + j*(367) -181 + j*(-424) --344 + j*(-240) -57 + j*(-547) --364 + j*(13) --27 + j*(-107) --59 + j*(80) -369 + j*(51) --217 + j*(-81) --407 + j*(509) -291 + j*(182) --293 + j*(334) -28 + j*(-156) --438 + j*(400) -343 + j*(-96) -477 + j*(371) --287 + j*(-291) -482 + j*(328) --282 + j*(-414) -61 + j*(179) --224 + j*(-69) --153 + j*(331) -188 + j*(-46) -41 + j*(-78) --571 + j*(556) --293 + j*(91) --260 + j*(90) -239 + j*(-81) --174 + j*(-201) -262 + j*(189) --197 + j*(-334) -368 + j*(311) --501 + j*(88) --48 + j*(-481) -325 + j*(389) --238 + j*(86) --356 + j*(-254) --293 + j*(-133) -287 + j*(380) -527 + j*(33) -497 + j*(-288) -432 + j*(-242) -409 + j*(-207) -28 + j*(-156) --240 + j*(181) --320 + j*(-711) --104 + j*(-373) -341 + j*(-32) --406 + j*(-363) -155 + j*(57) --262 + j*(190) -210 + j*(742) -65 + j*(-220) --291 + j*(-206) --197 + j*(352) --100 + j*(-406) -356 + j*(320) --412 + j*(217) --3 + j*(602) -382 + j*(-284) --122 + j*(93) --682 + j*(-298) -276 + j*(62) --551 + j*(75) -607 + j*(474) -26 + j*(235) -252 + j*(-453) --262 + j*(-438) --40 + j*(-168) --53 + j*(71) -192 + j*(431) -435 + j*(-244) -380 + j*(358) --403 + j*(-416) --105 + j*(-338) -58 + j*(-154) --199 + j*(-422) --193 + j*(391) -281 + j*(-103) -298 + j*(-147) -426 + j*(-414) -398 + j*(100) -165 + j*(140) -126 + j*(-89) -122 + j*(300) --155 + j*(-434) --440 + j*(69) -391 + j*(-152) --307 + j*(-64) -285 + j*(-441) --154 + j*(-491) --419 + j*(-529) --31 + j*(-330) -60 + j*(81) --173 + j*(132) -488 + j*(338) --42 + j*(-450) --159 + j*(-192) --74 + j*(-560) -235 + j*(-305) --415 + j*(-184) --165 + j*(-223) -158 + j*(383) -27 + j*(-197) --255 + j*(-47) -438 + j*(315) -138 + j*(-294) --40 + j*(-127) -337 + j*(-310) -257 + j*(239) -25 + j*(385) --507 + j*(55) --337 + j*(185) -355 + j*(501) --223 + j*(258) -161 + j*(-298) --408 + j*(-71) --342 + j*(351) -256 + j*(-382) --455 + j*(194) --324 + j*(457) --124 + j*(509) --184 + j*(209) -51 + j*(-226) --337 + j*(-282) --38 + j*(-43) -95 + j*(110) -163 + j*(-158) --318 + j*(-346) -160 + j*(321) --257 + j*(310) -305 + j*(-486) -258 + j*(214) --281 + j*(-214) -293 + j*(9) --225 + j*(-240) -207 + j*(-445) --308 + j*(185) --59 + j*(-70) --493 + j*(-380) -655 + j*(-197) --268 + j*(-100) -315 + j*(-30) -382 + j*(-180) -45 + j*(-370) -396 + j*(391) --488 + j*(-400) --333 + j*(-64) --162 + j*(456) --315 + j*(-665) -229 + j*(205) --97 + j*(441) -278 + j*(227) --42 + j*(-278) --182 + j*(413) -286 + j*(69) --286 + j*(530) -86 + j*(326) -196 + j*(257) --218 + j*(161) -444 + j*(-151) --243 + j*(11) --325 + j*(329) -648 + j*(55) -546 + j*(632) --120 + j*(370) -127 + j*(-274) -341 + j*(356) -605 + j*(-571) -129 + j*(441) --491 + j*(-367) -427 + j*(-232) --573 + j*(33) -99 + j*(240) --359 + j*(-138) -229 + j*(165) -309 + j*(119) -242 + j*(284) --192 + j*(27) -621 + j*(-439) --198 + j*(181) --245 + j*(275) --130 + j*(-330) -286 + j*(187) -295 + j*(-190) -665 + j*(218) -266 + j*(-188) --49 + j*(-291) --264 + j*(-29) -156 + j*(-284) -106 + j*(200) -342 + j*(250) -456 + j*(8) --72 + j*(-268) -132 + j*(385) -190 + j*(-104) -125 + j*(-565) -233 + j*(103) -260 + j*(9) -6 + j*(-413) -358 + j*(-296) --222 + j*(-221) --90 + j*(335) -361 + j*(-165) -440 + j*(344) --477 + j*(81) --384 + j*(-272) -366 + j*(144) -482 + j*(268) -368 + j*(-361) -270 + j*(-76) -238 + j*(-549) --412 + j*(-489) --165 + j*(28) --234 + j*(303) -53 + j*(263) --335 + j*(463) -435 + j*(-43) -402 + j*(-403) -573 + j*(438) --498 + j*(-515) --197 + j*(243) -456 + j*(28) --546 + j*(409) --193 + j*(-208) -66 + j*(417) --84 + j*(330) --218 + j*(-150) -378 + j*(202) -177 + j*(-46) -472 + j*(106) --259 + j*(-188) -291 + j*(-82) -251 + j*(423) -187 + j*(-513) -385 + j*(206) --281 + j*(-349) -105 + j*(202) --230 + j*(448) --470 + j*(-348) -13 + j*(-522) --318 + j*(-141) --642 + j*(-298) -82 + j*(-451) --448 + j*(419) -349 + j*(435) --437 + j*(618) --74 + j*(-261) -207 + j*(-99) --386 + j*(292) -290 + j*(-264) -431 + j*(-342) -346 + j*(-221) -240 + j*(151) --209 + j*(-525) --188 + j*(-429) --590 + j*(-514) -409 + j*(-223) --315 + j*(285) --521 + j*(-451) -202 + j*(458) --221 + j*(-139) -236 + j*(378) --672 + j*(421) -1 + j*(315) --83 + j*(-494) --306 + j*(396) -185 + j*(-515) --528 + j*(120) --441 + j*(96) --17 + j*(-30) -213 + j*(271) -631 + j*(-5) -364 + j*(26) -289 + j*(-235) --78 + j*(269) --317 + j*(-59) --365 + j*(-119) --433 + j*(439) -524 + j*(208) --506 + j*(479) -144 + j*(-102) -218 + j*(486) -166 + j*(308) -340 + j*(-202) -195 + j*(376) --243 + j*(18) -666 + j*(-218) --438 + j*(-264) --342 + j*(328) --4 + j*(-325) -266 + j*(344) --282 + j*(80) --177 + j*(581) --470 + j*(-49) -173 + j*(-510) --232 + j*(204) -192 + j*(-291) --95 + j*(-459) --422 + j*(420) --381 + j*(442) --5 + j*(-301) -23 + j*(-64) --246 + j*(-320) -86 + j*(22) -227 + j*(153) -523 + j*(-78) --17 + j*(234) -152 + j*(221) -361 + j*(127) -477 + j*(-136) --260 + j*(-223) --452 + j*(-424) --38 + j*(316) -7 + j*(41) -314 + j*(-93) --199 + j*(-49) -373 + j*(27) -138 + j*(-133) -670 + j*(440) -279 + j*(-281) -651 + j*(-272) --327 + j*(352) --197 + j*(-193) -50 + j*(-195) --464 + j*(169) -91 + j*(299) --268 + j*(-354) --175 + j*(243) -209 + j*(-299) -246 + j*(-74) --211 + j*(32) --590 + j*(-237) --349 + j*(-13) -493 + j*(91) -163 + j*(-473) --229 + j*(-415) -341 + j*(-74) --523 + j*(-462) -233 + j*(354) -476 + j*(-384) --311 + j*(429) --110 + j*(129) -316 + j*(-384) --472 + j*(187) -276 + j*(-151) --118 + j*(-93) -290 + j*(212) -427 + j*(168) --263 + j*(495) -173 + j*(170) --376 + j*(113) --264 + j*(252) --285 + j*(-351) -477 + j*(-281) --305 + j*(39) --271 + j*(75) --76 + j*(113) --59 + j*(45) -64 + j*(-188) -131 + j*(244) -23 + j*(242) -6 + j*(-276) -34 + j*(-119) --132 + j*(123) -158 + j*(-139) --154 + j*(-136) --228 + j*(-295) --5 + j*(-81) --198 + j*(-13) --163 + j*(-329) -123 + j*(-270) --20 + j*(-197) --28 + j*(-51) -145 + j*(-162) -157 + j*(24) --126 + j*(54) -371 + j*(-254) --260 + j*(-204) --182 + j*(-146) -156 + j*(264) -168 + j*(-101) -11 + j*(-81) --284 + j*(-288) --79 + j*(-81) -76 + j*(137) --160 + j*(-287) -165 + j*(-95) -83 + j*(7) -83 + j*(-138) --11 + j*(134) --58 + j*(281) -11 + j*(-214) --231 + j*(-128) -124 + j*(-11) --13 + j*(-123) --122 + j*(154) -286 + j*(-387) --153 + j*(59) --168 + j*(-157) --93 + j*(204) -143 + j*(237) -164 + j*(47) --13 + j*(170) --236 + j*(-96) -57 + j*(395) -71 + j*(-207) --18 + j*(-145) --165 + j*(-25) --185 + j*(-54) -144 + j*(6) --3 + j*(202) --39 + j*(137) -75 + j*(64) -65 + j*(-144) -57 + j*(-88) -130 + j*(-175) -86 + j*(268) --220 + j*(99) --303 + j*(-27) --86 + j*(-230) -0 + j*(-168) --86 + j*(-19) --112 + j*(-159) --46 + j*(-31) --248 + j*(334) -47 + j*(23) -109 + j*(130) --86 + j*(-11) -48 + j*(-79) --115 + j*(35) --107 + j*(139) --181 + j*(244) -33 + j*(-192) -72 + j*(235) -13 + j*(-37) --188 + j*(-218) --122 + j*(139) -83 + j*(211) -11 + j*(-64) --1 + j*(80) -6 + j*(296) --327 + j*(32) -51 + j*(-163) -5 + j*(-147) -89 + j*(-125) -72 + j*(-122) -163 + j*(119) -45 + j*(-27) --14 + j*(194) -67 + j*(35) --115 + j*(138) --69 + j*(352) --124 + j*(264) -358 + j*(-136) -16 + j*(-250) --62 + j*(148) --21 + j*(-112) -100 + j*(-281) --192 + j*(256) --50 + j*(113) -83 + j*(-140) --53 + j*(-184) -26 + j*(226) --146 + j*(-12) -59 + j*(323) -92 + j*(-313) -74 + j*(182) --87 + j*(371) --54 + j*(388) -102 + j*(-137) --317 + j*(235) -113 + j*(-13) --125 + j*(-184) --296 + j*(-134) --24 + j*(-75) -211 + j*(-616) --286 + j*(-27) -153 + j*(129) --287 + j*(221) -139 + j*(-23) -211 + j*(-58) -34 + j*(-3) -68 + j*(58) --232 + j*(52) --57 + j*(-89) -30 + j*(-63) -412 + j*(81) -44 + j*(65) --155 + j*(248) --379 + j*(57) -226 + j*(-62) -40 + j*(-147) -50 + j*(-100) -223 + j*(-29) --38 + j*(-45) --107 + j*(103) --33 + j*(-237) --35 + j*(5) -49 + j*(-75) -230 + j*(-153) -36 + j*(-48) --76 + j*(64) -17 + j*(-260) --31 + j*(134) --52 + j*(-53) --49 + j*(-129) --400 + j*(531) -103 + j*(29) --274 + j*(317) --204 + j*(297) -33 + j*(2) --34 + j*(27) --18 + j*(-21) -118 + j*(49) --165 + j*(-112) -20 + j*(48) -112 + j*(-151) --61 + j*(-64) --165 + j*(-1) --86 + j*(205) --132 + j*(-49) -227 + j*(115) --112 + j*(-151) --229 + j*(208) --18 + j*(288) --11 + j*(-17) --87 + j*(-221) -59 + j*(-103) -178 + j*(34) --68 + j*(78) --331 + j*(236) --50 + j*(202) --406 + j*(300) -168 + j*(360) -66 + j*(135) -210 + j*(-129) -261 + j*(-44) --182 + j*(100) --231 + j*(-123) --11 + j*(49) --225 + j*(-245) -299 + j*(-52) -57 + j*(-13) --121 + j*(342) --224 + j*(191) -13 + j*(-150) --9 + j*(-26) -146 + j*(-146) -192 + j*(-49) --19 + j*(-104) -92 + j*(-254) -214 + j*(-313) --219 + j*(19) --65 + j*(-359) --255 + j*(-38) -65 + j*(177) --96 + j*(-128) --78 + j*(6) -16 + j*(-17) --260 + j*(-66) --95 + j*(-110) -193 + j*(87) -77 + j*(-107) --19 + j*(-52) --70 + j*(-187) -547 + j*(262) --59 + j*(-39) -126 + j*(46) --47 + j*(-180) -18 + j*(-137) -18 + j*(-50) -110 + j*(354) -273 + j*(18) --44 + j*(-349) -97 + j*(-141) -112 + j*(173) -42 + j*(204) --33 + j*(-132) -157 + j*(-131) -62 + j*(-146) -84 + j*(-30) --169 + j*(163) -90 + j*(-85) --211 + j*(215) --147 + j*(-100) --325 + j*(17) -11 + j*(132) --309 + j*(99) --291 + j*(-136) -183 + j*(32) -25 + j*(-317) --243 + j*(-312) -115 + j*(129) --78 + j*(79) -249 + j*(-482) -160 + j*(-260) --12 + j*(130) --395 + j*(1) -330 + j*(-161) -21 + j*(9) --133 + j*(-103) -361 + j*(-362) -222 + j*(204) --265 + j*(88) --35 + j*(197) --187 + j*(123) --22 + j*(101) --37 + j*(12) --42 + j*(-145) -112 + j*(-66) --208 + j*(-199) --221 + j*(181) -2 + j*(-8) --106 + j*(-108) -238 + j*(28) -113 + j*(-265) --43 + j*(-2) --194 + j*(151) -485 + j*(0) --87 + j*(-110) --52 + j*(-28) --11 + j*(144) -63 + j*(-206) -75 + j*(292) --385 + j*(157) --62 + j*(223) --265 + j*(-31) -153 + j*(-35) --298 + j*(-184) -78 + j*(26) --50 + j*(192) -42 + j*(150) -27 + j*(-25) -310 + j*(175) -48 + j*(-118) -100 + j*(55) -120 + j*(175) -327 + j*(-191) -65 + j*(-161) --13 + j*(94) -60 + j*(62) --109 + j*(-181) --36 + j*(-14) --128 + j*(-132) --124 + j*(-5) -88 + j*(-116) -233 + j*(-172) -124 + j*(-318) -93 + j*(-222) --46 + j*(-119) -25 + j*(115) --62 + j*(-232) -182 + j*(-144) -115 + j*(-137) -209 + j*(-123) --194 + j*(156) -141 + j*(-25) -54 + j*(-33) -228 + j*(151) -161 + j*(-208) --235 + j*(-128) -77 + j*(433) --103 + j*(186) --173 + j*(105) --28 + j*(-249) -199 + j*(255) --308 + j*(-40) -72 + j*(-93) --238 + j*(-285) -549 + j*(58) --267 + j*(-106) --11 + j*(-100) -95 + j*(41) -112 + j*(185) -17 + j*(-157) --20 + j*(163) --278 + j*(8) --92 + j*(-59) --197 + j*(37) --441 + j*(-72) --11 + j*(68) -4 + j*(-237) -166 + j*(-2) -15 + j*(-119) --309 + j*(-29) --144 + j*(-14) --230 + j*(-114) --5 + j*(151) --181 + j*(-371) -18 + j*(-228) -163 + j*(-178) -13 + j*(248) --243 + j*(-315) --116 + j*(101) -146 + j*(206) -88 + j*(60) -111 + j*(-144) -0 + j*(281) -10 + j*(-163) --59 + j*(127) -517 + j*(11) -73 + j*(35) -172 + j*(12) -47 + j*(4) --83 + j*(-124) -53 + j*(50) --148 + j*(-124) --141 + j*(238) --54 + j*(41) --139 + j*(-158) --196 + j*(374) --301 + j*(265) --39 + j*(2) -97 + j*(-139) --106 + j*(133) --305 + j*(62) -114 + j*(90) --55 + j*(-114) --122 + j*(-102) -8 + j*(-168) --252 + j*(-70) --70 + j*(42) --141 + j*(-4) --69 + j*(226) -56 + j*(244) -49 + j*(2) --57 + j*(57) --194 + j*(122) --329 + j*(-75) -167 + j*(-91) --197 + j*(279) -117 + j*(-48) -30 + j*(-26) --132 + j*(159) -332 + j*(76) -36 + j*(230) --37 + j*(-238) --40 + j*(-260) -151 + j*(91) --77 + j*(60) -98 + j*(27) -251 + j*(-101) --18 + j*(120) --93 + j*(-235) --76 + j*(8) -404 + j*(191) --8 + j*(-64) -30 + j*(58) --175 + j*(281) --102 + j*(-7) --254 + j*(144) --15 + j*(13) -393 + j*(-165) --185 + j*(-293) --86 + j*(59) --87 + j*(-224) --60 + j*(-87) -177 + j*(-240) -455 + j*(64) -78 + j*(-25) -41 + j*(-100) --71 + j*(-47) -8 + j*(138) -18 + j*(-21) --141 + j*(195) -127 + j*(185) --158 + j*(-86) --62 + j*(5) -206 + j*(103) -156 + j*(-23) -46 + j*(0) -83 + j*(119) --12 + j*(-33) --260 + j*(-20) --59 + j*(-342) -159 + j*(52) -112 + j*(228) -137 + j*(212) --153 + j*(-200) --134 + j*(-71) -262 + j*(312) --369 + j*(-21) -129 + j*(-147) --73 + j*(-161) --117 + j*(110) -110 + j*(113) --8 + j*(49) -52 + j*(296) --158 + j*(-57) --72 + j*(94) --134 + j*(-95) -41 + j*(-303) -177 + j*(-135) --338 + j*(182) --182 + j*(33) --183 + j*(97) -144 + j*(-33) --47 + j*(-262) -139 + j*(95) --286 + j*(88) -318 + j*(-64) -119 + j*(252) --46 + j*(-5) -372 + j*(201) --144 + j*(103) --52 + j*(165) -59 + j*(214) -232 + j*(-100) --237 + j*(85) --396 + j*(-92) --230 + j*(126) --81 + j*(-54) -205 + j*(71) --80 + j*(-67) -322 + j*(-10) --101 + j*(-81) --22 + j*(110) -280 + j*(-179) -26 + j*(-250) -49 + j*(143) --253 + j*(16) --140 + j*(70) -238 + j*(177) -165 + j*(27) --12 + j*(233) -281 + j*(147) -49 + j*(-413) -190 + j*(-138) --115 + j*(280) -184 + j*(-147) -174 + j*(4) --112 + j*(56) --163 + j*(-38) --260 + j*(201) -257 + j*(-362) -344 + j*(141) --185 + j*(-252) -257 + j*(135) --119 + j*(-91) --13 + j*(-37) -133 + j*(21) -72 + j*(58) -71 + j*(368) -276 + j*(279) --87 + j*(293) -46 + j*(-38) --127 + j*(-140) --55 + j*(40) -180 + j*(-16) --54 + j*(267) -59 + j*(213) -24 + j*(-54) --160 + j*(-71) --115 + j*(-206) -0 + j*(-27) -30 + j*(63) -175 + j*(48) -250 + j*(107) -141 + j*(-119) --46 + j*(-228) -141 + j*(55) --11 + j*(-161) -71 + j*(-49) -132 + j*(-453) --171 + j*(134) --240 + j*(-64) --238 + j*(-89) -215 + j*(143) -95 + j*(-177) --115 + j*(12) --98 + j*(-80) -168 + j*(-66) -83 + j*(33) --310 + j*(256) -108 + j*(-310) -206 + j*(83) -103 + j*(61) --42 + j*(-98) -117 + j*(-24) -12 + j*(66) --107 + j*(-325) --97 + j*(-29) -279 + j*(-264) --112 + j*(-161) --330 + j*(88) --315 + j*(-161) --74 + j*(-153) -102 + j*(235) --49 + j*(358) -298 + j*(-292) -170 + j*(292) -139 + j*(254) --199 + j*(-175) -238 + j*(181) --100 + j*(77) --125 + j*(382) -69 + j*(40) --155 + j*(-226) --220 + j*(-99) --39 + j*(-467) --185 + j*(-52) --100 + j*(-15) --55 + j*(84) -80 + j*(278) -52 + j*(-245) --37 + j*(-181) -194 + j*(358) -180 + j*(25) -215 + j*(-21) --254 + j*(128) -208 + j*(43) -148 + j*(-43) -80 + j*(168) -168 + j*(-79) --107 + j*(-41) -98 + j*(250) --51 + j*(-281) -81 + j*(-32) --45 + j*(-207) -95 + j*(31) -29 + j*(60) --104 + j*(-112) -16 + j*(175) -64 + j*(-142) --16 + j*(-264) -90 + j*(-200) -106 + j*(-193) --76 + j*(-26) --81 + j*(226) -4 + j*(-62) --105 + j*(-92) --64 + j*(-13) --118 + j*(-20) --76 + j*(-79) -153 + j*(52) --29 + j*(216) --237 + j*(305) --57 + j*(43) -251 + j*(-64) -65 + j*(-22) --66 + j*(-105) --46 + j*(30) --124 + j*(-200) -186 + j*(108) --303 + j*(98) -127 + j*(-165) -35 + j*(-56) --58 + j*(30) -150 + j*(155) --151 + j*(-247) --194 + j*(-41) --150 + j*(6) --230 + j*(92) --91 + j*(37) -219 + j*(-158) --185 + j*(44) -97 + j*(-40) --209 + j*(43) --160 + j*(44) -111 + j*(-115) --206 + j*(2) --380 + j*(-145) --291 + j*(185) --16 + j*(211) -65 + j*(73) --13 + j*(137) -14 + j*(68) -19 + j*(24) --10 + j*(235) -21 + j*(-56) -36 + j*(-182) --54 + j*(25) -209 + j*(-83) --146 + j*(305) -138 + j*(-47) --152 + j*(-73) -218 + j*(23) -56 + j*(-35) -267 + j*(17) -214 + j*(-84) --240 + j*(309) -98 + j*(45) -211 + j*(-54) -133 + j*(-213) -1 + j*(87) --165 + j*(78) --58 + j*(-218) -10 + j*(-103) --237 + j*(82) --180 + j*(17) --169 + j*(-69) --100 + j*(-223) -339 + j*(34) -288 + j*(-133) --148 + j*(-80) -124 + j*(-6) -278 + j*(115) -88 + j*(39) --99 + j*(-206) -54 + j*(198) --30 + j*(92) --75 + j*(-107) -237 + j*(185) --15 + j*(-160) -141 + j*(182) -129 + j*(169) -72 + j*(9) --214 + j*(236) -133 + j*(21) --25 + j*(74) --122 + j*(-70) --260 + j*(163) --24 + j*(-200) --235 + j*(45) -185 + j*(207) --279 + j*(54) --241 + j*(-18) --153 + j*(-87) --255 + j*(40) --113 + j*(-238) -369 + j*(24) -218 + j*(57) -205 + j*(637) -19 + j*(61) -66 + j*(25) --217 + j*(-431) -62 + j*(208) -269 + j*(-142) -16 + j*(122) -56 + j*(-24) --279 + j*(-170) --141 + j*(233) -339 + j*(-234) --99 + j*(-257) --145 + j*(263) -57 + j*(-175) -36 + j*(250) --94 + j*(-114) --196 + j*(13) -57 + j*(242) -18 + j*(216) --37 + j*(291) -264 + j*(-162) --219 + j*(178) -349 + j*(211) -204 + j*(-43) -21 + j*(93) -21 + j*(-221) -41 + j*(-16) --98 + j*(-230) --264 + j*(-47) -126 + j*(-108) -268 + j*(-69) -41 + j*(65) -76 + j*(301) --84 + j*(-194) --156 + j*(-68) --6 + j*(-103) --9 + j*(-292) --274 + j*(-38) --128 + j*(-166) -57 + j*(127) --155 + j*(-173) --35 + j*(-301) --120 + j*(390) --71 + j*(-32) --16 + j*(-83) --28 + j*(-132) -146 + j*(-89) --233 + j*(134) --136 + j*(-153) --62 + j*(-111) -0 + j*(-173) -240 + j*(314) --331 + j*(-113) -215 + j*(99) --129 + j*(92) -81 + j*(183) -103 + j*(-28) --305 + j*(25) -64 + j*(165) -31 + j*(-141) -503 + j*(144) --18 + j*(-52) --139 + j*(9) --247 + j*(102) --14 + j*(-35) -139 + j*(-177) --218 + j*(1) --123 + j*(-48) --13 + j*(152) -164 + j*(342) --188 + j*(-28) -102 + j*(-18) --275 + j*(-183) --140 + j*(105) --89 + j*(-166) -150 + j*(-127) -153 + j*(202) --160 + j*(98) --30 + j*(-16) -136 + j*(36) -164 + j*(165) --61 + j*(-130) -232 + j*(-411) --65 + j*(129) -184 + j*(-213) --237 + j*(134) --322 + j*(240) --18 + j*(45) -52 + j*(-71) -202 + j*(-8) --103 + j*(-185) --91 + j*(56) --245 + j*(-260) --168 + j*(260) --35 + j*(30) -57 + j*(-226) -57 + j*(49) -199 + j*(-151) -43 + j*(28) --358 + j*(64) --94 + j*(-109) -270 + j*(-82) -132 + j*(7) -206 + j*(10) -506 + j*(-12) --49 + j*(-83) --315 + j*(-318) --15 + j*(277) --157 + j*(-344) -379 + j*(221) -377 + j*(59) -308 + j*(-408) --211 + j*(228) -16 + j*(-142) --260 + j*(-234) --285 + j*(-187) -272 + j*(170) --99 + j*(209) --125 + j*(86) --326 + j*(-369) --164 + j*(-24) --109 + j*(388) --103 + j*(-238) --169 + j*(-40) -10 + j*(-123) -190 + j*(-354) --339 + j*(141) -176 + j*(-11) --105 + j*(4) --83 + j*(-327) --14 + j*(-84) -86 + j*(65) -206 + j*(100) -279 + j*(-349) --328 + j*(191) -21 + j*(-1) -77 + j*(174) -49 + j*(-45) -32 + j*(-206) --141 + j*(75) --64 + j*(33) -174 + j*(88) -328 + j*(-105) -222 + j*(400) --209 + j*(493) --165 + j*(-93) --6 + j*(126) -30 + j*(-97) --117 + j*(-136) --81 + j*(-33) -12 + j*(2) -261 + j*(93) -11 + j*(-62) -10 + j*(98) --125 + j*(-16) -141 + j*(226) -182 + j*(-117) -94 + j*(283) --136 + j*(-20) -455 + j*(-54) --87 + j*(75) --151 + j*(226) --253 + j*(54) --8 + j*(-204) --62 + j*(-136) --182 + j*(148) --16 + j*(74) --17 + j*(-224) --67 + j*(-27) -138 + j*(30) -81 + j*(71) --7 + j*(-83) -127 + j*(98) -22 + j*(-260) -312 + j*(-258) --189 + j*(31) -159 + j*(158) -240 + j*(-91) --32 + j*(-305) -78 + j*(26) -48 + j*(242) --66 + j*(117) -176 + j*(-287) --78 + j*(0) -300 + j*(119) -128 + j*(-288) -22 + j*(161) -373 + j*(192) -272 + j*(70) --50 + j*(84) -3 + j*(54) -26 + j*(86) -49 + j*(182) -46 + j*(-55) --124 + j*(188) --196 + j*(277) -37 + j*(26) --77 + j*(-10) -130 + j*(-244) --35 + j*(421) -9 + j*(219) -177 + j*(49) -48 + j*(-383) --43 + j*(141) --102 + j*(76) -132 + j*(47) --154 + j*(56) --26 + j*(-116) --93 + j*(30) --99 + j*(-182) --301 + j*(-375) -47 + j*(-53) -196 + j*(-124) --271 + j*(-64) --61 + j*(-177) --325 + j*(-323) -8 + j*(147) -32 + j*(67) --158 + j*(-103) -97 + j*(-142) -193 + j*(-113) -168 + j*(-134) -12 + j*(122) --45 + j*(172) -153 + j*(59) -271 + j*(-115) -296 + j*(-90) --117 + j*(-60) --380 + j*(-109) --173 + j*(-264) -25 + j*(-51) -484 + j*(32) --175 + j*(52) --358 + j*(212) -81 + j*(-68) -10 + j*(128) --103 + j*(-35) -44 + j*(351) -202 + j*(36) --97 + j*(279) -87 + j*(103) --70 + j*(27) -133 + j*(235) -109 + j*(199) -146 + j*(88) --90 + j*(-188) --433 + j*(-84) --101 + j*(-179) -202 + j*(-115) -209 + j*(-90) -28 + j*(103) --146 + j*(168) -128 + j*(134) -273 + j*(158) --272 + j*(169) --179 + j*(-197) --387 + j*(-228) --86 + j*(-306) -161 + j*(-260) --61 + j*(-40) --128 + j*(-26) --1 + j*(188) -133 + j*(-36) --50 + j*(41) --20 + j*(-163) -163 + j*(68) -134 + j*(183) --278 + j*(-277) -168 + j*(294) --473 + j*(-18) -25 + j*(364) -61 + j*(-151) -83 + j*(59) -45 + j*(-225) -76 + j*(105) -162 + j*(-346) -101 + j*(94) --37 + j*(-292) --23 + j*(-143) -170 + j*(49) --14 + j*(-16) -22 + j*(71) --111 + j*(-79) -188 + j*(-58) --122 + j*(-239) -252 + j*(161) --45 + j*(-11) -25 + j*(-204) -279 + j*(-64) --137 + j*(-185) --114 + j*(23) -133 + j*(185) -188 + j*(212) --41 + j*(51) -141 + j*(-110) --96 + j*(-378) -58 + j*(-146) -152 + j*(-47) -35 + j*(30) -144 + j*(-59) --202 + j*(64) --265 + j*(-29) -69 + j*(-327) --15 + j*(54) -13 + j*(-119) --33 + j*(273) --203 + j*(81) --108 + j*(275) --109 + j*(119) --165 + j*(-93) --108 + j*(309) --100 + j*(-303) -269 + j*(-175) --293 + j*(95) --129 + j*(183) -187 + j*(-76) -317 + j*(-244) -131 + j*(30) --293 + j*(-280) --96 + j*(170) -11 + j*(219) --88 + j*(-159) --386 + j*(-183) --385 + j*(141) -13 + j*(252) --184 + j*(-351) -473 + j*(213) -6 + j*(-129) -13 + j*(216) -66 + j*(1) -257 + j*(-221) -332 + j*(164) --60 + j*(74) --113 + j*(-6) --59 + j*(264) --11 + j*(37) --74 + j*(263) -80 + j*(-193) --12 + j*(-102) -74 + j*(-3) --25 + j*(-152) -358 + j*(121) -134 + j*(69) --374 + j*(77) -323 + j*(-186) -47 + j*(72) --14 + j*(-469) --23 + j*(-97) --92 + j*(264) -100 + j*(-27) -158 + j*(-268) -32 + j*(55) -291 + j*(-216) --260 + j*(194) -97 + j*(159) --21 + j*(-142) --152 + j*(-19) --64 + j*(358) -162 + j*(18) --225 + j*(90) --127 + j*(234) -64 + j*(43) -141 + j*(45) --250 + j*(9) -52 + j*(-197) -202 + j*(114) --103 + j*(90) -306 + j*(-103) -385 + j*(21) --66 + j*(-288) --187 + j*(-74) --9 + j*(-46) -420 + j*(146) --13 + j*(166) --168 + j*(81) --267 + j*(-56) -98 + j*(-157) --362 + j*(155) -339 + j*(76) -190 + j*(25) --40 + j*(324) --40 + j*(135) --176 + j*(-10) --62 + j*(-112) -42 + j*(201) --52 + j*(-45) -290 + j*(-97) -190 + j*(98) -134 + j*(-165) --162 + j*(-31) --290 + j*(92) --80 + j*(-121) --72 + j*(217) --151 + j*(-44) -42 + j*(140) -185 + j*(-230) -144 + j*(9) -188 + j*(107) --9 + j*(174) -32 + j*(-89) -387 + j*(107) -185 + j*(232) --91 + j*(40) --83 + j*(137) -114 + j*(14) -180 + j*(12) --35 + j*(318) --139 + j*(-17) --3 + j*(-109) -163 + j*(-286) --211 + j*(-83) -29 + j*(21) -401 + j*(-445) --81 + j*(-83) --98 + j*(-218) --121 + j*(-2) -115 + j*(17) -78 + j*(-435) -98 + j*(40) -304 + j*(139) -53 + j*(166) -185 + j*(130) --115 + j*(-383) --170 + j*(-74) --49 + j*(-89) -7 + j*(77) -229 + j*(-230) -91 + j*(-82) -19 + j*(60) --278 + j*(-250) --127 + j*(25) -229 + j*(-180) --57 + j*(36) --25 + j*(163) -84 + j*(-128) -59 + j*(88) --171 + j*(-7) -114 + j*(255) -35 + j*(109) --44 + j*(409) --210 + j*(-250) --69 + j*(66) --121 + j*(48) -125 + j*(-195) -107 + j*(55) --1 + j*(-103) -264 + j*(24) -35 + j*(-345) --250 + j*(-409) -195 + j*(6) --60 + j*(-27) --64 + j*(147) --33 + j*(92) --25 + j*(-93) --228 + j*(-18) --37 + j*(-191) -78 + j*(-4) --69 + j*(-494) --152 + j*(261) --6 + j*(146) --361 + j*(-142) --65 + j*(176) -244 + j*(78) --58 + j*(-261) --58 + j*(-259) --66 + j*(-286) --186 + j*(181) --257 + j*(-41) -194 + j*(354) -47 + j*(93) --121 + j*(31) -136 + j*(-87) -10 + j*(190) --272 + j*(-148) --107 + j*(-56) -115 + j*(-47) --53 + j*(-172) -45 + j*(-48) -347 + j*(-141) -66 + j*(-78) --156 + j*(122) -50 + j*(-180) -217 + j*(-42) --210 + j*(-83) -228 + j*(189) -583 + j*(-493) -196 + j*(153) -40 + j*(-85) -105 + j*(8) --49 + j*(-282) -164 + j*(-246) --35 + j*(-301) -129 + j*(252) --268 + j*(125) --144 + j*(116) --309 + j*(112) -40 + j*(-140) -42 + j*(-145) -39 + j*(161) --340 + j*(243) --55 + j*(-122) -167 + j*(135) --185 + j*(122) -66 + j*(-51) -200 + j*(46) -67 + j*(-173) --50 + j*(126) -536 + j*(-277) -66 + j*(-58) --182 + j*(208) --59 + j*(-201) -253 + j*(46) --20 + j*(-202) -66 + j*(269) -395 + j*(128) --171 + j*(263) --45 + j*(-102) --135 + j*(13) --194 + j*(109) --115 + j*(313) -21 + j*(310) --22 + j*(-176) --59 + j*(-142) -274 + j*(33) -50 + j*(-194) --39 + j*(210) --163 + j*(-13) --247 + j*(316) -163 + j*(-173) -54 + j*(-386) -49 + j*(293) --6 + j*(286) --254 + j*(-59) --308 + j*(-129) -141 + j*(-104) --262 + j*(-76) --92 + j*(346) -318 + j*(-88) -134 + j*(248) --27 + j*(-118) -119 + j*(145) --185 + j*(-234) --141 + j*(-91) --95 + j*(-129) -151 + j*(-233) --91 + j*(-215) --105 + j*(-1) --32 + j*(-80) -133 + j*(-57) --52 + j*(-29) --103 + j*(-84) --65 + j*(-89) --83 + j*(38) --42 + j*(-209) --243 + j*(-137) --74 + j*(-73) --167 + j*(33) --197 + j*(-66) -12 + j*(-21) -88 + j*(-200) -129 + j*(108) -335 + j*(71) -54 + j*(-274) --129 + j*(-361) -338 + j*(-28) -35 + j*(-118) --44 + j*(-242) --66 + j*(-45) --290 + j*(-136) --23 + j*(180) -176 + j*(86) -63 + j*(-119) -68 + j*(-148) --366 + j*(-110) -138 + j*(86) --22 + j*(80) -72 + j*(28) --49 + j*(-218) -64 + j*(14) -364 + j*(-48) -221 + j*(-61) -212 + j*(175) --34 + j*(199) --25 + j*(135) -239 + j*(-129) --253 + j*(-223) -103 + j*(148) -100 + j*(199) -331 + j*(103) -256 + j*(-104) -194 + j*(78) -170 + j*(-54) --51 + j*(83) --112 + j*(288) -298 + j*(88) --196 + j*(-251) --5 + j*(33) -104 + j*(-231) --233 + j*(-22) -115 + j*(-112) -15 + j*(7) -147 + j*(-501) -223 + j*(60) --243 + j*(-366) --35 + j*(100) --64 + j*(-82) --236 + j*(-47) -137 + j*(-5) -31 + j*(-117) -401 + j*(436) --192 + j*(-45) -78 + j*(-392) --258 + j*(263) --303 + j*(-162) -119 + j*(169) -211 + j*(58) --53 + j*(117) --28 + j*(-269) -107 + j*(-180) -107 + j*(-92) --80 + j*(22) -356 + j*(127) --168 + j*(91) --199 + j*(-310) --117 + j*(-108) --193 + j*(-369) -60 + j*(156) -62 + j*(77) --21 + j*(-73) --219 + j*(-141) --418 + j*(11) --44 + j*(-158) -297 + j*(-14) -183 + j*(285) --77 + j*(-115) --92 + j*(-203) -302 + j*(-100) -234 + j*(-197) -275 + j*(88) -57 + j*(-214) -52 + j*(-255) -164 + j*(214) -119 + j*(-187) -117 + j*(86) --3 + j*(340) -95 + j*(-66) -32 + j*(-25) --200 + j*(105) --76 + j*(126) -91 + j*(37) --245 + j*(-36) --120 + j*(77) -120 + j*(-119) --99 + j*(-166) --4 + j*(137) -41 + j*(151) --182 + j*(35) --151 + j*(-89) --63 + j*(-212) -269 + j*(164) -284 + j*(163) -123 + j*(87) --55 + j*(-116) -68 + j*(-134) --62 + j*(-74) -57 + j*(100) -204 + j*(159) -255 + j*(182) -40 + j*(-157) --81 + j*(118) --11 + j*(-113) -168 + j*(-326) -158 + j*(8) --139 + j*(-2) -103 + j*(-64) -54 + j*(606) -202 + j*(32) --240 + j*(-212) --236 + j*(-55) -25 + j*(-208) -124 + j*(-163) -127 + j*(-118) --194 + j*(50) -23 + j*(106) -178 + j*(-280) -92 + j*(-33) --42 + j*(126) -208 + j*(159) --103 + j*(-33) -247 + j*(70) --337 + j*(253) --83 + j*(-166) --199 + j*(12) --92 + j*(542) -178 + j*(-195) --115 + j*(-338) -146 + j*(82) --163 + j*(-86) --88 + j*(-90) -19 + j*(-390) --59 + j*(-48) -81 + j*(165) -103 + j*(-173) -47 + j*(-240) --453 + j*(-52) --102 + j*(234) --272 + j*(161) -81 + j*(-75) --143 + j*(-223) --126 + j*(-250) -134 + j*(-209) -45 + j*(-143) --290 + j*(-23) --88 + j*(14) -382 + j*(-177) --407 + j*(-16) --9 + j*(-69) -401 + j*(-166) -127 + j*(-6) -149 + j*(-99) --124 + j*(-21) -17 + j*(-229) --5 + j*(23) --173 + j*(34) -34 + j*(59) -204 + j*(-1) -48 + j*(253) -247 + j*(154) --158 + j*(172) --81 + j*(340) --23 + j*(-86) --18 + j*(26) -6 + j*(-112) --252 + j*(-152) -186 + j*(148) --199 + j*(76) -330 + j*(6) -13 + j*(-215) --279 + j*(-163) -52 + j*(-40) --167 + j*(-231) --236 + j*(129) -78 + j*(-25) -147 + j*(-44) -119 + j*(125) --149 + j*(-324) -1 + j*(-77) --201 + j*(-49) -250 + j*(-146) -15 + j*(-36) -56 + j*(-78) --35 + j*(-8) --110 + j*(14) -170 + j*(-251) --460 + j*(-7) --32 + j*(-224) --18 + j*(86) --17 + j*(-165) -417 + j*(-276) --87 + j*(72) --205 + j*(-112) -0 + j*(-154) --8 + j*(-245) -147 + j*(27) -89 + j*(-115) --16 + j*(-88) --187 + j*(-146) --93 + j*(8) --11 + j*(181) --159 + j*(4) --132 + j*(92) --23 + j*(-123) -223 + j*(69) --5 + j*(249) --127 + j*(291) -95 + j*(4) -59 + j*(228) -75 + j*(-275) --171 + j*(11) --136 + j*(-105) --198 + j*(204) --57 + j*(5) -3 + j*(-324) --538 + j*(-66) -74 + j*(-358) -467 + j*(20) --421 + j*(-13) -46 + j*(-384) --553 + j*(-285) -178 + j*(18) --197 + j*(97) -333 + j*(-331) --301 + j*(-172) -50 + j*(-204) -291 + j*(331) --132 + j*(-193) --199 + j*(382) --44 + j*(-281) -33 + j*(177) -18 + j*(624) -291 + j*(-469) --192 + j*(71) --414 + j*(254) --331 + j*(-499) -281 + j*(-560) --112 + j*(-367) --390 + j*(-414) -274 + j*(-482) -373 + j*(-433) -320 + j*(128) -250 + j*(-570) --4 + j*(364) -345 + j*(329) --415 + j*(450) -384 + j*(-269) --269 + j*(337) --714 + j*(-90) --144 + j*(-327) -92 + j*(-220) --202 + j*(-617) -368 + j*(187) --391 + j*(445) --446 + j*(485) -606 + j*(-561) --156 + j*(266) -346 + j*(262) -44 + j*(288) -6 + j*(132) -199 + j*(107) -517 + j*(165) -59 + j*(218) -371 + j*(-624) -278 + j*(0) --479 + j*(-395) -390 + j*(-21) -233 + j*(52) --342 + j*(371) --434 + j*(473) --187 + j*(-260) --327 + j*(412) --393 + j*(179) --523 + j*(-187) --343 + j*(-66) -295 + j*(193) -132 + j*(-379) -298 + j*(-465) --434 + j*(26) --532 + j*(284) --207 + j*(-152) --286 + j*(412) --233 + j*(-143) -49 + j*(185) -11 + j*(10) --176 + j*(527) -395 + j*(203) --45 + j*(356) -264 + j*(-517) -189 + j*(-214) -325 + j*(-169) --23 + j*(114) --362 + j*(190) --424 + j*(-215) -442 + j*(496) --311 + j*(-489) -347 + j*(19) --66 + j*(-206) --299 + j*(-675) --133 + j*(-135) -369 + j*(312) --94 + j*(467) -222 + j*(-23) -177 + j*(240) --163 + j*(-114) -278 + j*(-13) -168 + j*(523) --314 + j*(127) --484 + j*(119) -298 + j*(522) --288 + j*(-101) --369 + j*(448) -62 + j*(138) -74 + j*(176) --442 + j*(-165) -25 + j*(-23) -540 + j*(622) -92 + j*(82) --477 + j*(187) -134 + j*(-74) -308 + j*(176) -213 + j*(-274) --223 + j*(-270) --400 + j*(393) -544 + j*(-454) -337 + j*(-287) --313 + j*(466) -304 + j*(397) -118 + j*(-298) --496 + j*(358) -58 + j*(-314) --18 + j*(56) --37 + j*(-183) -85 + j*(-219) -470 + j*(-586) --557 + j*(-581) -425 + j*(194) --148 + j*(-387) -111 + j*(66) -433 + j*(412) -330 + j*(-301) -284 + j*(-236) --71 + j*(156) -243 + j*(-194) -323 + j*(692) -49 + j*(547) --98 + j*(232) --141 + j*(-212) -57 + j*(250) -313 + j*(-370) --641 + j*(-368) --259 + j*(-291) --16 + j*(-18) --689 + j*(241) --308 + j*(-279) -392 + j*(-391) -271 + j*(-156) -40 + j*(334) -84 + j*(-208) --247 + j*(123) -122 + j*(-320) -293 + j*(-576) --299 + j*(446) --459 + j*(-285) --474 + j*(-351) -119 + j*(129) --264 + j*(110) --203 + j*(411) -245 + j*(52) -215 + j*(-194) --147 + j*(333) --242 + j*(-580) -255 + j*(140) -107 + j*(-214) -223 + j*(139) --246 + j*(-601) -219 + j*(-79) -232 + j*(-344) -250 + j*(-248) -76 + j*(64) -380 + j*(-157) -125 + j*(325) --306 + j*(257) -317 + j*(199) --364 + j*(435) --135 + j*(-126) -47 + j*(-95) --303 + j*(-332) --411 + j*(416) --205 + j*(-384) -341 + j*(-59) --47 + j*(-214) --64 + j*(-122) -284 + j*(352) --300 + j*(270) -419 + j*(175) -201 + j*(-445) -269 + j*(409) -381 + j*(225) -262 + j*(487) --52 + j*(-374) -33 + j*(-332) --221 + j*(-178) -57 + j*(-252) --325 + j*(325) -218 + j*(546) --151 + j*(0) -262 + j*(-284) -240 + j*(428) -144 + j*(123) -254 + j*(-41) --361 + j*(365) --5 + j*(288) -392 + j*(-202) -316 + j*(238) -296 + j*(165) -16 + j*(468) -36 + j*(290) --267 + j*(-337) -119 + j*(396) --428 + j*(401) --301 + j*(-145) -288 + j*(-189) -506 + j*(-230) --116 + j*(-116) --217 + j*(-225) -171 + j*(-210) -444 + j*(-202) -223 + j*(124) --432 + j*(522) -133 + j*(235) --234 + j*(-372) --84 + j*(-268) --142 + j*(-271) -189 + j*(148) -67 + j*(16) -342 + j*(278) -355 + j*(319) -115 + j*(-101) -631 + j*(-556) -267 + j*(344) --472 + j*(-622) --483 + j*(433) -327 + j*(373) --462 + j*(457) --331 + j*(139) --59 + j*(-136) -276 + j*(-262) --57 + j*(182) --319 + j*(168) --277 + j*(132) -351 + j*(-30) --111 + j*(260) --291 + j*(560) -425 + j*(622) -221 + j*(-26) -121 + j*(54) --103 + j*(271) --273 + j*(-501) -608 + j*(-200) --373 + j*(-40) -103 + j*(-91) -33 + j*(107) --253 + j*(302) -208 + j*(-200) --401 + j*(78) --143 + j*(-327) -354 + j*(-397) --85 + j*(-421) -280 + j*(-222) -320 + j*(-242) -283 + j*(-122) --399 + j*(407) --46 + j*(9) -244 + j*(171) -462 + j*(-53) --617 + j*(-304) --309 + j*(115) -493 + j*(-261) --403 + j*(140) --300 + j*(86) -643 + j*(4) -339 + j*(-296) --363 + j*(-57) --72 + j*(472) -199 + j*(-41) --198 + j*(212) -369 + j*(185) -228 + j*(-564) --215 + j*(-262) --423 + j*(-37) --159 + j*(371) --373 + j*(-308) --371 + j*(241) --204 + j*(-335) -68 + j*(182) --284 + j*(-345) --332 + j*(-184) -418 + j*(255) -3 + j*(-298) -437 + j*(219) -66 + j*(-67) -98 + j*(-235) --384 + j*(288) --322 + j*(271) --377 + j*(-383) -517 + j*(-313) -53 + j*(211) -356 + j*(158) -131 + j*(23) --161 + j*(-13) -284 + j*(-383) -414 + j*(50) -295 + j*(-61) -239 + j*(-342) -289 + j*(-161) -458 + j*(-262) --348 + j*(-588) --573 + j*(215) -266 + j*(463) -344 + j*(-51) -4 + j*(383) -226 + j*(-94) -306 + j*(-347) -206 + j*(11) -347 + j*(151) --305 + j*(337) -433 + j*(302) --28 + j*(527) --534 + j*(-516) -248 + j*(206) -33 + j*(70) --18 + j*(-231) -231 + j*(-226) --456 + j*(-378) -112 + j*(-158) --90 + j*(-523) -52 + j*(-177) --156 + j*(-113) -46 + j*(268) -22 + j*(422) --191 + j*(-325) --315 + j*(-511) --562 + j*(-180) --69 + j*(-325) -591 + j*(288) --554 + j*(337) --305 + j*(358) --340 + j*(-383) --443 + j*(412) -98 + j*(-349) --403 + j*(219) -401 + j*(-107) -209 + j*(-242) --416 + j*(307) -470 + j*(-292) -249 + j*(344) -84 + j*(520) --99 + j*(-9) --381 + j*(240) -52 + j*(-255) --315 + j*(228) -165 + j*(-340) --385 + j*(-367) -378 + j*(11) -486 + j*(-447) -574 + j*(-212) --550 + j*(-66) -296 + j*(443) --421 + j*(-38) --15 + j*(334) -156 + j*(-60) -291 + j*(184) --148 + j*(-100) --99 + j*(294) -214 + j*(76) -349 + j*(-234) -291 + j*(263) --121 + j*(-279) --119 + j*(-69) -187 + j*(204) -340 + j*(-244) --297 + j*(244) --8 + j*(-47) --105 + j*(-7) --196 + j*(-63) --105 + j*(35) -405 + j*(69) -423 + j*(219) --462 + j*(-112) --197 + j*(-422) -224 + j*(81) --612 + j*(71) -363 + j*(209) -133 + j*(-302) -235 + j*(418) --315 + j*(479) --166 + j*(-6) --97 + j*(140) -278 + j*(451) --301 + j*(212) --412 + j*(-291) -446 + j*(224) -108 + j*(-417) -487 + j*(269) --527 + j*(156) --550 + j*(-249) -543 + j*(424) --126 + j*(57) --230 + j*(-80) --40 + j*(-153) --22 + j*(-342) --75 + j*(-334) -339 + j*(-45) --105 + j*(36) -151 + j*(81) --457 + j*(499) -207 + j*(-512) --276 + j*(462) --246 + j*(-299) --155 + j*(-314) --18 + j*(-281) -233 + j*(-358) -564 + j*(-344) --448 + j*(-518) -477 + j*(84) --371 + j*(-276) -453 + j*(187) --252 + j*(-148) -459 + j*(370) --31 + j*(-509) --215 + j*(-175) --177 + j*(-291) --182 + j*(-204) -298 + j*(47) -200 + j*(-255) --353 + j*(-530) -182 + j*(-202) --296 + j*(-480) -370 + j*(-175) --250 + j*(-131) --74 + j*(-313) --115 + j*(-626) -326 + j*(274) --16 + j*(-218) --151 + j*(-180) --474 + j*(374) -378 + j*(-107) -141 + j*(245) -113 + j*(-241) --526 + j*(1) --300 + j*(-199) -550 + j*(-174) -392 + j*(166) -110 + j*(-38) -301 + j*(-351) -284 + j*(-59) -223 + j*(-526) --282 + j*(608) -317 + j*(332) --503 + j*(-453) --366 + j*(518) -349 + j*(1) -310 + j*(279) --163 + j*(-223) --21 + j*(-283) -443 + j*(-171) -262 + j*(-201) -317 + j*(441) -75 + j*(-129) --223 + j*(223) -296 + j*(91) --455 + j*(-91) --651 + j*(175) -359 + j*(-354) --51 + j*(512) -540 + j*(-234) --161 + j*(-114) -349 + j*(-91) --20 + j*(290) --208 + j*(-203) --25 + j*(161) --315 + j*(373) -286 + j*(-8) -125 + j*(395) --95 + j*(53) -332 + j*(-238) --211 + j*(-252) --69 + j*(-207) --617 + j*(268) --103 + j*(356) --131 + j*(393) --310 + j*(-280) --245 + j*(-274) --2 + j*(-759) --375 + j*(-166) --215 + j*(182) -315 + j*(230) --190 + j*(158) --446 + j*(333) -226 + j*(355) -344 + j*(-258) -16 + j*(-428) --372 + j*(301) -393 + j*(189) -293 + j*(-177) -455 + j*(-136) --35 + j*(-170) -16 + j*(-351) --16 + j*(-304) --127 + j*(205) --550 + j*(-288) --10 + j*(-56) --173 + j*(-178) --307 + j*(164) --329 + j*(175) --215 + j*(-426) -397 + j*(211) -289 + j*(-257) --272 + j*(23) --107 + j*(-281) -179 + j*(168) -26 + j*(-535) -23 + j*(234) -302 + j*(392) --164 + j*(-396) -52 + j*(231) -194 + j*(-21) --352 + j*(-203) --338 + j*(146) --677 + j*(-162) --191 + j*(-365) --387 + j*(493) --414 + j*(242) --103 + j*(243) --315 + j*(-6) --612 + j*(210) -41 + j*(-360) --133 + j*(-148) --368 + j*(241) -54 + j*(-62) -398 + j*(-445) --71 + j*(-591) -98 + j*(273) --729 + j*(338) --323 + j*(-267) -355 + j*(-348) -163 + j*(510) -508 + j*(-466) --651 + j*(-209) -189 + j*(168) -487 + j*(150) -364 + j*(111) -267 + j*(-54) -427 + j*(211) --412 + j*(594) --238 + j*(-31) --233 + j*(328) -192 + j*(115) -305 + j*(297) -484 + j*(436) --35 + j*(180) --129 + j*(-513) --51 + j*(-513) --398 + j*(-67) -162 + j*(373) -638 + j*(376) -641 + j*(-561) --204 + j*(-426) -551 + j*(-218) --161 + j*(556) -474 + j*(226) --243 + j*(-293) -16 + j*(-136) --474 + j*(-295) --490 + j*(-260) -252 + j*(-169) --363 + j*(209) --151 + j*(457) --361 + j*(-232) --168 + j*(460) -32 + j*(-496) --92 + j*(-243) --503 + j*(-238) -367 + j*(148) --56 + j*(258) --156 + j*(98) --250 + j*(-78) --107 + j*(-18) -298 + j*(257) --404 + j*(-225) --339 + j*(-220) --61 + j*(-391) --600 + j*(-141) -304 + j*(-457) --280 + j*(146) -206 + j*(421) -355 + j*(709) -153 + j*(225) -124 + j*(-206) -373 + j*(-447) --442 + j*(88) -269 + j*(-115) --335 + j*(-300) --158 + j*(-78) --320 + j*(-414) -491 + j*(-345) -559 + j*(252) --67 + j*(-332) --394 + j*(-370) -242 + j*(-639) --349 + j*(286) -98 + j*(57) -506 + j*(286) -117 + j*(-76) --506 + j*(47) --100 + j*(156) --59 + j*(-168) -162 + j*(363) --142 + j*(298) -110 + j*(139) -163 + j*(184) --107 + j*(-296) -40 + j*(231) --26 + j*(-117) --184 + j*(8) -156 + j*(-24) --98 + j*(-288) -192 + j*(-55) --138 + j*(-66) -161 + j*(276) -337 + j*(-55) -122 + j*(-122) -233 + j*(-233) --29 + j*(-118) --36 + j*(0) --259 + j*(5) -63 + j*(18) --158 + j*(-301) --95 + j*(-240) -549 + j*(309) -184 + j*(53) --141 + j*(328) --11 + j*(258) --41 + j*(237) --107 + j*(35) --265 + j*(-267) -205 + j*(-198) --274 + j*(284) --211 + j*(-33) --326 + j*(-124) --64 + j*(-79) --161 + j*(-294) -122 + j*(32) --248 + j*(-27) --3 + j*(-115) --145 + j*(-153) --308 + j*(35) -138 + j*(-127) --254 + j*(-220) --139 + j*(49) --33 + j*(-45) -41 + j*(23) -4 + j*(-356) --192 + j*(50) --81 + j*(200) -157 + j*(266) -110 + j*(252) -51 + j*(-231) --297 + j*(-110) --142 + j*(-7) --208 + j*(13) --236 + j*(-299) --43 + j*(190) -312 + j*(-10) -157 + j*(-322) -171 + j*(-177) --15 + j*(-80) --320 + j*(103) --58 + j*(208) -192 + j*(-77) -424 + j*(-43) -83 + j*(56) -218 + j*(83) -46 + j*(-98) --73 + j*(74) --149 + j*(35) --199 + j*(47) --54 + j*(-18) --68 + j*(136) -327 + j*(240) --45 + j*(337) --107 + j*(-88) --52 + j*(224) -238 + j*(58) --213 + j*(-77) -105 + j*(56) -163 + j*(-331) -119 + j*(-413) --66 + j*(-121) --112 + j*(176) -93 + j*(35) -199 + j*(98) -177 + j*(-56) --216 + j*(-6) --44 + j*(-34) --244 + j*(-201) -53 + j*(-68) -133 + j*(149) -85 + j*(179) --88 + j*(-4) --91 + j*(28) --173 + j*(16) --13 + j*(135) --147 + j*(120) --85 + j*(-152) -24 + j*(-194) --226 + j*(-117) --8 + j*(120) -301 + j*(350) -110 + j*(-192) --210 + j*(-33) --57 + j*(-59) --57 + j*(-199) -71 + j*(-110) -6 + j*(-235) --84 + j*(100) -38 + j*(-43) --40 + j*(151) --187 + j*(224) --156 + j*(138) -148 + j*(-41) -204 + j*(-564) -144 + j*(-85) -16 + j*(-325) --55 + j*(78) --21 + j*(-2) -77 + j*(152) --99 + j*(-4) --256 + j*(228) -221 + j*(0) --71 + j*(226) --83 + j*(-78) --5 + j*(173) --42 + j*(-68) -116 + j*(-40) -44 + j*(-258) --39 + j*(-39) --7 + j*(-173) --223 + j*(-71) -40 + j*(89) --86 + j*(-344) --243 + j*(190) -286 + j*(48) --284 + j*(227) -156 + j*(98) -180 + j*(-112) --327 + j*(-141) -180 + j*(11) --76 + j*(-96) --55 + j*(-71) --104 + j*(-48) -276 + j*(-40) --4 + j*(-30) -281 + j*(-175) -425 + j*(192) -33 + j*(-87) -279 + j*(42) --97 + j*(-129) -76 + j*(-5) -26 + j*(69) -48 + j*(-472) --218 + j*(-209) --143 + j*(-159) --59 + j*(1) -221 + j*(25) --95 + j*(32) --69 + j*(79) -95 + j*(-206) -159 + j*(-54) --121 + j*(107) --23 + j*(33) --68 + j*(-163) -40 + j*(-171) -190 + j*(-384) --162 + j*(-95) -23 + j*(-211) --136 + j*(0) --46 + j*(-2) -381 + j*(-231) -128 + j*(-233) --30 + j*(-272) --98 + j*(86) --109 + j*(-287) --30 + j*(-47) --94 + j*(235) --144 + j*(0) -257 + j*(210) --68 + j*(-23) -195 + j*(123) --221 + j*(122) -244 + j*(110) --126 + j*(-84) -59 + j*(-195) --64 + j*(305) -186 + j*(74) -85 + j*(-304) --126 + j*(96) -245 + j*(165) -23 + j*(-156) -267 + j*(-207) --306 + j*(-105) --195 + j*(131) --52 + j*(-120) -13 + j*(-123) --27 + j*(-401) -51 + j*(-105) --214 + j*(121) --68 + j*(-316) -64 + j*(83) --260 + j*(-67) --200 + j*(66) --270 + j*(108) --496 + j*(-64) --40 + j*(-259) --36 + j*(365) -29 + j*(61) -271 + j*(139) --46 + j*(-204) -112 + j*(301) -73 + j*(-66) -211 + j*(-33) -24 + j*(161) --153 + j*(-43) -4 + j*(-89) -107 + j*(202) --52 + j*(-315) -23 + j*(59) --80 + j*(-99) -115 + j*(-133) -127 + j*(-4) -56 + j*(278) --90 + j*(17) --215 + j*(176) -39 + j*(-146) --180 + j*(21) --135 + j*(146) -297 + j*(-195) --173 + j*(13) -227 + j*(153) -107 + j*(-227) --42 + j*(94) --177 + j*(176) -157 + j*(40) --243 + j*(30) --65 + j*(-271) --162 + j*(218) -574 + j*(-124) -64 + j*(-87) --106 + j*(21) --64 + j*(-85) -105 + j*(78) -170 + j*(252) -171 + j*(-236) -301 + j*(157) -257 + j*(-142) --198 + j*(127) -8 + j*(402) --31 + j*(137) --168 + j*(-62) -331 + j*(-171) -95 + j*(-11) -260 + j*(-33) -358 + j*(-293) --36 + j*(63) --6 + j*(151) -177 + j*(-247) -60 + j*(-130) -199 + j*(49) --54 + j*(83) -0 + j*(27) --158 + j*(-120) -190 + j*(-147) --168 + j*(138) -161 + j*(-16) --5 + j*(14) --260 + j*(-122) --65 + j*(118) --136 + j*(-20) -97 + j*(0) --78 + j*(0) -89 + j*(-169) -141 + j*(-215) --119 + j*(191) -114 + j*(-15) --366 + j*(300) --267 + j*(373) --71 + j*(211) -220 + j*(136) -3 + j*(91) -170 + j*(275) -159 + j*(-59) --163 + j*(-139) --148 + j*(-9) -161 + j*(321) -167 + j*(26) --87 + j*(-114) --143 + j*(33) -47 + j*(145) -30 + j*(-80) -64 + j*(-204) -70 + j*(-93) --183 + j*(37) --71 + j*(-274) --81 + j*(-93) -243 + j*(197) --277 + j*(-307) --103 + j*(-231) -32 + j*(168) -18 + j*(-4) -320 + j*(267) --28 + j*(-4) -64 + j*(195) --165 + j*(-17) --72 + j*(-80) --83 + j*(236) --95 + j*(-298) --310 + j*(4) -43 + j*(-100) -219 + j*(-225) -99 + j*(184) --158 + j*(-57) --32 + j*(-35) --405 + j*(-144) -329 + j*(9) -191 + j*(47) --65 + j*(98) --28 + j*(-207) --56 + j*(103) --9 + j*(30) --59 + j*(249) --161 + j*(-89) -105 + j*(-37) --136 + j*(-25) --461 + j*(-19) -238 + j*(-184) --49 + j*(-118) --171 + j*(-199) -208 + j*(-146) --117 + j*(-15) --72 + j*(192) -351 + j*(-381) --117 + j*(-57) --37 + j*(-335) --4 + j*(-30) --269 + j*(-141) -351 + j*(107) --214 + j*(-186) -154 + j*(-385) --10 + j*(-100) --200 + j*(-194) -120 + j*(-171) -16 + j*(-36) --6 + j*(64) -53 + j*(-182) --21 + j*(66) --244 + j*(-162) --187 + j*(107) -257 + j*(6) -254 + j*(183) -21 + j*(-123) --260 + j*(-235) --198 + j*(208) -67 + j*(-178) --156 + j*(171) -23 + j*(-328) -50 + j*(-82) -273 + j*(91) --465 + j*(11) --252 + j*(-271) -66 + j*(159) --349 + j*(-22) --38 + j*(-395) -63 + j*(-30) --83 + j*(-186) --167 + j*(-312) -231 + j*(17) -168 + j*(-475) -216 + j*(-16) --141 + j*(-285) --185 + j*(72) -88 + j*(-3) --132 + j*(-122) -63 + j*(245) -158 + j*(-104) --301 + j*(-276) --28 + j*(226) -129 + j*(40) --146 + j*(-64) --306 + j*(-209) -35 + j*(50) -390 + j*(30) --264 + j*(-94) --201 + j*(30) -4 + j*(21) --325 + j*(-134) --270 + j*(-317) -402 + j*(4) --135 + j*(181) -221 + j*(69) --272 + j*(-63) --79 + j*(169) --31 + j*(249) -25 + j*(238) -69 + j*(39) -38 + j*(119) --13 + j*(54) -218 + j*(-204) --118 + j*(-271) --123 + j*(-87) --215 + j*(-211) -8 + j*(-20) --113 + j*(-134) -118 + j*(330) -184 + j*(52) --52 + j*(8) -170 + j*(-322) -59 + j*(-35) --247 + j*(372) --42 + j*(-73) -119 + j*(111) --25 + j*(-49) --2 + j*(-87) --310 + j*(-179) -250 + j*(70) --49 + j*(18) -100 + j*(-186) --135 + j*(28) --71 + j*(153) -45 + j*(428) -3 + j*(-249) --119 + j*(111) -321 + j*(223) -25 + j*(-214) -199 + j*(-301) -36 + j*(-147) -182 + j*(-100) -138 + j*(-7) --115 + j*(-452) -147 + j*(52) -31 + j*(-32) --359 + j*(243) --57 + j*(-26) -288 + j*(-342) --114 + j*(362) --314 + j*(-102) --130 + j*(-46) -90 + j*(184) -46 + j*(-83) --231 + j*(151) --25 + j*(-37) --51 + j*(-51) --491 + j*(88) --45 + j*(141) -62 + j*(-93) --115 + j*(189) --167 + j*(556) --111 + j*(-173) --148 + j*(-122) --70 + j*(-202) -226 + j*(315) -47 + j*(82) -107 + j*(92) --71 + j*(159) --201 + j*(96) --279 + j*(312) -178 + j*(-182) -21 + j*(30) -93 + j*(-142) -330 + j*(-162) -88 + j*(49) -91 + j*(118) --88 + j*(186) -157 + j*(76) --174 + j*(79) -172 + j*(-34) -175 + j*(-133) --195 + j*(-25) -100 + j*(-73) -237 + j*(213) --206 + j*(-190) -209 + j*(-362) --407 + j*(407) --188 + j*(88) --54 + j*(264) --172 + j*(-100) -127 + j*(-121) --132 + j*(-37) --45 + j*(96) -221 + j*(111) -167 + j*(-11) -57 + j*(19) -119 + j*(-85) --74 + j*(69) -12 + j*(-302) --69 + j*(-177) --21 + j*(181) --117 + j*(157) -82 + j*(328) -393 + j*(29) -186 + j*(77) -371 + j*(-147) -93 + j*(-47) --169 + j*(-63) --48 + j*(215) -9 + j*(-59) -73 + j*(-226) --295 + j*(-11) --247 + j*(158) --114 + j*(-120) --83 + j*(-57) -53 + j*(-2) --151 + j*(-27) --251 + j*(-245) --193 + j*(-12) -31 + j*(-63) -235 + j*(208) -53 + j*(-342) -138 + j*(-112) -93 + j*(-262) -5 + j*(65) --266 + j*(-119) --149 + j*(-166) --25 + j*(38) -184 + j*(7) --290 + j*(-71) -157 + j*(293) --90 + j*(-56) -458 + j*(-84) --99 + j*(-19) -164 + j*(153) -224 + j*(174) --101 + j*(-18) --81 + j*(154) -158 + j*(154) --127 + j*(-254) -175 + j*(-91) -292 + j*(21) --170 + j*(0) -148 + j*(-99) --146 + j*(133) -136 + j*(121) -114 + j*(-186) --29 + j*(60) -39 + j*(108) --83 + j*(-29) -25 + j*(254) --4 + j*(-291) -28 + j*(199) --47 + j*(-40) --95 + j*(203) --223 + j*(18) -109 + j*(-144) --82 + j*(-18) -148 + j*(302) -42 + j*(58) -291 + j*(205) -69 + j*(25) --135 + j*(-63) -73 + j*(-18) --325 + j*(-216) --100 + j*(62) --17 + j*(-175) --198 + j*(93) --25 + j*(216) -92 + j*(-165) -122 + j*(-248) -165 + j*(166) -121 + j*(85) -81 + j*(-57) -105 + j*(167) -211 + j*(-134) -18 + j*(-106) --33 + j*(-170) -73 + j*(-61) -286 + j*(-19) -2 + j*(286) --436 + j*(426) --118 + j*(-88) --47 + j*(-100) --127 + j*(266) -58 + j*(-47) --15 + j*(210) -117 + j*(130) --325 + j*(146) -91 + j*(108) -127 + j*(-89) -41 + j*(-191) --69 + j*(283) --24 + j*(-206) --237 + j*(-129) -24 + j*(1) --15 + j*(188) -159 + j*(-438) --153 + j*(177) -91 + j*(84) -196 + j*(99) --199 + j*(-139) --26 + j*(161) --98 + j*(-145) -139 + j*(208) -8 + j*(-177) -106 + j*(83) -107 + j*(-57) --309 + j*(-213) --96 + j*(16) -88 + j*(-123) --114 + j*(145) -238 + j*(-22) -46 + j*(-329) -156 + j*(-65) --183 + j*(112) -61 + j*(-93) -11 + j*(154) -47 + j*(8) --110 + j*(-246) --185 + j*(-25) -383 + j*(-152) -6 + j*(-38) -162 + j*(-64) --345 + j*(178) --4 + j*(-176) --76 + j*(49) -50 + j*(-157) --230 + j*(-141) --103 + j*(-71) -286 + j*(134) --431 + j*(-79) -153 + j*(34) --320 + j*(-55) -178 + j*(292) --25 + j*(-117) -189 + j*(57) -158 + j*(105) --108 + j*(-551) -170 + j*(-34) --298 + j*(-87) -187 + j*(-165) -69 + j*(59) --166 + j*(453) -111 + j*(-119) -172 + j*(-110) --185 + j*(158) --131 + j*(-267) --54 + j*(-285) --57 + j*(65) -94 + j*(-38) -382 + j*(-139) --119 + j*(-199) --252 + j*(48) --190 + j*(421) --119 + j*(30) -165 + j*(236) -77 + j*(42) -14 + j*(210) --52 + j*(-196) -144 + j*(-216) -28 + j*(99) --242 + j*(151) --19 + j*(-17) -62 + j*(-230) -146 + j*(130) --67 + j*(-202) -158 + j*(-134) --318 + j*(192) -48 + j*(-28) --322 + j*(180) --263 + j*(187) -58 + j*(226) --1 + j*(96) -8 + j*(304) --31 + j*(-8) -214 + j*(-35) --35 + j*(-71) --22 + j*(-124) --321 + j*(-234) -305 + j*(-367) --170 + j*(-57) --206 + j*(124) --64 + j*(-117) -35 + j*(-8) --74 + j*(-139) --81 + j*(200) -355 + j*(189) -115 + j*(158) --22 + j*(1) --117 + j*(319) -48 + j*(193) --66 + j*(-28) --78 + j*(-221) -77 + j*(204) --308 + j*(187) --373 + j*(223) --246 + j*(224) -277 + j*(147) -64 + j*(-37) --13 + j*(-129) -6 + j*(-28) -80 + j*(15) -173 + j*(60) --112 + j*(98) --279 + j*(-98) -103 + j*(29) -115 + j*(13) -49 + j*(-102) -233 + j*(81) -189 + j*(-76) -192 + j*(52) --54 + j*(-86) --33 + j*(-18) --248 + j*(105) -76 + j*(177) -433 + j*(-158) --190 + j*(-6) --139 + j*(93) --57 + j*(-262) -165 + j*(-156) -305 + j*(-173) --5 + j*(323) -33 + j*(335) --156 + j*(-53) --235 + j*(111) --19 + j*(78) --34 + j*(-106) -254 + j*(62) --130 + j*(185) -5 + j*(-9) -53 + j*(-91) --107 + j*(357) --16 + j*(-24) -41 + j*(-177) --18 + j*(135) -102 + j*(223) --88 + j*(87) -173 + j*(251) --35 + j*(-85) --260 + j*(-141) -13 + j*(35) -235 + j*(136) -45 + j*(109) -57 + j*(-5) -59 + j*(-38) -148 + j*(78) -134 + j*(-247) --215 + j*(40) -243 + j*(-28) -42 + j*(-71) --59 + j*(-18) -63 + j*(-50) --286 + j*(-103) --140 + j*(-54) -43 + j*(-92) -117 + j*(-78) -58 + j*(-70) --2 + j*(-187) -33 + j*(1) --328 + j*(189) --151 + j*(-17) -70 + j*(56) --33 + j*(110) --56 + j*(-232) -139 + j*(211) -68 + j*(-8) --23 + j*(-332) --84 + j*(-69) --124 + j*(-66) -238 + j*(-9) -165 + j*(-138) -117 + j*(153) --3 + j*(-95) -252 + j*(-83) --146 + j*(81) --163 + j*(-2) -231 + j*(206) -103 + j*(-237) -14 + j*(-40) -187 + j*(175) --88 + j*(171) -66 + j*(202) -71 + j*(-172) --182 + j*(-47) --193 + j*(96) -158 + j*(197) --11 + j*(-202) --110 + j*(86) --76 + j*(-20) -23 + j*(-204) --110 + j*(228) -30 + j*(-39) -182 + j*(-27) -104 + j*(30) --421 + j*(55) --124 + j*(-89) -275 + j*(140) --114 + j*(65) -188 + j*(221) --515 + j*(152) --315 + j*(-170) -1 + j*(-225) -294 + j*(14) -202 + j*(6) -255 + j*(-163) --30 + j*(-192) --179 + j*(141) -148 + j*(-154) --74 + j*(-300) --235 + j*(18) -247 + j*(-79) -177 + j*(-129) --186 + j*(182) --50 + j*(-11) -356 + j*(-52) -148 + j*(-117) -136 + j*(99) -93 + j*(-328) --4 + j*(26) -7 + j*(-222) --58 + j*(-41) -236 + j*(106) --535 + j*(89) -356 + j*(320) --111 + j*(38) -58 + j*(-325) --165 + j*(103) --176 + j*(-89) --93 + j*(-48) --6 + j*(69) -110 + j*(-194) --19 + j*(1) -18 + j*(-311) -407 + j*(-1) -64 + j*(161) -142 + j*(-227) --356 + j*(-335) -195 + j*(366) --200 + j*(-170) -160 + j*(194) --43 + j*(-305) -168 + j*(-30) -221 + j*(146) --13 + j*(194) -366 + j*(-336) --265 + j*(107) --216 + j*(133) --73 + j*(124) --288 + j*(-79) --6 + j*(78) -359 + j*(126) --62 + j*(180) -205 + j*(-325) --21 + j*(-49) -54 + j*(-180) -77 + j*(-340) --77 + j*(-49) --87 + j*(166) -129 + j*(115) --167 + j*(25) -192 + j*(-13) -395 + j*(-304) -358 + j*(-41) -8 + j*(135) --91 + j*(-146) --103 + j*(-84) -136 + j*(98) --123 + j*(-60) -298 + j*(-141) --117 + j*(-283) -335 + j*(-21) -143 + j*(-44) --249 + j*(-75) -11 + j*(47) --146 + j*(-163) -185 + j*(232) -313 + j*(59) --227 + j*(-141) --214 + j*(-50) --64 + j*(143) -73 + j*(-165) -185 + j*(-30) -55 + j*(48) --152 + j*(-82) --35 + j*(-16) -49 + j*(-21) -4 + j*(313) -279 + j*(42) -48 + j*(-219) -40 + j*(37) --71 + j*(99) --75 + j*(-37) -11 + j*(-197) -118 + j*(40) --59 + j*(45) --106 + j*(79) -84 + j*(-100) --6 + j*(-39) --144 + j*(418) -52 + j*(351) -187 + j*(264) --26 + j*(25) --1 + j*(-44) --93 + j*(515) -63 + j*(-93) -296 + j*(78) --311 + j*(363) -4 + j*(-178) -63 + j*(265) --204 + j*(-132) -59 + j*(-104) --294 + j*(8) --167 + j*(76) --74 + j*(288) -105 + j*(-91) -105 + j*(21) -19 + j*(-169) -132 + j*(-124) -83 + j*(43) --302 + j*(-35) -155 + j*(206) -151 + j*(100) --242 + j*(188) -1 + j*(269) --30 + j*(-129) -387 + j*(-134) -135 + j*(89) -15 + j*(-282) -130 + j*(-124) -387 + j*(10) -136 + j*(74) --83 + j*(-74) --450 + j*(-119) --84 + j*(-28) --62 + j*(161) --76 + j*(-78) -75 + j*(-597) -273 + j*(80) --9 + j*(109) -4 + j*(62) -106 + j*(62) -105 + j*(199) --132 + j*(158) --21 + j*(5) --142 + j*(98) --282 + j*(170) -180 + j*(131) -211 + j*(-172) --155 + j*(192) --393 + j*(-5) --84 + j*(-328) --30 + j*(-112) --71 + j*(-198) -120 + j*(-38) --223 + j*(-73) --11 + j*(196) -170 + j*(76) --129 + j*(67) --121 + j*(-35) --66 + j*(103) --183 + j*(148) --215 + j*(-71) --158 + j*(-179) --211 + j*(13) --78 + j*(201) -245 + j*(132) --139 + j*(-11) --58 + j*(204) --103 + j*(-175) --12 + j*(73) --52 + j*(-126) -29 + j*(40) -67 + j*(-36) -18 + j*(-4) -15 + j*(-45) -268 + j*(-138) -62 + j*(25) --344 + j*(-20) -16 + j*(93) --122 + j*(119) --44 + j*(-205) -137 + j*(-150) -197 + j*(-11) -56 + j*(-64) -25 + j*(-168) -112 + j*(141) --144 + j*(29) --170 + j*(-252) --190 + j*(-37) --8 + j*(-127) --10 + j*(247) -193 + j*(-303) --122 + j*(-218) -165 + j*(-90) -28 + j*(-100) -31 + j*(19) --96 + j*(-121) --98 + j*(30) --281 + j*(-203) -250 + j*(-42) --244 + j*(109) --47 + j*(-231) -16 + j*(-291) -40 + j*(-218) --300 + j*(34) --152 + j*(173) --74 + j*(73) --23 + j*(-93) --45 + j*(-342) -24 + j*(-52) --193 + j*(183) --151 + j*(-307) --26 + j*(24) -207 + j*(-115) --58 + j*(139) --33 + j*(-112) --409 + j*(149) --1 + j*(-136) --288 + j*(-105) --30 + j*(-198) -187 + j*(39) -71 + j*(33) --371 + j*(64) --27 + j*(-169) -40 + j*(4) --234 + j*(72) --243 + j*(-18) -29 + j*(71) -189 + j*(-243) --201 + j*(-335) --214 + j*(-97) --161 + j*(185) --247 + j*(45) --260 + j*(-303) --206 + j*(245) --127 + j*(12) -49 + j*(156) --52 + j*(-3) -193 + j*(69) -203 + j*(62) -111 + j*(-100) --105 + j*(-18) -25 + j*(-121) --134 + j*(104) --275 + j*(233) -100 + j*(-326) --230 + j*(-73) -139 + j*(-256) -300 + j*(23) --189 + j*(-491) -137 + j*(-88) -133 + j*(-263) --106 + j*(-373) --18 + j*(-103) --98 + j*(223) --4 + j*(-18) -6 + j*(266) -60 + j*(-30) --188 + j*(-150) --118 + j*(40) --140 + j*(-16) -88 + j*(59) --22 + j*(-28) -110 + j*(-66) -160 + j*(-157) -139 + j*(31) -19 + j*(-97) -69 + j*(101) --49 + j*(172) -245 + j*(-80) -14 + j*(274) --71 + j*(1) --33 + j*(29) --208 + j*(66) -184 + j*(227) --239 + j*(-216) -127 + j*(-18) -469 + j*(177) --91 + j*(263) -4 + j*(46) --212 + j*(102) -25 + j*(-23) -153 + j*(10) --97 + j*(-8) --236 + j*(-30) --46 + j*(-418) --104 + j*(288) -78 + j*(-39) -136 + j*(1) -43 + j*(-76) -34 + j*(-223) -110 + j*(-4) -146 + j*(-64) --5 + j*(45) -89 + j*(44) --12 + j*(-76) --5 + j*(-25) -20 + j*(243) -47 + j*(-218) --81 + j*(71) --73 + j*(187) -314 + j*(94) --119 + j*(-69) -136 + j*(88) -158 + j*(75) --196 + j*(-190) --5 + j*(-135) -134 + j*(228) --108 + j*(-257) --16 + j*(414) --16 + j*(96) -151 + j*(163) -93 + j*(4) --204 + j*(-71) --107 + j*(213) -187 + j*(26) --30 + j*(242) -89 + j*(-8) -4 + j*(-206) --54 + j*(-242) -110 + j*(-37) --175 + j*(-238) --148 + j*(15) -208 + j*(-152) --28 + j*(-235) --183 + j*(-280) -189 + j*(-124) --19 + j*(8) --250 + j*(-168) --24 + j*(-89) --247 + j*(140) -216 + j*(385) -88 + j*(-119) -356 + j*(-173) -4 + j*(145) --193 + j*(-115) -109 + j*(-45) -203 + j*(172) --103 + j*(337) --80 + j*(187) --129 + j*(179) -158 + j*(-235) --52 + j*(-272) --91 + j*(327) --25 + j*(117) --143 + j*(-141) -92 + j*(310) -129 + j*(33) --202 + j*(159) -86 + j*(43) --43 + j*(69) --130 + j*(-140) --139 + j*(371) --1 + j*(92) --301 + j*(-141) -170 + j*(83) -6 + j*(-224) --183 + j*(132) --187 + j*(74) -141 + j*(-238) --102 + j*(346) --230 + j*(298) -71 + j*(280) --360 + j*(311) --85 + j*(173) -117 + j*(-69) -23 + j*(314) --179 + j*(234) -95 + j*(8) -18 + j*(-133) --137 + j*(-108) -115 + j*(122) --23 + j*(-101) -18 + j*(2) -96 + j*(-134) -21 + j*(3) -373 + j*(-148) -162 + j*(41) -240 + j*(244) --114 + j*(192) -86 + j*(-23) --55 + j*(67) --188 + j*(163) --23 + j*(10) -18 + j*(-76) --27 + j*(21) -163 + j*(198) --44 + j*(33) -70 + j*(66) --132 + j*(356) --43 + j*(-99) --134 + j*(165) -225 + j*(-81) --55 + j*(-30) -143 + j*(88) -64 + j*(-105) --44 + j*(-93) --69 + j*(-28) --184 + j*(-154) --315 + j*(184) -49 + j*(-148) --220 + j*(91) --91 + j*(-29) --177 + j*(-166) -35 + j*(86) --190 + j*(-197) --281 + j*(-106) --211 + j*(-90) --185 + j*(27) -50 + j*(298) -71 + j*(-78) -268 + j*(-33) -79 + j*(-139) -218 + j*(125) -400 + j*(190) --83 + j*(17) --129 + j*(385) --5 + j*(-299) --202 + j*(-363) -233 + j*(24) -13 + j*(-80) --256 + j*(-156) -194 + j*(-125) -233 + j*(104) --206 + j*(145) --181 + j*(137) --342 + j*(253) -91 + j*(13) --117 + j*(164) --138 + j*(58) -227 + j*(-179) --38 + j*(42) --46 + j*(-65) -98 + j*(302) --18 + j*(167) -135 + j*(136) -111 + j*(16) --107 + j*(-140) -69 + j*(-180) -69 + j*(-49) --100 + j*(190) --161 + j*(302) --57 + j*(261) -78 + j*(-50) -62 + j*(45) -298 + j*(24) -65 + j*(288) --132 + j*(4) -186 + j*(4) -53 + j*(84) --94 + j*(177) -258 + j*(-5) -82 + j*(-281) -282 + j*(295) -119 + j*(-278) --65 + j*(-95) --216 + j*(-46) -116 + j*(105) -13 + j*(287) -105 + j*(165) -221 + j*(-129) -27 + j*(115) --284 + j*(5) --20 + j*(190) -39 + j*(128) --301 + j*(-53) --198 + j*(-95) --39 + j*(129) --34 + j*(-30) --25 + j*(280) -134 + j*(176) --54 + j*(-99) -64 + j*(-139) --147 + j*(191) -77 + j*(-8) --140 + j*(1) -29 + j*(6) --252 + j*(-90) -66 + j*(-373) --273 + j*(177) --53 + j*(-73) -426 + j*(209) -303 + j*(-223) -230 + j*(78) --146 + j*(-151) -32 + j*(169) -408 + j*(48) -149 + j*(54) --18 + j*(-1) -320 + j*(122) --23 + j*(28) -89 + j*(-202) -33 + j*(-117) -274 + j*(-25) -23 + j*(-18) --88 + j*(-291) --51 + j*(407) --50 + j*(18) --4 + j*(-36) -115 + j*(124) --13 + j*(150) -223 + j*(-66) --48 + j*(108) --82 + j*(-92) -40 + j*(219) --216 + j*(148) --187 + j*(-291) --45 + j*(56) -185 + j*(47) -94 + j*(-248) --107 + j*(-1) --199 + j*(-47) -20 + j*(60) -117 + j*(141) --151 + j*(-326) -51 + j*(-210) -121 + j*(-66) --40 + j*(-173) --83 + j*(-199) --54 + j*(-74) -83 + j*(-98) -243 + j*(170) -217 + j*(-255) -242 + j*(-443) --148 + j*(-34) -42 + j*(201) -29 + j*(-47) --98 + j*(-1) -45 + j*(141) --148 + j*(-74) -161 + j*(-137) -116 + j*(169) -49 + j*(-519) -9 + j*(-118) -144 + j*(169) --106 + j*(77) --124 + j*(-10) --298 + j*(303) -268 + j*(-8) -44 + j*(-12) -165 + j*(-390) --98 + j*(-107) -199 + j*(197) -194 + j*(49) --206 + j*(412) -68 + j*(-216) -274 + j*(139) --237 + j*(60) -85 + j*(285) -4 + j*(-130) -168 + j*(-20) -284 + j*(175) -316 + j*(-301) -62 + j*(148) -54 + j*(-270) -95 + j*(266) --95 + j*(-28) --46 + j*(29) --254 + j*(-30) --159 + j*(117) --9 + j*(-117) --64 + j*(-76) -59 + j*(19) --45 + j*(-144) --358 + j*(-110) --302 + j*(218) -140 + j*(335) -233 + j*(12) -386 + j*(96) --37 + j*(-218) --187 + j*(-46) -16 + j*(290) -59 + j*(18) -158 + j*(-102) -104 + j*(-3) --23 + j*(204) -131 + j*(161) -105 + j*(339) --226 + j*(-220) --144 + j*(202) --95 + j*(-191) --44 + j*(49) -69 + j*(-114) --105 + j*(221) -12 + j*(58) -264 + j*(-68) --21 + j*(88) --357 + j*(15) --122 + j*(-136) --35 + j*(129) -139 + j*(-16) --175 + j*(-110) -24 + j*(67) -17 + j*(56) --100 + j*(-48) --75 + j*(-260) --28 + j*(-51) -52 + j*(-117) -445 + j*(41) -35 + j*(159) --68 + j*(112) --208 + j*(158) --182 + j*(-253) --3 + j*(-115) --30 + j*(371) -8 + j*(30) --223 + j*(-93) -274 + j*(57) --313 + j*(-148) -244 + j*(195) -10 + j*(-305) -296 + j*(88) -7 + j*(87) --40 + j*(91) --315 + j*(-76) --16 + j*(88) --83 + j*(-124) --98 + j*(-20) --94 + j*(-92) --143 + j*(-262) --87 + j*(49) -252 + j*(-49) --119 + j*(354) -134 + j*(46) --167 + j*(-270) --130 + j*(-144) -103 + j*(151) --87 + j*(243) -70 + j*(132) --128 + j*(2) -58 + j*(114) -215 + j*(14) --81 + j*(183) -37 + j*(65) --151 + j*(38) --92 + j*(75) --240 + j*(-64) --23 + j*(-105) --359 + j*(-221) --107 + j*(18) -88 + j*(-301) --308 + j*(542) --77 + j*(-313) -221 + j*(-117) --18 + j*(-79) -118 + j*(-240) --389 + j*(-11) -57 + j*(0) --142 + j*(-67) --115 + j*(-76) -39 + j*(-61) -182 + j*(0) --65 + j*(46) -57 + j*(-47) --304 + j*(33) --430 + j*(489) --425 + j*(47) -261 + j*(597) --67 + j*(314) --337 + j*(167) --143 + j*(-90) --353 + j*(-21) --335 + j*(162) -605 + j*(390) --31 + j*(-196) --340 + j*(-206) --275 + j*(-161) --332 + j*(120) -422 + j*(202) -316 + j*(192) --141 + j*(535) --296 + j*(-251) -209 + j*(-497) --286 + j*(-75) -165 + j*(470) --82 + j*(273) -99 + j*(267) --262 + j*(188) --15 + j*(172) --30 + j*(403) -212 + j*(272) --204 + j*(-431) --351 + j*(-269) -589 + j*(204) -311 + j*(-122) -391 + j*(-222) --371 + j*(286) --566 + j*(-589) -202 + j*(-261) --151 + j*(-124) -474 + j*(-434) -272 + j*(-49) -359 + j*(75) -129 + j*(-83) --320 + j*(-96) -140 + j*(-76) --211 + j*(-550) -305 + j*(417) --412 + j*(64) -226 + j*(-547) -407 + j*(-380) --83 + j*(-97) -396 + j*(-173) -255 + j*(-368) -213 + j*(-57) -313 + j*(110) -42 + j*(158) --93 + j*(-151) --267 + j*(12) --50 + j*(119) --161 + j*(-238) --6 + j*(-322) --392 + j*(-337) -472 + j*(-371) -142 + j*(421) --317 + j*(400) -447 + j*(-417) -487 + j*(-246) --265 + j*(420) --237 + j*(279) --163 + j*(188) --423 + j*(341) --38 + j*(-321) -492 + j*(101) --297 + j*(-282) --43 + j*(210) -247 + j*(262) -219 + j*(253) -446 + j*(250) --492 + j*(-336) -272 + j*(-373) -289 + j*(241) --71 + j*(-12) --334 + j*(684) --156 + j*(294) -219 + j*(168) -222 + j*(391) --127 + j*(585) -458 + j*(-467) -400 + j*(-296) --229 + j*(1) --195 + j*(130) --42 + j*(-72) --548 + j*(46) -168 + j*(17) --109 + j*(307) -274 + j*(-205) -181 + j*(-606) -23 + j*(216) --359 + j*(13) -91 + j*(288) --216 + j*(141) --315 + j*(-303) -165 + j*(450) --474 + j*(64) -450 + j*(-318) --443 + j*(348) -131 + j*(450) -259 + j*(401) --464 + j*(-486) -74 + j*(-565) --122 + j*(-119) -512 + j*(-184) --305 + j*(201) -199 + j*(-392) -158 + j*(-424) -156 + j*(43) --610 + j*(289) -172 + j*(-296) -47 + j*(297) --458 + j*(-441) -222 + j*(-376) --399 + j*(8) --208 + j*(371) --65 + j*(-204) --322 + j*(663) --438 + j*(-144) -144 + j*(123) -97 + j*(363) -164 + j*(-170) --237 + j*(167) -117 + j*(55) -342 + j*(-199) --254 + j*(226) --356 + j*(474) --164 + j*(171) -393 + j*(-431) --197 + j*(-47) -192 + j*(179) -183 + j*(-356) -377 + j*(-268) -465 + j*(407) --193 + j*(-66) --267 + j*(-235) -607 + j*(416) --198 + j*(310) -403 + j*(542) -182 + j*(-26) --594 + j*(-251) --167 + j*(-284) --265 + j*(667) -171 + j*(-404) -122 + j*(-467) --266 + j*(57) --361 + j*(-285) -348 + j*(23) --206 + j*(-553) --160 + j*(309) -491 + j*(283) --422 + j*(-171) --202 + j*(-250) --229 + j*(99) -183 + j*(95) -134 + j*(-175) -172 + j*(-517) -147 + j*(385) --446 + j*(392) -228 + j*(106) -90 + j*(-122) --284 + j*(-69) --255 + j*(-495) -99 + j*(-112) --347 + j*(-191) -355 + j*(173) --342 + j*(175) -407 + j*(-28) -223 + j*(-71) --313 + j*(26) -156 + j*(-120) -392 + j*(-379) --321 + j*(-26) --399 + j*(160) -187 + j*(228) --249 + j*(-415) -404 + j*(399) -198 + j*(253) -438 + j*(82) -479 + j*(237) -363 + j*(318) -576 + j*(-229) --667 + j*(-161) -300 + j*(-527) -92 + j*(596) --7 + j*(-363) --397 + j*(414) -142 + j*(220) -535 + j*(395) -306 + j*(418) --162 + j*(-406) -354 + j*(-330) --219 + j*(162) --331 + j*(-506) -496 + j*(225) -133 + j*(115) -214 + j*(218) -197 + j*(-316) -587 + j*(9) --30 + j*(397) --547 + j*(-593) -352 + j*(-108) --219 + j*(142) --383 + j*(286) --216 + j*(-329) -390 + j*(276) --157 + j*(-122) -236 + j*(122) -31 + j*(-37) -174 + j*(-285) -253 + j*(-253) -427 + j*(-403) --315 + j*(345) --428 + j*(-682) -15 + j*(-400) --339 + j*(496) --588 + j*(91) -229 + j*(-165) -529 + j*(296) -553 + j*(346) --144 + j*(66) --397 + j*(452) -445 + j*(406) --112 + j*(-163) -301 + j*(253) -296 + j*(274) -354 + j*(-94) --457 + j*(-530) --373 + j*(-168) --270 + j*(-178) --407 + j*(-224) -3 + j*(-22) -177 + j*(288) --476 + j*(31) --296 + j*(232) --331 + j*(-110) -429 + j*(-240) -385 + j*(-395) --89 + j*(326) -369 + j*(243) --419 + j*(30) -117 + j*(-298) --83 + j*(388) -427 + j*(119) --233 + j*(-222) --437 + j*(509) --329 + j*(-51) -184 + j*(238) -383 + j*(-150) -398 + j*(204) --277 + j*(-255) --166 + j*(105) -409 + j*(-567) --312 + j*(-180) -85 + j*(-119) --353 + j*(52) --416 + j*(-530) --59 + j*(-94) --454 + j*(-723) -321 + j*(148) --545 + j*(-355) --286 + j*(-40) -398 + j*(-600) -144 + j*(-344) -199 + j*(-606) --42 + j*(290) --328 + j*(-112) --199 + j*(-245) -303 + j*(-335) --484 + j*(-413) --314 + j*(98) --100 + j*(-88) --328 + j*(383) --117 + j*(33) -491 + j*(-299) -320 + j*(426) -124 + j*(320) --184 + j*(223) --165 + j*(-230) -280 + j*(-183) -67 + j*(-808) -104 + j*(177) -260 + j*(-230) -454 + j*(-49) -145 + j*(-433) --284 + j*(-306) -336 + j*(-199) --338 + j*(-395) -168 + j*(-86) --537 + j*(-232) --396 + j*(-558) -587 + j*(-207) -155 + j*(-412) --122 + j*(185) --648 + j*(-65) --167 + j*(-233) --371 + j*(308) --449 + j*(-25) -156 + j*(233) --207 + j*(243) --474 + j*(313) -325 + j*(6) --183 + j*(269) --344 + j*(-54) --98 + j*(325) -382 + j*(197) --304 + j*(-89) -100 + j*(-390) --471 + j*(-12) -237 + j*(255) -247 + j*(-138) --98 + j*(-78) -63 + j*(199) --258 + j*(-231) --470 + j*(-422) --224 + j*(378) -629 + j*(1) --255 + j*(-604) --100 + j*(478) --19 + j*(430) -663 + j*(213) -222 + j*(181) --127 + j*(270) -351 + j*(-373) -308 + j*(192) --149 + j*(240) -80 + j*(-377) -120 + j*(-112) --96 + j*(-182) --8 + j*(-73) -477 + j*(-154) --419 + j*(274) --496 + j*(256) --240 + j*(410) -150 + j*(-351) --243 + j*(-137) --11 + j*(-345) -100 + j*(197) -67 + j*(52) -247 + j*(276) -106 + j*(404) --426 + j*(-358) -161 + j*(-528) -211 + j*(233) --408 + j*(180) -334 + j*(464) -469 + j*(-114) -278 + j*(178) -86 + j*(-257) -78 + j*(-322) -457 + j*(-159) --275 + j*(328) --508 + j*(-10) -209 + j*(89) --301 + j*(291) --247 + j*(-146) -259 + j*(177) -83 + j*(-61) --369 + j*(-315) --206 + j*(-272) --194 + j*(53) -344 + j*(291) -242 + j*(-343) -433 + j*(-74) -424 + j*(423) --332 + j*(160) --345 + j*(675) -209 + j*(-36) --152 + j*(-247) --177 + j*(434) -312 + j*(317) -197 + j*(-103) --355 + j*(112) --69 + j*(-194) -400 + j*(118) -151 + j*(506) -386 + j*(-337) -451 + j*(228) -40 + j*(-25) -48 + j*(-194) --218 + j*(-320) -207 + j*(-124) --117 + j*(-141) -343 + j*(-224) -308 + j*(291) --247 + j*(-361) -511 + j*(32) -228 + j*(91) -380 + j*(302) -324 + j*(-119) --413 + j*(463) -292 + j*(281) --201 + j*(-165) --303 + j*(-211) --471 + j*(418) --69 + j*(-121) --607 + j*(274) -141 + j*(342) --339 + j*(-220) --51 + j*(-165) -229 + j*(-407) --151 + j*(263) --238 + j*(-291) -316 + j*(-284) -279 + j*(-5) -530 + j*(231) -362 + j*(-301) --351 + j*(88) --110 + j*(-561) -112 + j*(460) --511 + j*(-83) -465 + j*(-271) -302 + j*(-204) -164 + j*(355) --293 + j*(-134) -190 + j*(-144) -306 + j*(343) -368 + j*(298) -53 + j*(-6) --45 + j*(180) --273 + j*(359) --361 + j*(58) --361 + j*(-168) --212 + j*(-321) --178 + j*(13) -186 + j*(-363) --138 + j*(276) -149 + j*(-330) --303 + j*(291) -427 + j*(-233) -410 + j*(147) --484 + j*(243) -57 + j*(-330) -357 + j*(-601) -107 + j*(86) -402 + j*(-378) --295 + j*(-273) --211 + j*(-189) -264 + j*(360) -525 + j*(78) -414 + j*(161) --354 + j*(-292) -457 + j*(262) --247 + j*(284) -316 + j*(-690) -285 + j*(-289) -109 + j*(-199) --414 + j*(-325) --316 + j*(151) --11 + j*(278) -296 + j*(57) -403 + j*(187) -196 + j*(129) --380 + j*(-382) --358 + j*(432) -311 + j*(-158) --141 + j*(-752) --210 + j*(223) -181 + j*(-170) --144 + j*(479) -42 + j*(337) --118 + j*(-448) -222 + j*(-74) -631 + j*(-293) -339 + j*(-683) --165 + j*(141) -388 + j*(-554) --211 + j*(358) --309 + j*(110) --313 + j*(130) -223 + j*(560) -415 + j*(496) -11 + j*(344) -634 + j*(-202) -226 + j*(-28) --185 + j*(363) --289 + j*(107) -43 + j*(301) -91 + j*(-283) -76 + j*(-579) --298 + j*(95) -31 + j*(84) --288 + j*(252) -194 + j*(413) -264 + j*(-355) -165 + j*(-302) --120 + j*(101) -344 + j*(-684) --288 + j*(52) --290 + j*(-463) --135 + j*(286) --445 + j*(-125) --263 + j*(97) --277 + j*(-421) -302 + j*(-375) -455 + j*(412) --128 + j*(63) -118 + j*(107) --360 + j*(407) -54 + j*(366) --74 + j*(-502) -234 + j*(242) -572 + j*(-114) -197 + j*(-351) -518 + j*(128) -477 + j*(462) --64 + j*(393) --113 + j*(-435) -303 + j*(-301) --221 + j*(146) --116 + j*(-151) --352 + j*(-286) --298 + j*(-105) -153 + j*(-247) -539 + j*(7) -360 + j*(144) -110 + j*(74) -328 + j*(28) --337 + j*(424) -129 + j*(-260) -549 + j*(41) --368 + j*(378) --253 + j*(-668) -263 + j*(180) -253 + j*(-273) --412 + j*(212) --180 + j*(207) --329 + j*(-180) -154 + j*(-82) --102 + j*(197) --356 + j*(107) --89 + j*(-513) --393 + j*(41) -344 + j*(403) -245 + j*(286) --390 + j*(146) -184 + j*(-487) -132 + j*(-408) --330 + j*(441) --28 + j*(579) -197 + j*(-210) --52 + j*(-171) -317 + j*(201) --162 + j*(-148) -111 + j*(-285) --148 + j*(177) --291 + j*(210) --358 + j*(-169) -421 + j*(-378) --173 + j*(52) -19 + j*(-194) -211 + j*(62) --416 + j*(202) --296 + j*(194) --357 + j*(72) --214 + j*(49) -289 + j*(400) --182 + j*(349) --583 + j*(-578) --322 + j*(232) --136 + j*(179) -276 + j*(397) --436 + j*(24) --224 + j*(-35) -74 + j*(110) --414 + j*(-103) --369 + j*(513) --141 + j*(-160) -309 + j*(346) -276 + j*(763) --186 + j*(401) -137 + j*(202) -179 + j*(272) --358 + j*(217) -109 + j*(330) --497 + j*(70) --352 + j*(288) -957 + j*(428) -136 + j*(149) --426 + j*(-522) -91 + j*(52) --378 + j*(150) --367 + j*(416) -130 + j*(123) --260 + j*(361) --31 + j*(-247) -346 + j*(-375) -166 + j*(-52) -158 + j*(-178) --497 + j*(201) -376 + j*(-266) --416 + j*(258) --198 + j*(175) --107 + j*(-139) --255 + j*(77) --380 + j*(267) --342 + j*(277) --279 + j*(-194) -217 + j*(9) -65 + j*(-134) --23 + j*(-395) -195 + j*(262) -86 + j*(-10) --37 + j*(278) --40 + j*(-135) -6 + j*(-1) -144 + j*(163) --16 + j*(-21) --5 + j*(147) --47 + j*(-260) --321 + j*(172) -238 + j*(-30) -216 + j*(81) -11 + j*(-53) --47 + j*(-23) -93 + j*(-51) --1 + j*(-8) --76 + j*(-121) --240 + j*(0) --38 + j*(-183) -0 + j*(163) -234 + j*(-31) --15 + j*(244) -76 + j*(-4) --153 + j*(257) -173 + j*(26) --37 + j*(-276) --131 + j*(206) -65 + j*(192) -278 + j*(-243) --161 + j*(-1) -44 + j*(-173) -167 + j*(245) --102 + j*(122) --47 + j*(-253) --21 + j*(-165) --1 + j*(57) -10 + j*(-13) -48 + j*(188) --45 + j*(-52) --17 + j*(-233) -32 + j*(-101) --295 + j*(-116) -388 + j*(128) --134 + j*(-117) --81 + j*(-160) --45 + j*(-393) -72 + j*(-60) --24 + j*(-247) -208 + j*(-424) -280 + j*(-19) --87 + j*(276) -23 + j*(70) -88 + j*(-285) -1 + j*(-189) -121 + j*(-41) --55 + j*(-153) --192 + j*(147) -98 + j*(-22) -0 + j*(218) --347 + j*(138) --95 + j*(-165) -214 + j*(-88) --113 + j*(-315) --131 + j*(390) --264 + j*(144) -114 + j*(-233) --54 + j*(-50) --342 + j*(124) --173 + j*(-27) -140 + j*(-115) -48 + j*(361) --327 + j*(187) --40 + j*(-163) --104 + j*(229) -144 + j*(-105) --83 + j*(-214) -183 + j*(117) --150 + j*(75) -160 + j*(-52) --6 + j*(-65) -209 + j*(132) --195 + j*(275) -75 + j*(-323) --33 + j*(-221) -92 + j*(-206) -8 + j*(-38) --83 + j*(-167) -68 + j*(198) -31 + j*(13) --310 + j*(318) -105 + j*(175) -5 + j*(-67) -42 + j*(-11) -107 + j*(29) -79 + j*(-83) --68 + j*(-226) -366 + j*(92) --146 + j*(172) -74 + j*(386) -160 + j*(-37) -327 + j*(-145) --189 + j*(208) --25 + j*(-168) -93 + j*(-51) -15 + j*(202) -4 + j*(2) -37 + j*(152) --97 + j*(-64) -276 + j*(257) --67 + j*(-88) --58 + j*(-4) --297 + j*(242) --194 + j*(-285) --26 + j*(139) --220 + j*(271) -27 + j*(-36) --277 + j*(98) -182 + j*(-327) -314 + j*(211) --52 + j*(-117) --92 + j*(64) --197 + j*(-198) --291 + j*(16) -45 + j*(100) -7 + j*(-226) --6 + j*(-90) --440 + j*(110) --20 + j*(144) -296 + j*(-84) --49 + j*(29) --97 + j*(416) --202 + j*(-2) -31 + j*(-51) --156 + j*(-209) --198 + j*(-40) -66 + j*(82) --215 + j*(378) -414 + j*(23) --291 + j*(122) -221 + j*(-47) --374 + j*(33) -348 + j*(-216) -187 + j*(70) -129 + j*(-145) --108 + j*(-35) --100 + j*(-327) -228 + j*(-83) -334 + j*(107) --380 + j*(-332) --64 + j*(93) -177 + j*(-193) --50 + j*(-9) --325 + j*(152) --71 + j*(111) -291 + j*(-116) --158 + j*(229) --150 + j*(-164) -36 + j*(126) -8 + j*(-73) -190 + j*(-161) --25 + j*(-20) -130 + j*(99) -35 + j*(276) -242 + j*(171) --145 + j*(-106) -103 + j*(-179) -127 + j*(-1) --112 + j*(-151) --141 + j*(308) -199 + j*(-22) -23 + j*(156) --23 + j*(-225) --168 + j*(37) --245 + j*(83) -145 + j*(40) --308 + j*(-13) -39 + j*(7) -16 + j*(-214) -87 + j*(-40) --126 + j*(-33) -371 + j*(313) -80 + j*(-34) -8 + j*(175) --110 + j*(368) --66 + j*(130) -124 + j*(-55) --166 + j*(-139) -119 + j*(126) --124 + j*(245) --150 + j*(110) -161 + j*(-21) -52 + j*(-105) --98 + j*(27) --139 + j*(125) -38 + j*(76) --90 + j*(259) --3 + j*(23) -31 + j*(84) -292 + j*(-22) --146 + j*(505) -293 + j*(71) --9 + j*(198) -9 + j*(15) --60 + j*(-96) --231 + j*(241) --232 + j*(-240) -211 + j*(-120) --145 + j*(54) -3 + j*(16) --204 + j*(-413) --373 + j*(-87) --5 + j*(128) --222 + j*(-5) --42 + j*(-223) --224 + j*(33) --10 + j*(-8) --134 + j*(25) --187 + j*(351) -109 + j*(-105) -114 + j*(-36) --226 + j*(84) --168 + j*(-105) --91 + j*(-60) -55 + j*(-227) --25 + j*(-95) --35 + j*(325) -59 + j*(-122) -81 + j*(-134) --172 + j*(117) --4 + j*(141) -30 + j*(-124) --381 + j*(-111) --119 + j*(-175) -103 + j*(-36) --96 + j*(-64) -197 + j*(-59) -52 + j*(-100) --151 + j*(125) --132 + j*(-57) --35 + j*(-74) -52 + j*(-267) -139 + j*(4) --177 + j*(177) --141 + j*(-110) --64 + j*(372) --204 + j*(-33) -113 + j*(187) --123 + j*(91) -177 + j*(-75) -56 + j*(-164) --342 + j*(178) --83 + j*(124) -71 + j*(-26) --179 + j*(76) --7 + j*(-199) --92 + j*(94) -67 + j*(-88) -62 + j*(197) -144 + j*(223) --164 + j*(25) -148 + j*(-99) -176 + j*(-33) -96 + j*(-22) -4 + j*(-28) -8 + j*(-88) --38 + j*(69) -20 + j*(27) --151 + j*(-105) -46 + j*(279) --182 + j*(-129) -187 + j*(-45) -125 + j*(41) --105 + j*(260) -139 + j*(-175) -197 + j*(62) --47 + j*(-6) -8 + j*(-264) -145 + j*(-122) --71 + j*(-253) --63 + j*(233) -121 + j*(-4) --58 + j*(111) -358 + j*(151) --23 + j*(-28) -11 + j*(-8) -11 + j*(26) --92 + j*(-46) --100 + j*(336) --50 + j*(31) --165 + j*(-91) -116 + j*(-206) -65 + j*(272) --177 + j*(163) --134 + j*(44) -194 + j*(84) -214 + j*(-51) --225 + j*(210) -88 + j*(158) -120 + j*(-69) -111 + j*(115) -139 + j*(205) -329 + j*(-174) -47 + j*(82) --327 + j*(-317) -37 + j*(154) -84 + j*(14) -84 + j*(-11) -221 + j*(155) --364 + j*(194) -113 + j*(43) -4 + j*(21) --107 + j*(-91) --89 + j*(26) --249 + j*(-27) -23 + j*(132) -127 + j*(-84) --12 + j*(-115) --71 + j*(-11) --30 + j*(-1) --172 + j*(138) -335 + j*(131) --389 + j*(-301) --227 + j*(-21) -31 + j*(-216) --5 + j*(-132) --144 + j*(-299) --165 + j*(228) -3 + j*(-140) --32 + j*(64) --133 + j*(62) --59 + j*(-167) --209 + j*(-176) -313 + j*(-33) --28 + j*(137) -184 + j*(219) --16 + j*(294) --196 + j*(-70) --86 + j*(38) --75 + j*(-91) -356 + j*(226) --60 + j*(390) -22 + j*(-121) -90 + j*(76) --141 + j*(-10) -87 + j*(57) --245 + j*(-4) -88 + j*(-81) --40 + j*(148) --1 + j*(209) -216 + j*(24) -26 + j*(13) --249 + j*(45) -251 + j*(-110) --366 + j*(-232) -13 + j*(130) -17 + j*(271) --126 + j*(-201) --52 + j*(-122) -102 + j*(-264) -74 + j*(206) -317 + j*(-79) -122 + j*(13) -186 + j*(132) --86 + j*(-180) --253 + j*(-194) -86 + j*(-68) --88 + j*(-161) -159 + j*(-275) -146 + j*(-74) --85 + j*(-33) --16 + j*(-133) --136 + j*(-61) --112 + j*(-103) --156 + j*(57) -43 + j*(-80) -58 + j*(193) --187 + j*(-203) -197 + j*(191) -277 + j*(26) -4 + j*(-117) --81 + j*(182) --8 + j*(-11) -54 + j*(-61) --351 + j*(64) --178 + j*(-216) --4 + j*(-388) --141 + j*(91) --140 + j*(-93) -33 + j*(197) -63 + j*(-147) -17 + j*(132) -10 + j*(127) --253 + j*(192) --36 + j*(107) -125 + j*(-66) --131 + j*(-82) --250 + j*(-14) --285 + j*(5) -119 + j*(-23) -28 + j*(253) --49 + j*(330) -73 + j*(24) -82 + j*(40) -4 + j*(179) -44 + j*(-324) --77 + j*(64) --16 + j*(-161) -181 + j*(-55) --248 + j*(-226) --185 + j*(130) -108 + j*(110) --337 + j*(-95) -117 + j*(-192) --18 + j*(104) -185 + j*(204) --106 + j*(28) --400 + j*(57) --91 + j*(47) --243 + j*(-143) --141 + j*(37) -216 + j*(79) --63 + j*(23) -1 + j*(-54) --258 + j*(254) --26 + j*(-60) -203 + j*(132) -260 + j*(57) --13 + j*(209) -46 + j*(-156) -55 + j*(294) --322 + j*(-226) -101 + j*(118) -163 + j*(-56) -189 + j*(-47) -209 + j*(-12) -140 + j*(146) --81 + j*(282) --238 + j*(20) --152 + j*(180) --140 + j*(-190) -146 + j*(-109) --63 + j*(-105) -49 + j*(6) --37 + j*(-4) -25 + j*(-124) -21 + j*(-45) -214 + j*(209) -6 + j*(-68) --174 + j*(189) -79 + j*(-70) -103 + j*(167) --227 + j*(171) --139 + j*(-351) -245 + j*(-18) --17 + j*(325) --490 + j*(-99) -301 + j*(81) -218 + j*(-4) -32 + j*(-16) -274 + j*(-51) --122 + j*(21) -95 + j*(7) -295 + j*(-64) --18 + j*(245) --122 + j*(47) -86 + j*(7) -122 + j*(-269) -35 + j*(-125) -29 + j*(34) -187 + j*(53) --205 + j*(-129) --29 + j*(264) -93 + j*(-149) --36 + j*(-107) --225 + j*(255) -371 + j*(-177) --142 + j*(11) --230 + j*(217) --100 + j*(-18) -40 + j*(163) --57 + j*(-83) --293 + j*(316) --86 + j*(-52) -111 + j*(21) --91 + j*(-33) --121 + j*(-47) --133 + j*(-12) --7 + j*(124) --154 + j*(-30) --74 + j*(-225) -14 + j*(-54) --176 + j*(252) --217 + j*(-202) -65 + j*(-130) -144 + j*(192) -209 + j*(-108) -11 + j*(264) --10 + j*(-170) --9 + j*(-129) --90 + j*(-147) -108 + j*(44) --19 + j*(99) --256 + j*(53) -301 + j*(-249) --164 + j*(124) --231 + j*(-234) --64 + j*(-274) --40 + j*(28) -54 + j*(-162) -99 + j*(72) -78 + j*(135) --120 + j*(165) -123 + j*(-209) --23 + j*(306) --133 + j*(-216) --35 + j*(121) -260 + j*(264) -134 + j*(25) --32 + j*(255) --245 + j*(-106) --35 + j*(-74) -192 + j*(-317) --175 + j*(286) --25 + j*(-154) --146 + j*(29) -40 + j*(181) --10 + j*(119) --47 + j*(-151) -161 + j*(105) -205 + j*(-194) --270 + j*(28) --18 + j*(1) --131 + j*(125) -176 + j*(-149) -21 + j*(80) -13 + j*(-211) --273 + j*(123) --182 + j*(176) --247 + j*(87) -72 + j*(141) --78 + j*(-149) --96 + j*(158) --235 + j*(-231) --2 + j*(194) -44 + j*(192) --6 + j*(-80) -37 + j*(-110) --148 + j*(-328) --267 + j*(251) -168 + j*(175) -97 + j*(30) --54 + j*(-40) --168 + j*(89) --72 + j*(-33) --68 + j*(-249) --100 + j*(48) -64 + j*(-49) --161 + j*(150) -31 + j*(137) -27 + j*(-29) -243 + j*(28) --22 + j*(-22) -94 + j*(22) --238 + j*(-66) --6 + j*(-87) --109 + j*(99) -184 + j*(204) --250 + j*(-3) -263 + j*(-223) --428 + j*(-54) -155 + j*(-169) -43 + j*(-285) --182 + j*(-257) -71 + j*(-199) -37 + j*(-130) -51 + j*(41) --75 + j*(-66) --95 + j*(105) -33 + j*(-125) --195 + j*(-38) -281 + j*(-226) --16 + j*(-185) -85 + j*(64) --13 + j*(-259) -25 + j*(-330) -342 + j*(218) -91 + j*(331) --245 + j*(-42) --240 + j*(224) --66 + j*(-228) --37 + j*(182) -128 + j*(214) -109 + j*(129) --244 + j*(135) -237 + j*(178) --14 + j*(-62) --26 + j*(11) --275 + j*(-257) -99 + j*(-284) -97 + j*(501) --361 + j*(-166) --69 + j*(96) --25 + j*(-182) -227 + j*(94) -157 + j*(445) --29 + j*(-144) -368 + j*(-150) -40 + j*(-45) --46 + j*(143) -56 + j*(-343) --4 + j*(62) -272 + j*(-117) --291 + j*(83) --387 + j*(111) --93 + j*(-18) -250 + j*(-13) --193 + j*(48) -59 + j*(706) -264 + j*(228) -33 + j*(-315) -404 + j*(-147) --79 + j*(1) --296 + j*(-135) --250 + j*(-423) -36 + j*(27) -64 + j*(-75) --195 + j*(-198) --51 + j*(-132) --103 + j*(204) -261 + j*(-173) -44 + j*(-41) --77 + j*(55) --18 + j*(-163) --241 + j*(106) -76 + j*(-120) -346 + j*(323) --168 + j*(-142) -83 + j*(-60) -30 + j*(262) -250 + j*(-2) --146 + j*(-236) --66 + j*(-267) --28 + j*(-10) --58 + j*(-90) -139 + j*(-92) -143 + j*(105) --192 + j*(525) -119 + j*(158) -15 + j*(-111) -25 + j*(-11) --103 + j*(144) --283 + j*(-173) -356 + j*(-98) --53 + j*(274) --1 + j*(94) -204 + j*(91) -127 + j*(-239) --121 + j*(62) --2 + j*(145) -134 + j*(-30) --77 + j*(320) -148 + j*(27) --372 + j*(-130) -274 + j*(8) -71 + j*(-80) -333 + j*(-121) --292 + j*(-135) -205 + j*(479) --37 + j*(-227) -62 + j*(61) -83 + j*(-158) -279 + j*(-41) -31 + j*(132) --54 + j*(472) --214 + j*(261) -148 + j*(-199) -73 + j*(499) -78 + j*(-23) -108 + j*(-213) -25 + j*(-210) -12 + j*(315) --42 + j*(63) --86 + j*(119) -76 + j*(246) -211 + j*(-351) --42 + j*(-95) --47 + j*(156) -37 + j*(144) --249 + j*(-69) --274 + j*(-139) -110 + j*(-13) --269 + j*(21) -173 + j*(-42) -55 + j*(110) --130 + j*(-165) --187 + j*(-255) --53 + j*(-127) -262 + j*(-6) -16 + j*(28) --292 + j*(-63) --219 + j*(-310) --93 + j*(404) --34 + j*(60) -78 + j*(-91) --74 + j*(146) --162 + j*(-143) --127 + j*(64) -400 + j*(-46) --81 + j*(373) -408 + j*(-136) --45 + j*(13) --161 + j*(-119) -39 + j*(310) -50 + j*(-281) --64 + j*(4) -305 + j*(69) --59 + j*(45) --137 + j*(416) -56 + j*(-198) -273 + j*(-237) -141 + j*(173) -18 + j*(-60) --41 + j*(225) -236 + j*(297) -80 + j*(18) --388 + j*(277) -180 + j*(-110) --67 + j*(-74) --215 + j*(-148) -8 + j*(242) --293 + j*(-219) --88 + j*(81) -117 + j*(-18) -78 + j*(-66) --80 + j*(-532) -141 + j*(21) --211 + j*(-342) --204 + j*(-96) --131 + j*(-108) -124 + j*(-298) -43 + j*(-57) -13 + j*(220) -206 + j*(33) -43 + j*(-93) --8 + j*(-59) -300 + j*(-127) --181 + j*(218) -110 + j*(-66) -148 + j*(372) --188 + j*(66) -28 + j*(-363) --211 + j*(37) -110 + j*(22) --132 + j*(110) --122 + j*(-109) --124 + j*(241) --132 + j*(8) --109 + j*(-1) --186 + j*(-119) --202 + j*(-288) --29 + j*(143) -115 + j*(-307) --51 + j*(-297) --89 + j*(-169) -26 + j*(299) -66 + j*(76) --62 + j*(133) --110 + j*(-276) -410 + j*(-174) --315 + j*(-66) --5 + j*(165) -175 + j*(-115) --167 + j*(-226) --148 + j*(273) -197 + j*(-184) --124 + j*(159) -285 + j*(-25) -221 + j*(13) -102 + j*(-86) -56 + j*(183) --1 + j*(-25) -71 + j*(-21) --281 + j*(156) --62 + j*(40) --3 + j*(153) -159 + j*(323) --15 + j*(173) --105 + j*(-136) -1 + j*(25) -7 + j*(154) --380 + j*(-333) --211 + j*(293) -11 + j*(-76) --137 + j*(-161) -44 + j*(-180) -378 + j*(-2) -322 + j*(-284) -217 + j*(34) -107 + j*(161) --20 + j*(156) -36 + j*(-98) --142 + j*(11) -117 + j*(105) -51 + j*(-16) -253 + j*(-144) --33 + j*(-183) --190 + j*(-316) --55 + j*(207) --121 + j*(440) --301 + j*(-78) --73 + j*(-63) -95 + j*(-9) --110 + j*(196) -329 + j*(-70) --90 + j*(34) --246 + j*(177) --52 + j*(-62) -40 + j*(-156) -13 + j*(67) --311 + j*(129) -101 + j*(88) --107 + j*(107) --245 + j*(-196) --18 + j*(216) -126 + j*(161) --21 + j*(194) --64 + j*(-221) -40 + j*(-85) -107 + j*(168) -24 + j*(84) --122 + j*(15) --183 + j*(-73) -133 + j*(-38) --105 + j*(37) --154 + j*(35) -100 + j*(150) -500 + j*(-12) -115 + j*(4) -290 + j*(41) -243 + j*(-122) --17 + j*(-80) -49 + j*(-163) --144 + j*(-378) --375 + j*(-136) -35 + j*(-108) --19 + j*(-320) --138 + j*(-10) -169 + j*(-57) --212 + j*(114) -375 + j*(-63) --171 + j*(117) -205 + j*(-184) --233 + j*(77) -74 + j*(-168) --19 + j*(142) --77 + j*(124) --53 + j*(-18) -51 + j*(-360) --148 + j*(-2) -226 + j*(-23) -61 + j*(-165) --67 + j*(-58) -278 + j*(-44) -412 + j*(-89) --74 + j*(-80) --32 + j*(151) --106 + j*(226) -190 + j*(-121) --247 + j*(-198) -36 + j*(-45) --82 + j*(311) -115 + j*(1) --379 + j*(4) -172 + j*(38) --187 + j*(134) --156 + j*(-50) --126 + j*(-186) --20 + j*(-57) -312 + j*(-151) --218 + j*(180) --42 + j*(-283) --98 + j*(112) -145 + j*(57) -21 + j*(-140) -223 + j*(119) -71 + j*(-245) -134 + j*(243) --80 + j*(252) --33 + j*(-303) --5 + j*(84) --161 + j*(-120) --268 + j*(-303) --62 + j*(-187) --151 + j*(-25) -164 + j*(-359) --130 + j*(293) --35 + j*(-424) --359 + j*(368) -79 + j*(235) -344 + j*(-23) --98 + j*(-108) -157 + j*(221) --342 + j*(-91) -35 + j*(-46) --111 + j*(-6) -119 + j*(-21) --146 + j*(144) -167 + j*(36) --347 + j*(-155) -238 + j*(4) -37 + j*(249) --159 + j*(-104) --79 + j*(348) -58 + j*(199) --2 + j*(-211) -347 + j*(73) -28 + j*(-163) --150 + j*(143) --34 + j*(-91) --53 + j*(390) --163 + j*(135) --274 + j*(-153) -69 + j*(194) -131 + j*(-263) --412 + j*(177) --86 + j*(-347) -52 + j*(-134) -264 + j*(84) -91 + j*(161) --64 + j*(-158) --34 + j*(-561) --90 + j*(-67) --67 + j*(-100) -117 + j*(-13) -16 + j*(-20) -144 + j*(128) -378 + j*(86) -96 + j*(-165) --218 + j*(-17) -78 + j*(281) -221 + j*(-293) -161 + j*(257) -170 + j*(98) --197 + j*(82) --374 + j*(211) -331 + j*(-194) -166 + j*(-191) -233 + j*(-141) -21 + j*(-85) --260 + j*(20) --378 + j*(212) -54 + j*(337) -217 + j*(342) -85 + j*(87) --145 + j*(105) -310 + j*(152) --69 + j*(137) -138 + j*(-73) --54 + j*(-25) --87 + j*(-16) -133 + j*(-134) -137 + j*(-126) -133 + j*(34) --137 + j*(7) -325 + j*(0) --141 + j*(185) -89 + j*(-3) --195 + j*(-91) -137 + j*(121) --211 + j*(-122) --57 + j*(88) --246 + j*(-217) -130 + j*(-260) --226 + j*(-54) --120 + j*(-135) -332 + j*(-94) --28 + j*(-57) -274 + j*(91) -49 + j*(-37) -173 + j*(119) -141 + j*(46) --79 + j*(-44) -95 + j*(-190) --48 + j*(-25) --94 + j*(-227) --261 + j*(-165) --60 + j*(87) --52 + j*(93) --146 + j*(-202) -24 + j*(-27) -110 + j*(-47) --88 + j*(-157) --37 + j*(305) --108 + j*(11) --304 + j*(-94) -0 + j*(86) -308 + j*(91) --243 + j*(121) -156 + j*(-95) -59 + j*(-81) --126 + j*(138) -177 + j*(32) --28 + j*(-145) -140 + j*(306) -44 + j*(-207) -4 + j*(-25) -69 + j*(91) --279 + j*(-240) --209 + j*(-70) --236 + j*(-49) --266 + j*(119) --29 + j*(40) -246 + j*(-281) --91 + j*(170) --66 + j*(-84) -257 + j*(-77) -169 + j*(205) --49 + j*(-64) -129 + j*(235) -153 + j*(-272) -25 + j*(167) -45 + j*(-199) -160 + j*(-20) --114 + j*(139) --255 + j*(-46) -276 + j*(-267) -145 + j*(72) -52 + j*(-160) --346 + j*(13) --107 + j*(203) --278 + j*(286) --279 + j*(300) --83 + j*(-110) -40 + j*(69) -77 + j*(-233) -177 + j*(55) -135 + j*(-241) -25 + j*(30) -100 + j*(81) -293 + j*(-232) --99 + j*(206) --428 + j*(232) -135 + j*(-12) -227 + j*(-14) -64 + j*(-328) -45 + j*(-37) --197 + j*(-253) -126 + j*(103) -113 + j*(4) --6 + j*(-86) -11 + j*(130) -45 + j*(-115) -3 + j*(141) --295 + j*(228) --132 + j*(-34) -328 + j*(7) --10 + j*(-414) -174 + j*(145) -108 + j*(-86) --244 + j*(10) --16 + j*(-123) --77 + j*(-84) -98 + j*(-405) -131 + j*(-130) --358 + j*(276) --59 + j*(-46) --523 + j*(75) --109 + j*(-81) --3 + j*(47) -197 + j*(207) -180 + j*(-38) -286 + j*(20) --299 + j*(-468) -107 + j*(-59) --273 + j*(-121) --14 + j*(-8) --58 + j*(-18) -123 + j*(266) -82 + j*(91) --117 + j*(70) -328 + j*(213) -165 + j*(-51) -234 + j*(-64) -192 + j*(-102) -25 + j*(81) --20 + j*(30) -54 + j*(-132) --57 + j*(91) -6 + j*(101) --6 + j*(66) -101 + j*(-100) -95 + j*(49) -160 + j*(272) -173 + j*(-262) -134 + j*(106) --59 + j*(9) -287 + j*(259) --105 + j*(-248) --156 + j*(-380) --287 + j*(141) --98 + j*(-66) -16 + j*(52) -63 + j*(103) -35 + j*(128) --104 + j*(-173) -86 + j*(226) -33 + j*(92) -149 + j*(49) -77 + j*(-76) --126 + j*(23) --417 + j*(13) --241 + j*(152) --30 + j*(-218) --176 + j*(-159) -93 + j*(105) -150 + j*(79) -163 + j*(66) -209 + j*(27) -21 + j*(-233) --144 + j*(16) -130 + j*(16) -322 + j*(192) --192 + j*(50) -230 + j*(-177) -98 + j*(-100) --127 + j*(-187) --153 + j*(33) -246 + j*(-37) -147 + j*(-141) --211 + j*(202) -265 + j*(177) -137 + j*(43) -538 + j*(218) --583 + j*(125) -52 + j*(42) -165 + j*(-288) --336 + j*(368) -175 + j*(-170) --441 + j*(240) -149 + j*(129) --235 + j*(148) --38 + j*(-30) --76 + j*(-467) -213 + j*(-158) -16 + j*(-30) --51 + j*(-43) --37 + j*(202) -16 + j*(-47) -199 + j*(-107) --161 + j*(105) --114 + j*(175) --57 + j*(-124) -13 + j*(-55) -148 + j*(-185) --76 + j*(-110) --127 + j*(95) -629 + j*(323) -75 + j*(-234) --103 + j*(-122) -88 + j*(-91) --88 + j*(-165) --19 + j*(47) --55 + j*(197) --31 + j*(-1) --206 + j*(52) --128 + j*(108) -218 + j*(58) --254 + j*(-185) --171 + j*(-105) -54 + j*(161) -31 + j*(41) --173 + j*(210) --4 + j*(45) --276 + j*(33) --270 + j*(92) -136 + j*(-105) -71 + j*(-156) -21 + j*(298) --134 + j*(284) -138 + j*(8) --62 + j*(483) --495 + j*(62) --231 + j*(-243) --231 + j*(139) -117 + j*(56) --121 + j*(-21) --205 + j*(-68) -46 + j*(-148) -272 + j*(-71) -22 + j*(-134) --88 + j*(170) -227 + j*(-7) -194 + j*(-216) --105 + j*(-83) -35 + j*(-38) --62 + j*(-11) --25 + j*(-57) --165 + j*(334) -59 + j*(-33) --66 + j*(54) -40 + j*(-2) --113 + j*(87) -61 + j*(-245) -47 + j*(-117) -71 + j*(-265) -177 + j*(298) -28 + j*(-226) -255 + j*(-117) -91 + j*(-88) --136 + j*(-4) -122 + j*(162) --66 + j*(156) --35 + j*(190) -112 + j*(233) -37 + j*(-218) --210 + j*(136) --117 + j*(199) --121 + j*(21) -21 + j*(42) --133 + j*(-1) -261 + j*(67) -274 + j*(-211) -117 + j*(109) --59 + j*(-67) --262 + j*(-350) -49 + j*(29) --164 + j*(-71) --7 + j*(148) --145 + j*(-25) -110 + j*(66) --63 + j*(-243) -45 + j*(371) -70 + j*(111) --69 + j*(-186) -170 + j*(-42) -7 + j*(18) --207 + j*(-57) -52 + j*(-413) -198 + j*(303) -42 + j*(-6) -162 + j*(131) --103 + j*(-41) --161 + j*(75) --18 + j*(137) -63 + j*(192) -317 + j*(201) --246 + j*(-300) -81 + j*(194) -410 + j*(-223) -168 + j*(109) --35 + j*(-319) --192 + j*(-197) --59 + j*(293) --138 + j*(-165) --124 + j*(-127) -161 + j*(-1) --225 + j*(252) -1 + j*(6) -66 + j*(-69) --95 + j*(33) -33 + j*(-151) --37 + j*(332) -38 + j*(-76) -113 + j*(-186) --132 + j*(-240) --67 + j*(125) --87 + j*(-121) --51 + j*(11) -436 + j*(-5) -5 + j*(4) -319 + j*(-137) -26 + j*(-105) --58 + j*(251) -49 + j*(-78) --159 + j*(-67) -82 + j*(177) --57 + j*(-229) -150 + j*(54) -39 + j*(-21) -23 + j*(-116) -83 + j*(154) --116 + j*(-146) -35 + j*(35) -129 + j*(66) --139 + j*(-21) --247 + j*(-43) -66 + j*(201) --48 + j*(-122) -115 + j*(-10) -59 + j*(-78) --135 + j*(325) -186 + j*(94) -321 + j*(64) --243 + j*(-163) --21 + j*(219) -92 + j*(18) --138 + j*(-308) -116 + j*(-98) --293 + j*(-9) --483 + j*(-84) --51 + j*(99) --34 + j*(-354) -44 + j*(124) --294 + j*(-137) --216 + j*(-135) -122 + j*(-151) --213 + j*(-472) --165 + j*(134) -184 + j*(-23) --178 + j*(-216) -71 + j*(-120) -35 + j*(107) --88 + j*(115) -394 + j*(-350) -261 + j*(-11) -18 + j*(69) -94 + j*(-419) -57 + j*(-196) --62 + j*(-337) --86 + j*(-111) --284 + j*(-116) --260 + j*(-87) --50 + j*(-44) -266 + j*(117) -37 + j*(-122) --249 + j*(80) -59 + j*(108) -151 + j*(-60) --13 + j*(60) -44 + j*(18) -233 + j*(108) -305 + j*(-136) --246 + j*(-6) --122 + j*(-25) --132 + j*(-170) --2 + j*(34) -93 + j*(-3) --87 + j*(93) -190 + j*(16) -192 + j*(314) -122 + j*(184) -185 + j*(272) --151 + j*(-226) -58 + j*(181) --39 + j*(-141) --36 + j*(-188) --96 + j*(158) --15 + j*(-67) --89 + j*(-180) -225 + j*(-103) -233 + j*(-173) -169 + j*(-23) --7 + j*(-106) -165 + j*(-170) --112 + j*(-73) --428 + j*(-307) --46 + j*(458) -235 + j*(-32) -255 + j*(268) -117 + j*(-291) -45 + j*(99) --194 + j*(-226) -103 + j*(-133) -107 + j*(-172) --18 + j*(-30) --3 + j*(-140) --146 + j*(-248) -127 + j*(12) --25 + j*(158) -199 + j*(170) -334 + j*(103) -38 + j*(218) --57 + j*(270) --229 + j*(6) --359 + j*(288) -100 + j*(107) -168 + j*(-62) -127 + j*(-205) --25 + j*(-194) -60 + j*(-344) --257 + j*(-204) -205 + j*(47) -63 + j*(6) -286 + j*(-307) -190 + j*(46) --404 + j*(24) -117 + j*(74) -17 + j*(-186) --358 + j*(70) --447 + j*(50) -317 + j*(-105) --300 + j*(-24) --170 + j*(-203) --18 + j*(-217) -401 + j*(59) --368 + j*(74) -227 + j*(-190) -150 + j*(6) -431 + j*(-158) -251 + j*(-187) --59 + j*(-158) --281 + j*(-172) --202 + j*(-277) -226 + j*(-39) --74 + j*(-202) -32 + j*(257) --249 + j*(-104) --342 + j*(18) --42 + j*(276) -20 + j*(-174) --58 + j*(55) -107 + j*(13) -62 + j*(110) --88 + j*(-8) --53 + j*(105) --98 + j*(-82) -40 + j*(-269) --168 + j*(146) --91 + j*(-114) --34 + j*(-367) --131 + j*(29) --137 + j*(58) --79 + j*(-44) --255 + j*(-166) --56 + j*(-137) --202 + j*(-279) -63 + j*(21) -383 + j*(-27) -19 + j*(252) -28 + j*(-19) --69 + j*(16) --136 + j*(275) -395 + j*(-137) -107 + j*(351) --59 + j*(279) --196 + j*(-284) -165 + j*(45) -68 + j*(-99) -404 + j*(303) --238 + j*(-18) -245 + j*(-265) -59 + j*(303) --35 + j*(-162) --453 + j*(-248) --334 + j*(163) --344 + j*(474) -6 + j*(-3) --201 + j*(269) -134 + j*(-625) -441 + j*(165) -89 + j*(-500) -170 + j*(475) -499 + j*(38) --637 + j*(-19) --191 + j*(444) --91 + j*(369) -129 + j*(270) -103 + j*(112) --11 + j*(255) -452 + j*(323) --325 + j*(-290) -485 + j*(-310) -238 + j*(-470) --148 + j*(-462) --323 + j*(-13) -175 + j*(-445) -381 + j*(-290) --479 + j*(-116) --348 + j*(245) -274 + j*(356) -54 + j*(233) -29 + j*(-153) -556 + j*(420) -88 + j*(27) --383 + j*(83) --45 + j*(606) -44 + j*(245) --272 + j*(-347) --452 + j*(-182) -35 + j*(165) -179 + j*(-366) --275 + j*(280) -294 + j*(-340) --371 + j*(200) --260 + j*(410) -210 + j*(-378) --54 + j*(371) -276 + j*(352) -524 + j*(361) -228 + j*(-63) --296 + j*(-247) -590 + j*(-115) --23 + j*(234) -71 + j*(255) --517 + j*(-235) -75 + j*(450) -89 + j*(-307) -180 + j*(313) -247 + j*(448) -197 + j*(98) -163 + j*(160) --272 + j*(182) -177 + j*(35) --397 + j*(201) --122 + j*(-438) --453 + j*(-634) --269 + j*(-228) --167 + j*(-662) -262 + j*(-260) -95 + j*(225) -477 + j*(356) --121 + j*(216) -77 + j*(161) --372 + j*(-286) --375 + j*(-124) --553 + j*(269) --320 + j*(-297) -158 + j*(-262) -456 + j*(-231) --440 + j*(-190) --234 + j*(182) -47 + j*(269) -122 + j*(54) --106 + j*(409) --245 + j*(228) --1 + j*(196) --120 + j*(-257) --173 + j*(80) --477 + j*(-206) -83 + j*(472) --611 + j*(176) -47 + j*(239) --474 + j*(89) -606 + j*(251) --338 + j*(451) -176 + j*(-199) --354 + j*(-397) --89 + j*(-178) -124 + j*(-152) -172 + j*(199) --367 + j*(-373) -461 + j*(-211) -341 + j*(63) -8 + j*(172) --398 + j*(109) -6 + j*(132) -422 + j*(139) --229 + j*(-193) --118 + j*(163) --74 + j*(105) --80 + j*(199) -622 + j*(-87) -206 + j*(-106) -62 + j*(117) --354 + j*(235) --129 + j*(-91) -413 + j*(430) --419 + j*(107) -236 + j*(187) --494 + j*(-507) --118 + j*(340) --25 + j*(335) -528 + j*(-308) --499 + j*(-47) --11 + j*(95) --275 + j*(259) --395 + j*(128) -35 + j*(264) --16 + j*(-187) -127 + j*(-355) -358 + j*(323) -517 + j*(13) --177 + j*(7) --335 + j*(-337) --570 + j*(210) -290 + j*(183) --529 + j*(-514) --87 + j*(272) --121 + j*(298) --682 + j*(-194) --99 + j*(228) --216 + j*(-336) -433 + j*(-46) --585 + j*(-307) --225 + j*(136) --92 + j*(-79) --38 + j*(413) --22 + j*(201) -272 + j*(311) -258 + j*(67) -19 + j*(-434) -417 + j*(343) --291 + j*(145) --197 + j*(173) -539 + j*(430) --530 + j*(-280) --69 + j*(276) --442 + j*(71) --363 + j*(-136) --390 + j*(245) --186 + j*(326) -426 + j*(217) -83 + j*(467) --613 + j*(281) -146 + j*(-255) -37 + j*(-203) --504 + j*(49) --48 + j*(-541) -165 + j*(33) --302 + j*(296) --528 + j*(73) --281 + j*(-112) -455 + j*(547) -245 + j*(-219) --552 + j*(-479) --163 + j*(-419) -235 + j*(424) --527 + j*(240) -25 + j*(-750) --203 + j*(-203) --205 + j*(-281) --88 + j*(88) -353 + j*(597) -362 + j*(287) --308 + j*(175) -569 + j*(180) -421 + j*(-441) --382 + j*(76) --40 + j*(180) --81 + j*(235) --308 + j*(169) -364 + j*(-674) --218 + j*(49) -437 + j*(369) -251 + j*(-216) -395 + j*(-381) --255 + j*(113) --411 + j*(300) --109 + j*(83) --132 + j*(512) -194 + j*(336) --83 + j*(283) -340 + j*(-88) -47 + j*(156) --71 + j*(293) -467 + j*(389) -269 + j*(-11) --188 + j*(-217) --266 + j*(220) --368 + j*(402) --394 + j*(153) --148 + j*(-221) -132 + j*(-19) -284 + j*(-238) --255 + j*(-104) --399 + j*(-474) --693 + j*(211) --318 + j*(97) --568 + j*(-313) -206 + j*(10) -339 + j*(-526) --535 + j*(-288) --4 + j*(-254) -537 + j*(140) --313 + j*(377) -59 + j*(164) -257 + j*(258) -387 + j*(-396) -252 + j*(650) -144 + j*(-562) --56 + j*(-597) --163 + j*(377) --89 + j*(488) --245 + j*(-170) --94 + j*(-573) --248 + j*(374) -327 + j*(-499) --438 + j*(89) -228 + j*(-331) -40 + j*(-243) -205 + j*(320) --280 + j*(-1) -380 + j*(-342) --539 + j*(176) -37 + j*(-398) --567 + j*(474) --322 + j*(319) -118 + j*(222) --317 + j*(-47) -304 + j*(-267) -355 + j*(-300) -146 + j*(256) --330 + j*(-215) -23 + j*(435) -354 + j*(83) -231 + j*(90) -152 + j*(-227) --246 + j*(262) --451 + j*(341) --208 + j*(-239) -256 + j*(-187) --474 + j*(-392) -293 + j*(-143) -397 + j*(273) -349 + j*(150) -211 + j*(62) --249 + j*(-354) -76 + j*(213) --129 + j*(-209) --555 + j*(-134) -264 + j*(-363) -457 + j*(-358) --165 + j*(-33) -149 + j*(-256) -190 + j*(136) -182 + j*(190) -371 + j*(287) -252 + j*(56) -395 + j*(391) -308 + j*(-521) -45 + j*(-256) --9 + j*(-543) -323 + j*(407) -486 + j*(-177) --363 + j*(29) -206 + j*(-639) --333 + j*(-112) -71 + j*(-152) -21 + j*(-375) -154 + j*(39) --103 + j*(-450) --281 + j*(-57) --215 + j*(428) --332 + j*(-16) -349 + j*(-7) --145 + j*(-528) -226 + j*(295) -472 + j*(-151) -56 + j*(241) -144 + j*(75) --641 + j*(-214) -316 + j*(303) --523 + j*(-491) -504 + j*(373) -170 + j*(419) --469 + j*(-817) -76 + j*(163) -204 + j*(-40) --467 + j*(-346) --181 + j*(93) --25 + j*(-513) -204 + j*(446) -525 + j*(229) --499 + j*(383) --91 + j*(288) -33 + j*(-115) -8 + j*(-433) --238 + j*(-446) -156 + j*(496) -207 + j*(17) --271 + j*(-318) -287 + j*(-330) --212 + j*(-262) --62 + j*(-20) -617 + j*(157) --40 + j*(-72) --256 + j*(-126) -313 + j*(-422) --209 + j*(23) -433 + j*(-441) -175 + j*(-378) --223 + j*(16) --1 + j*(-623) -441 + j*(-211) --243 + j*(-511) --370 + j*(-292) --114 + j*(-321) --347 + j*(-197) --501 + j*(-327) -57 + j*(-296) --231 + j*(241) -148 + j*(68) --516 + j*(391) -250 + j*(-153) --300 + j*(-183) --9 + j*(-402) -332 + j*(197) -209 + j*(280) -115 + j*(-447) --167 + j*(66) -455 + j*(105) -307 + j*(98) -409 + j*(-368) -37 + j*(-124) -137 + j*(238) --402 + j*(-307) --319 + j*(-198) -37 + j*(-339) -223 + j*(199) --354 + j*(-160) --3 + j*(401) --11 + j*(30) -377 + j*(-197) --639 + j*(-83) --15 + j*(296) -79 + j*(-421) --197 + j*(-234) --47 + j*(-387) -629 + j*(30) -293 + j*(170) -595 + j*(486) --391 + j*(256) --44 + j*(25) --497 + j*(364) --74 + j*(198) -127 + j*(322) --373 + j*(161) --200 + j*(67) -503 + j*(301) -319 + j*(209) -276 + j*(-260) --539 + j*(-240) --53 + j*(356) -340 + j*(-97) -28 + j*(321) -45 + j*(-135) -1 + j*(-404) -319 + j*(-499) -457 + j*(-78) -178 + j*(-281) --399 + j*(-112) -124 + j*(-13) --195 + j*(-286) -132 + j*(354) -677 + j*(-21) --69 + j*(-286) -571 + j*(197) -141 + j*(17) -126 + j*(282) -176 + j*(611) -419 + j*(-260) -202 + j*(-305) -196 + j*(-390) --696 + j*(547) -226 + j*(-73) -187 + j*(537) --245 + j*(276) --508 + j*(139) -364 + j*(235) -438 + j*(-310) -284 + j*(-198) --246 + j*(616) -346 + j*(-528) -190 + j*(365) -279 + j*(310) --286 + j*(287) --128 + j*(-385) --150 + j*(461) -305 + j*(81) --167 + j*(305) -177 + j*(310) --1 + j*(-93) --322 + j*(450) --278 + j*(-342) -549 + j*(328) --168 + j*(540) -351 + j*(-178) -217 + j*(314) --275 + j*(300) -163 + j*(-137) --153 + j*(-810) --314 + j*(457) -279 + j*(-263) -157 + j*(-163) -622 + j*(-212) -70 + j*(-303) -275 + j*(-532) -321 + j*(409) -134 + j*(293) --91 + j*(-387) -272 + j*(127) --312 + j*(-547) --226 + j*(-198) --518 + j*(583) -117 + j*(218) -658 + j*(19) -317 + j*(691) --420 + j*(193) -62 + j*(-383) --79 + j*(-174) -74 + j*(348) -354 + j*(-148) --478 + j*(-88) -393 + j*(-581) -282 + j*(16) -214 + j*(416) --163 + j*(-387) -226 + j*(-209) -44 + j*(-400) -345 + j*(-215) --203 + j*(-110) -269 + j*(301) --269 + j*(75) -199 + j*(471) --320 + j*(1) --648 + j*(-421) -245 + j*(-436) --57 + j*(183) --571 + j*(21) --403 + j*(158) -427 + j*(218) --327 + j*(-246) -529 + j*(459) -150 + j*(127) --418 + j*(-54) -412 + j*(369) -116 + j*(-91) -395 + j*(296) -301 + j*(276) -566 + j*(285) -15 + j*(-486) -267 + j*(511) --98 + j*(-312) --190 + j*(-24) --30 + j*(-380) --484 + j*(-349) --109 + j*(85) --43 + j*(-262) -320 + j*(355) --552 + j*(-317) --95 + j*(250) -358 + j*(277) --62 + j*(-587) -128 + j*(-55) --302 + j*(127) --338 + j*(-502) --90 + j*(-230) --271 + j*(-47) -638 + j*(-255) -330 + j*(-83) --233 + j*(421) --182 + j*(-139) --32 + j*(405) -296 + j*(157) -28 + j*(216) -129 + j*(1) --267 + j*(-117) --310 + j*(-152) --390 + j*(-285) -389 + j*(371) -199 + j*(165) -120 + j*(45) -530 + j*(354) --42 + j*(-301) -368 + j*(-213) --28 + j*(-317) --89 + j*(-516) --32 + j*(213) -218 + j*(105) --168 + j*(293) --261 + j*(225) -158 + j*(221) --180 + j*(-234) -236 + j*(383) --63 + j*(-86) -319 + j*(-243) -265 + j*(60) --63 + j*(149) -191 + j*(-45) --172 + j*(202) --212 + j*(616) --405 + j*(387) --325 + j*(19) --18 + j*(149) --594 + j*(-148) --387 + j*(460) --368 + j*(469) -407 + j*(310) --475 + j*(6) --474 + j*(30) --553 + j*(331) --99 + j*(-116) -265 + j*(-308) -188 + j*(-201) -64 + j*(-253) --30 + j*(-274) --364 + j*(322) -309 + j*(-317) --293 + j*(223) -197 + j*(-407) -433 + j*(-237) --73 + j*(37) -392 + j*(373) --235 + j*(-14) -425 + j*(-168) --192 + j*(49) -15 + j*(-447) -61 + j*(202) -374 + j*(-368) -393 + j*(-243) -383 + j*(-417) -214 + j*(-48) --228 + j*(148) --298 + j*(-249) -55 + j*(-243) -269 + j*(-70) -230 + j*(85) -402 + j*(-211) --491 + j*(-202) --465 + j*(-66) -556 + j*(352) -105 + j*(473) -358 + j*(-113) --377 + j*(244) --344 + j*(-247) --160 + j*(233) -437 + j*(-361) -288 + j*(184) -94 + j*(-404) --11 + j*(205) --216 + j*(-250) --11 + j*(-221) --1 + j*(-287) -269 + j*(-443) -244 + j*(-533) --298 + j*(-8) --180 + j*(109) -248 + j*(479) -213 + j*(124) -358 + j*(541) --181 + j*(-170) --250 + j*(187) -117 + j*(-116) --319 + j*(226) -206 + j*(124) --320 + j*(-134) -241 + j*(518) --218 + j*(6) --407 + j*(-465) -93 + j*(479) --550 + j*(275) -112 + j*(623) --153 + j*(102) --38 + j*(-216) -125 + j*(-53) -243 + j*(-223) --298 + j*(-80) -358 + j*(153) --172 + j*(99) --166 + j*(-334) --24 + j*(136) --269 + j*(83) --16 + j*(141) --81 + j*(-37) -288 + j*(-160) -76 + j*(-252) -15 + j*(-38) -52 + j*(-147) --139 + j*(-18) --134 + j*(163) --214 + j*(-61) --187 + j*(259) -317 + j*(-68) --102 + j*(-43) --310 + j*(-237) -28 + j*(-4) --106 + j*(21) -106 + j*(-231) --339 + j*(50) -30 + j*(-218) --42 + j*(-162) --235 + j*(-288) --110 + j*(-78) -95 + j*(413) --305 + j*(67) -238 + j*(279) -124 + j*(196) --105 + j*(-66) --495 + j*(-67) -190 + j*(62) --241 + j*(-206) -99 + j*(3) --175 + j*(-147) -78 + j*(-20) --103 + j*(-211) --167 + j*(-285) -54 + j*(-207) -88 + j*(11) -21 + j*(35) --62 + j*(13) -317 + j*(199) -113 + j*(122) --373 + j*(252) -94 + j*(-60) -35 + j*(117) --180 + j*(194) --21 + j*(81) -21 + j*(87) --96 + j*(-382) --185 + j*(100) --463 + j*(392) --78 + j*(-193) -312 + j*(-53) --126 + j*(-49) -217 + j*(52) --62 + j*(187) --66 + j*(76) --37 + j*(-108) -82 + j*(-197) -37 + j*(-62) -45 + j*(-120) -83 + j*(-103) --91 + j*(165) --77 + j*(90) --224 + j*(160) --145 + j*(67) -230 + j*(-203) -143 + j*(54) -223 + j*(163) -42 + j*(-2) -39 + j*(-60) -2 + j*(235) -216 + j*(274) -34 + j*(-177) -138 + j*(-175) --220 + j*(-211) --15 + j*(36) --23 + j*(300) -91 + j*(282) --3 + j*(166) --193 + j*(-123) --103 + j*(27) --5 + j*(28) --121 + j*(60) -243 + j*(-2) -145 + j*(-293) --127 + j*(415) --83 + j*(267) --95 + j*(47) -35 + j*(96) --53 + j*(-190) -18 + j*(-146) --76 + j*(165) -131 + j*(-103) -5 + j*(-44) -57 + j*(-155) --339 + j*(-77) -8 + j*(-175) -157 + j*(16) -119 + j*(149) --276 + j*(-163) -23 + j*(107) -69 + j*(-146) -135 + j*(-267) -94 + j*(103) -27 + j*(57) -29 + j*(164) -24 + j*(-66) --98 + j*(-193) --9 + j*(51) --144 + j*(-103) -346 + j*(59) -377 + j*(262) -82 + j*(-277) -60 + j*(143) -88 + j*(107) -192 + j*(-120) --146 + j*(-35) --455 + j*(107) -91 + j*(236) -181 + j*(45) -90 + j*(64) --56 + j*(-392) --73 + j*(-43) -99 + j*(9) --270 + j*(-105) --62 + j*(-435) --349 + j*(-218) --298 + j*(-86) --137 + j*(-90) -76 + j*(28) -235 + j*(-12) --63 + j*(-119) --180 + j*(71) --165 + j*(218) --96 + j*(-2) -1 + j*(-390) --1 + j*(5) -59 + j*(-162) -33 + j*(171) -9 + j*(-5) -387 + j*(-101) --89 + j*(94) --168 + j*(-165) --230 + j*(-2) -446 + j*(198) -209 + j*(161) -172 + j*(153) -34 + j*(153) -80 + j*(3) --238 + j*(245) --28 + j*(-286) -261 + j*(202) --277 + j*(139) -76 + j*(148) -321 + j*(-148) -5 + j*(-124) -175 + j*(286) --22 + j*(95) -14 + j*(-212) --30 + j*(-224) --52 + j*(-112) -240 + j*(-124) --21 + j*(292) --39 + j*(-235) -81 + j*(262) -3 + j*(-186) -74 + j*(-12) -178 + j*(84) -86 + j*(-62) -238 + j*(-4) -4 + j*(13) -265 + j*(-82) -37 + j*(218) --187 + j*(71) --288 + j*(330) --112 + j*(340) -71 + j*(-57) --62 + j*(81) -18 + j*(96) --84 + j*(132) -10 + j*(162) -97 + j*(4) -50 + j*(308) --25 + j*(442) --136 + j*(187) --161 + j*(109) --50 + j*(54) -210 + j*(-192) -59 + j*(174) --51 + j*(-252) -139 + j*(-155) -280 + j*(156) -32 + j*(-54) -211 + j*(24) --198 + j*(-298) -165 + j*(206) -122 + j*(-144) -30 + j*(119) --21 + j*(281) -74 + j*(-119) --54 + j*(-23) --25 + j*(332) -78 + j*(-199) --125 + j*(-74) -232 + j*(11) --199 + j*(154) -311 + j*(31) -76 + j*(307) -39 + j*(-23) --165 + j*(397) -310 + j*(42) -255 + j*(-36) -276 + j*(-68) --192 + j*(20) --98 + j*(166) -3 + j*(-489) -41 + j*(177) --72 + j*(305) --52 + j*(-67) -66 + j*(-297) -20 + j*(-185) --270 + j*(-66) -15 + j*(-18) --71 + j*(-7) -40 + j*(-203) -199 + j*(-431) -316 + j*(-88) -46 + j*(90) --196 + j*(38) -91 + j*(-21) --1 + j*(169) -96 + j*(36) --76 + j*(-205) -289 + j*(76) --132 + j*(-141) --145 + j*(-97) --1 + j*(171) --51 + j*(182) -19 + j*(-129) -40 + j*(50) --175 + j*(-300) -21 + j*(74) -51 + j*(142) --128 + j*(-64) --43 + j*(-92) -247 + j*(109) --53 + j*(-28) --20 + j*(-168) -47 + j*(331) -8 + j*(-158) --7 + j*(-202) --51 + j*(-9) -49 + j*(66) -26 + j*(67) --157 + j*(-441) -82 + j*(-47) --124 + j*(165) --134 + j*(201) --74 + j*(184) -201 + j*(-29) -85 + j*(-272) -68 + j*(-132) -138 + j*(-243) --44 + j*(170) --154 + j*(-1) --93 + j*(79) -132 + j*(-134) --168 + j*(132) -147 + j*(144) --113 + j*(-10) -88 + j*(124) --267 + j*(25) -63 + j*(-53) -156 + j*(-330) -75 + j*(167) -238 + j*(0) -189 + j*(29) --175 + j*(-159) -110 + j*(-90) --68 + j*(-70) -36 + j*(-15) -6 + j*(-356) -138 + j*(315) -17 + j*(-114) --239 + j*(129) -279 + j*(21) --151 + j*(-25) -103 + j*(-17) -213 + j*(8) --81 + j*(148) --171 + j*(24) --63 + j*(6) -178 + j*(-13) -115 + j*(115) -187 + j*(148) --191 + j*(-442) --9 + j*(218) --60 + j*(101) --64 + j*(191) --21 + j*(-170) -78 + j*(110) --395 + j*(216) -122 + j*(186) --81 + j*(2) --324 + j*(237) -26 + j*(-274) -60 + j*(-154) --54 + j*(-83) -9 + j*(240) --117 + j*(63) --10 + j*(3) -109 + j*(124) -55 + j*(-28) -51 + j*(-1) -293 + j*(-194) --88 + j*(-208) --58 + j*(-27) -48 + j*(117) --287 + j*(97) --105 + j*(-250) --2 + j*(-269) --204 + j*(-248) --189 + j*(-123) --134 + j*(206) --114 + j*(-123) --180 + j*(-58) --320 + j*(-144) --265 + j*(-50) -243 + j*(-311) -48 + j*(25) --69 + j*(-78) --98 + j*(25) --3 + j*(-18) -63 + j*(-254) --182 + j*(-132) -122 + j*(-55) --43 + j*(161) --257 + j*(219) -1 + j*(-32) -417 + j*(64) --131 + j*(199) --215 + j*(-242) -308 + j*(153) -157 + j*(-10) --199 + j*(164) --77 + j*(-54) --68 + j*(76) --22 + j*(-71) -101 + j*(95) --223 + j*(-192) --94 + j*(113) --256 + j*(-165) -420 + j*(131) -62 + j*(0) --168 + j*(95) --69 + j*(-202) -137 + j*(1) -226 + j*(439) -153 + j*(-33) --76 + j*(81) --264 + j*(30) -400 + j*(62) -175 + j*(-37) -343 + j*(-157) --302 + j*(59) -246 + j*(114) -148 + j*(-61) -112 + j*(74) --134 + j*(-46) --243 + j*(41) -255 + j*(-355) --85 + j*(-38) --110 + j*(183) -132 + j*(95) --566 + j*(169) -313 + j*(162) --31 + j*(-28) --245 + j*(442) --64 + j*(-252) -334 + j*(-138) -105 + j*(-85) --135 + j*(16) -123 + j*(-224) -62 + j*(-48) --78 + j*(-16) --272 + j*(74) -66 + j*(222) -49 + j*(269) --255 + j*(-76) --192 + j*(-3) -11 + j*(-50) -168 + j*(293) -76 + j*(110) --43 + j*(99) -187 + j*(61) --340 + j*(-91) --110 + j*(-132) --156 + j*(-99) -149 + j*(103) -203 + j*(-56) -37 + j*(261) --232 + j*(78) -44 + j*(13) -139 + j*(-14) --58 + j*(-137) --52 + j*(-281) --231 + j*(35) -211 + j*(-35) -42 + j*(65) --177 + j*(223) -127 + j*(61) -148 + j*(-34) -101 + j*(224) --8 + j*(91) --49 + j*(157) --174 + j*(-173) --47 + j*(-56) --55 + j*(115) --108 + j*(-19) --147 + j*(-96) --132 + j*(-86) --23 + j*(23) -183 + j*(-191) -265 + j*(107) --83 + j*(306) -50 + j*(239) -137 + j*(-273) -330 + j*(52) --153 + j*(45) --191 + j*(306) -171 + j*(-64) --16 + j*(78) --298 + j*(-16) -94 + j*(410) --125 + j*(65) --154 + j*(112) -81 + j*(69) --151 + j*(-175) -294 + j*(-264) --119 + j*(286) --35 + j*(-293) -49 + j*(221) --77 + j*(-30) --170 + j*(407) --198 + j*(14) --5 + j*(6) -315 + j*(-35) -41 + j*(282) -241 + j*(25) -148 + j*(168) -34 + j*(196) --248 + j*(161) -129 + j*(-66) -296 + j*(-42) --45 + j*(119) --87 + j*(141) -86 + j*(90) -66 + j*(-45) --13 + j*(-129) -273 + j*(-148) --6 + j*(-82) -227 + j*(-168) -32 + j*(-130) -59 + j*(-64) -11 + j*(99) --91 + j*(-40) -208 + j*(-91) -218 + j*(69) -48 + j*(-325) -6 + j*(47) -6 + j*(-215) --250 + j*(-271) --98 + j*(36) --180 + j*(-23) --371 + j*(-30) --242 + j*(-11) -191 + j*(6) -70 + j*(-28) --90 + j*(171) -208 + j*(-58) -3 + j*(101) -122 + j*(-214) -13 + j*(99) --80 + j*(217) --315 + j*(182) -124 + j*(-228) -192 + j*(177) -330 + j*(61) --270 + j*(-122) --5 + j*(-162) -182 + j*(31) --197 + j*(-168) -11 + j*(123) -86 + j*(277) --37 + j*(-84) -164 + j*(-81) -148 + j*(24) -355 + j*(-25) -149 + j*(54) --36 + j*(158) -189 + j*(-11) -127 + j*(141) -76 + j*(130) --32 + j*(33) --189 + j*(-19) --35 + j*(-350) --133 + j*(252) --139 + j*(-38) -71 + j*(-33) --42 + j*(-138) --252 + j*(121) -283 + j*(140) --50 + j*(135) --124 + j*(-32) -124 + j*(289) --84 + j*(153) -197 + j*(134) --80 + j*(434) --41 + j*(71) -159 + j*(-46) -30 + j*(321) -165 + j*(-438) --47 + j*(98) -180 + j*(125) --144 + j*(-28) -292 + j*(-85) --129 + j*(168) --117 + j*(54) -100 + j*(-224) -25 + j*(-146) -397 + j*(-4) -81 + j*(37) --47 + j*(8) -20 + j*(-333) -110 + j*(-108) --198 + j*(236) --209 + j*(-77) -35 + j*(-111) --82 + j*(78) --46 + j*(-170) -150 + j*(153) -210 + j*(37) --378 + j*(-346) -122 + j*(105) --48 + j*(128) -4 + j*(250) --42 + j*(233) --59 + j*(46) -132 + j*(-116) --69 + j*(51) --296 + j*(228) --81 + j*(40) -121 + j*(-190) -111 + j*(60) --33 + j*(-152) --71 + j*(145) --310 + j*(-11) --144 + j*(-107) -91 + j*(134) --54 + j*(134) -15 + j*(154) -110 + j*(191) --214 + j*(-2) -504 + j*(-209) --42 + j*(-76) -284 + j*(75) --138 + j*(-303) --53 + j*(110) -120 + j*(74) -240 + j*(131) -272 + j*(-115) -3 + j*(69) --32 + j*(18) -259 + j*(-187) -127 + j*(179) --197 + j*(187) -337 + j*(-229) --2 + j*(-35) -188 + j*(25) --348 + j*(177) -138 + j*(-299) --150 + j*(169) -140 + j*(231) --232 + j*(92) --8 + j*(131) --88 + j*(144) -54 + j*(-169) --54 + j*(95) -46 + j*(-153) -74 + j*(112) --187 + j*(-75) --163 + j*(-105) --109 + j*(95) --149 + j*(-81) --320 + j*(128) -245 + j*(117) --284 + j*(93) --26 + j*(-222) --240 + j*(144) -30 + j*(-30) --11 + j*(327) -148 + j*(68) -149 + j*(37) --110 + j*(-209) -348 + j*(7) --69 + j*(-78) -207 + j*(13) --160 + j*(-16) --59 + j*(-75) -70 + j*(7) -203 + j*(220) -301 + j*(210) --206 + j*(-198) -24 + j*(115) --163 + j*(-298) -115 + j*(104) -222 + j*(290) --147 + j*(-90) --254 + j*(-416) -123 + j*(-111) -11 + j*(-310) --179 + j*(-358) -334 + j*(-325) --4 + j*(-132) -35 + j*(134) -5 + j*(-226) -243 + j*(-151) -28 + j*(15) --40 + j*(62) -37 + j*(179) -308 + j*(-266) --185 + j*(-283) -116 + j*(107) -374 + j*(-155) -270 + j*(137) --241 + j*(292) -170 + j*(-226) -55 + j*(-2) -40 + j*(-28) --175 + j*(8) --221 + j*(-73) --51 + j*(-106) --148 + j*(-103) -109 + j*(143) -6 + j*(203) -149 + j*(239) --368 + j*(-54) -95 + j*(249) -210 + j*(64) -13 + j*(-30) -302 + j*(80) -409 + j*(-78) -76 + j*(-308) --71 + j*(-169) --23 + j*(-222) -33 + j*(80) --338 + j*(-320) -45 + j*(-105) --66 + j*(-274) -70 + j*(-21) -48 + j*(27) -189 + j*(257) --64 + j*(7) --117 + j*(-42) --28 + j*(-128) --148 + j*(-406) --174 + j*(-208) -198 + j*(-69) -147 + j*(-133) -257 + j*(-138) --231 + j*(17) -127 + j*(-88) -88 + j*(42) --126 + j*(36) --63 + j*(-175) -123 + j*(-173) --252 + j*(-136) --198 + j*(122) --290 + j*(237) -22 + j*(-23) -171 + j*(89) -239 + j*(-141) -11 + j*(-109) -301 + j*(-88) --216 + j*(1) -14 + j*(-177) -47 + j*(6) --161 + j*(20) --186 + j*(-78) -173 + j*(-47) --289 + j*(-68) --81 + j*(83) --77 + j*(164) -220 + j*(-20) --106 + j*(177) --292 + j*(-216) -74 + j*(-34) -245 + j*(1) -4 + j*(383) --30 + j*(-119) -221 + j*(180) -139 + j*(-260) --160 + j*(95) -58 + j*(361) --223 + j*(57) --59 + j*(-59) --82 + j*(-51) -105 + j*(35) -59 + j*(146) --158 + j*(-41) --64 + j*(197) --202 + j*(-83) -191 + j*(-335) -129 + j*(-421) --30 + j*(-118) -69 + j*(129) --116 + j*(-67) --366 + j*(-18) -279 + j*(235) --279 + j*(1) -45 + j*(-96) --13 + j*(-238) -382 + j*(-21) -207 + j*(351) -192 + j*(-107) --103 + j*(-137) --90 + j*(110) --262 + j*(-211) --127 + j*(162) -109 + j*(40) --238 + j*(127) -81 + j*(5) --30 + j*(109) -118 + j*(71) --12 + j*(26) -40 + j*(-161) -23 + j*(124) --23 + j*(25) --374 + j*(-62) -154 + j*(448) --66 + j*(-63) -152 + j*(-354) -409 + j*(-129) --469 + j*(96) --4 + j*(-141) --13 + j*(142) -276 + j*(12) --135 + j*(-289) --50 + j*(181) --205 + j*(-146) -196 + j*(255) --200 + j*(23) -279 + j*(52) --76 + j*(196) -40 + j*(98) --62 + j*(211) -74 + j*(73) --161 + j*(-179) --134 + j*(-2) --18 + j*(-132) -444 + j*(21) --194 + j*(69) --92 + j*(25) --119 + j*(-431) -121 + j*(136) --100 + j*(63) -14 + j*(-67) -66 + j*(234) --35 + j*(288) -356 + j*(-111) --74 + j*(-60) -215 + j*(206) --46 + j*(8) --4 + j*(-153) --135 + j*(-165) -274 + j*(-99) --218 + j*(-60) --7 + j*(145) --282 + j*(-132) --21 + j*(-270) -35 + j*(-186) -59 + j*(161) --148 + j*(-212) --452 + j*(-222) -203 + j*(-168) -16 + j*(142) -177 + j*(448) -56 + j*(-74) --37 + j*(119) --47 + j*(48) -192 + j*(30) --243 + j*(67) --199 + j*(78) -197 + j*(103) -164 + j*(-210) --33 + j*(185) --55 + j*(35) --388 + j*(21) --49 + j*(-101) --27 + j*(-276) --197 + j*(-151) --236 + j*(-178) --32 + j*(-162) --78 + j*(257) --75 + j*(85) -157 + j*(-10) --147 + j*(-3) -21 + j*(-8) -120 + j*(120) -132 + j*(98) --140 + j*(-98) -194 + j*(-322) -113 + j*(-51) -177 + j*(-63) -41 + j*(204) -146 + j*(45) --145 + j*(62) -17 + j*(74) -257 + j*(-247) --16 + j*(-193) --33 + j*(-364) --297 + j*(100) -18 + j*(-268) --79 + j*(-70) -49 + j*(17) --61 + j*(-52) -296 + j*(-32) -37 + j*(168) --117 + j*(-164) --74 + j*(-211) --87 + j*(66) --165 + j*(-38) -18 + j*(136) -14 + j*(74) -187 + j*(172) -99 + j*(22) -95 + j*(-151) -88 + j*(-236) --201 + j*(92) -91 + j*(214) -280 + j*(200) -254 + j*(-28) -82 + j*(199) --333 + j*(294) --64 + j*(-255) -228 + j*(375) --1 + j*(94) -211 + j*(-207) -299 + j*(-447) --104 + j*(-17) --30 + j*(-28) --164 + j*(-211) --87 + j*(-76) --124 + j*(264) -176 + j*(-222) -221 + j*(-322) -158 + j*(148) --307 + j*(-128) -86 + j*(9) --10 + j*(-23) -131 + j*(25) --108 + j*(186) --144 + j*(132) -67 + j*(121) -11 + j*(-222) -1 + j*(93) -182 + j*(93) --114 + j*(200) -87 + j*(163) -88 + j*(86) --73 + j*(-90) -123 + j*(-30) --16 + j*(-27) -214 + j*(-188) --36 + j*(25) --286 + j*(310) --202 + j*(-54) --223 + j*(238) --161 + j*(54) --62 + j*(170) --214 + j*(-35) -110 + j*(264) -262 + j*(265) -100 + j*(37) --488 + j*(305) --148 + j*(254) --253 + j*(123) -146 + j*(182) --332 + j*(-199) -55 + j*(-65) -204 + j*(83) --1 + j*(-51) -32 + j*(-314) -43 + j*(23) -68 + j*(-412) -78 + j*(-180) --197 + j*(146) --76 + j*(-66) -136 + j*(-226) -40 + j*(241) -27 + j*(-177) --144 + j*(66) -112 + j*(-258) -163 + j*(-74) --1 + j*(-81) -52 + j*(469) -3 + j*(-276) -148 + j*(107) --93 + j*(-173) -64 + j*(37) --231 + j*(124) -61 + j*(-131) --88 + j*(114) -107 + j*(-32) --170 + j*(240) -226 + j*(-173) -58 + j*(-247) -22 + j*(47) -168 + j*(181) -16 + j*(158) --120 + j*(-66) --81 + j*(296) --209 + j*(-192) --75 + j*(-115) -95 + j*(86) -32 + j*(125) -57 + j*(64) -6 + j*(-11) --367 + j*(-47) -180 + j*(-28) --443 + j*(-35) --174 + j*(67) --83 + j*(-21) -64 + j*(-84) -206 + j*(-67) -25 + j*(-205) --205 + j*(139) -16 + j*(-135) --233 + j*(-43) -158 + j*(-4) --18 + j*(-106) --87 + j*(129) --112 + j*(-28) -159 + j*(144) -98 + j*(-110) --11 + j*(28) --41 + j*(192) -21 + j*(-199) --26 + j*(233) -6 + j*(-337) -412 + j*(7) --136 + j*(-25) -83 + j*(103) --45 + j*(62) -79 + j*(20) -86 + j*(20) -142 + j*(284) --45 + j*(-91) -100 + j*(67) --142 + j*(100) --223 + j*(248) --3 + j*(120) -311 + j*(-245) -62 + j*(-47) -91 + j*(-78) --141 + j*(-132) -4 + j*(-133) -81 + j*(-179) --13 + j*(166) -20 + j*(180) -182 + j*(-139) -230 + j*(83) -387 + j*(67) --6 + j*(-113) -63 + j*(161) --198 + j*(104) --36 + j*(-129) --30 + j*(-63) -112 + j*(-41) -127 + j*(189) -156 + j*(62) --110 + j*(-12) -52 + j*(-182) --110 + j*(-298) --151 + j*(180) -234 + j*(-178) -14 + j*(69) -75 + j*(-57) -236 + j*(-168) --54 + j*(-212) --194 + j*(15) -80 + j*(347) -190 + j*(412) -11 + j*(-153) -59 + j*(28) --182 + j*(-11) -54 + j*(145) -69 + j*(78) -166 + j*(-189) -204 + j*(-157) -83 + j*(-216) -87 + j*(-35) --200 + j*(-156) -455 + j*(141) -7 + j*(-114) -91 + j*(305) --95 + j*(62) --254 + j*(-61) --80 + j*(117) --30 + j*(-195) --146 + j*(105) -21 + j*(-25) -305 + j*(23) --81 + j*(-15) -192 + j*(395) -141 + j*(303) --52 + j*(-129) -54 + j*(-149) -63 + j*(64) -98 + j*(-260) -132 + j*(19) --59 + j*(-57) -116 + j*(170) -251 + j*(-284) -42 + j*(208) -51 + j*(-195) --98 + j*(-44) --57 + j*(55) -106 + j*(-38) --243 + j*(16) -153 + j*(-65) -7 + j*(-110) -88 + j*(-73) --279 + j*(77) --173 + j*(40) --112 + j*(0) --154 + j*(-228) -2 + j*(-147) --166 + j*(126) -119 + j*(148) --215 + j*(114) --155 + j*(23) --41 + j*(-34) -40 + j*(-300) --328 + j*(202) --206 + j*(-212) -59 + j*(-325) -25 + j*(-100) --208 + j*(-235) --233 + j*(167) --243 + j*(20) --203 + j*(0) --168 + j*(-173) --310 + j*(-146) --148 + j*(398) --72 + j*(-93) -62 + j*(-152) -28 + j*(128) --217 + j*(-27) --222 + j*(-188) -168 + j*(16) --100 + j*(140) -99 + j*(8) -76 + j*(-57) -139 + j*(-150) --192 + j*(-49) --18 + j*(-206) --16 + j*(-327) -78 + j*(35) -11 + j*(42) --107 + j*(-82) --274 + j*(235) -81 + j*(-11) -281 + j*(-61) --148 + j*(78) --279 + j*(-51) --252 + j*(186) -31 + j*(-99) -292 + j*(-155) --188 + j*(192) -258 + j*(-96) -21 + j*(-92) --28 + j*(165) -146 + j*(59) -0 + j*(-21) -30 + j*(-192) -82 + j*(14) --294 + j*(-13) --150 + j*(137) --71 + j*(68) --233 + j*(45) -12 + j*(-62) --177 + j*(44) --175 + j*(337) --41 + j*(1) -363 + j*(-244) -231 + j*(181) -191 + j*(-130) -287 + j*(115) --69 + j*(221) --236 + j*(-50) --393 + j*(-47) -71 + j*(13) -447 + j*(-110) --76 + j*(316) -42 + j*(71) --20 + j*(-75) --17 + j*(82) --231 + j*(-258) -156 + j*(-174) --85 + j*(-142) --165 + j*(-173) --185 + j*(-25) -173 + j*(137) -303 + j*(-119) --86 + j*(-105) --253 + j*(-318) --68 + j*(142) --213 + j*(259) -179 + j*(-58) --93 + j*(122) -135 + j*(-185) --1 + j*(-180) -261 + j*(-385) --207 + j*(-315) -6 + j*(-70) -216 + j*(339) --137 + j*(-129) -35 + j*(15) -16 + j*(127) -71 + j*(-29) --254 + j*(-211) --325 + j*(103) --222 + j*(6) -159 + j*(91) -25 + j*(106) --139 + j*(101) --133 + j*(-289) --124 + j*(-40) --238 + j*(-183) --144 + j*(-1) -111 + j*(-64) -63 + j*(-308) --78 + j*(-153) -324 + j*(-243) -209 + j*(11) -64 + j*(232) -71 + j*(62) -203 + j*(-52) --161 + j*(129) --339 + j*(144) -78 + j*(86) -66 + j*(-263) --78 + j*(-190) -247 + j*(293) --25 + j*(19) --267 + j*(-15) -89 + j*(-206) --64 + j*(120) -83 + j*(165) --195 + j*(249) --55 + j*(-379) --194 + j*(19) --139 + j*(49) -316 + j*(-139) --190 + j*(170) --33 + j*(34) -14 + j*(-44) --363 + j*(50) -39 + j*(77) -296 + j*(-133) --183 + j*(289) --96 + j*(-81) --74 + j*(-333) -92 + j*(-183) --99 + j*(167) --63 + j*(21) -339 + j*(-39) --175 + j*(-257) -72 + j*(117) --192 + j*(105) -17 + j*(-17) --84 + j*(166) -49 + j*(188) --156 + j*(153) -74 + j*(-169) --35 + j*(280) --81 + j*(101) -9 + j*(112) -214 + j*(-38) -254 + j*(-35) -78 + j*(263) -125 + j*(-71) -100 + j*(68) -339 + j*(111) --10 + j*(134) --4 + j*(-69) --98 + j*(74) --41 + j*(106) --28 + j*(330) -325 + j*(88) --59 + j*(41) --110 + j*(-247) -154 + j*(16) -463 + j*(363) --112 + j*(-29) -133 + j*(-1) -315 + j*(208) --102 + j*(-248) -135 + j*(23) -328 + j*(11) -201 + j*(46) -163 + j*(134) -224 + j*(-62) -178 + j*(-89) -136 + j*(107) -69 + j*(-224) -140 + j*(-87) --112 + j*(254) --65 + j*(120) --239 + j*(-35) -80 + j*(30) --331 + j*(-125) --71 + j*(45) -31 + j*(417) --17 + j*(-139) --54 + j*(49) -246 + j*(-253) --6 + j*(101) -110 + j*(-138) --88 + j*(56) -66 + j*(264) --255 + j*(-18) --155 + j*(95) --332 + j*(88) --103 + j*(25) --618 + j*(214) -213 + j*(-211) -260 + j*(-49) --94 + j*(-75) --9 + j*(12) -97 + j*(171) -74 + j*(219) --18 + j*(-54) -101 + j*(-135) --159 + j*(82) --48 + j*(-196) -408 + j*(275) --194 + j*(-74) -111 + j*(337) --13 + j*(409) --106 + j*(-51) --178 + j*(-203) --228 + j*(-69) --243 + j*(-10) -1 + j*(-8) -177 + j*(-189) -85 + j*(16) -131 + j*(270) --96 + j*(226) --4 + j*(336) --217 + j*(42) --99 + j*(-82) --206 + j*(-93) -18 + j*(295) -99 + j*(-189) --350 + j*(129) --8 + j*(91) -59 + j*(-274) --83 + j*(173) -48 + j*(29) -207 + j*(-75) -49 + j*(78) --65 + j*(-382) -193 + j*(100) --70 + j*(42) -33 + j*(-206) -228 + j*(49) -53 + j*(208) --76 + j*(-93) -102 + j*(-103) --256 + j*(-43) -86 + j*(-13) --111 + j*(40) -186 + j*(-48) --2 + j*(498) --182 + j*(52) --127 + j*(81) -74 + j*(-54) -38 + j*(-88) -35 + j*(-194) --173 + j*(112) --129 + j*(224) --54 + j*(-2) -191 + j*(113) --88 + j*(72) --69 + j*(-259) -84 + j*(240) --187 + j*(70) --79 + j*(-11) -259 + j*(206) -123 + j*(365) -92 + j*(103) --187 + j*(76) -54 + j*(232) -40 + j*(-158) --212 + j*(-424) --91 + j*(215) --112 + j*(138) --110 + j*(243) --110 + j*(145) -72 + j*(80) -30 + j*(-110) -180 + j*(26) -63 + j*(5) -232 + j*(238) -199 + j*(-119) -438 + j*(64) --40 + j*(-139) --146 + j*(-31) -85 + j*(167) -139 + j*(-206) -45 + j*(66) -98 + j*(-75) -23 + j*(131) -131 + j*(15) --84 + j*(126) --64 + j*(-182) -28 + j*(141) -17 + j*(37) -194 + j*(6) --4 + j*(336) -160 + j*(205) --259 + j*(113) --52 + j*(4) --104 + j*(-249) --11 + j*(-245) --66 + j*(86) -30 + j*(-138) -90 + j*(-182) -47 + j*(122) -281 + j*(166) --230 + j*(13) --165 + j*(380) -222 + j*(-15) --247 + j*(113) --91 + j*(-12) --88 + j*(200) --69 + j*(240) --165 + j*(-6) --124 + j*(-184) --327 + j*(296) --209 + j*(37) --114 + j*(-329) -238 + j*(-267) --122 + j*(-149) --104 + j*(-238) -339 + j*(264) -347 + j*(76) -184 + j*(-87) -272 + j*(-118) -10 + j*(169) -23 + j*(74) --53 + j*(377) --180 + j*(-162) --35 + j*(-269) -73 + j*(280) --176 + j*(-9) -69 + j*(172) --14 + j*(101) --124 + j*(-119) --54 + j*(-187) --47 + j*(158) -352 + j*(147) -167 + j*(312) --187 + j*(-197) -101 + j*(202) --170 + j*(-168) -140 + j*(39) -132 + j*(40) -29 + j*(-33) --226 + j*(204) --341 + j*(-25) --21 + j*(235) -110 + j*(25) --176 + j*(40) --35 + j*(105) --175 + j*(13) --85 + j*(-78) --216 + j*(-102) -147 + j*(43) -370 + j*(-45) --330 + j*(-246) --337 + j*(179) --133 + j*(67) -110 + j*(-80) -92 + j*(-27) -199 + j*(-197) -150 + j*(98) --129 + j*(79) --209 + j*(-61) --128 + j*(406) -472 + j*(301) --19 + j*(146) --18 + j*(-83) --54 + j*(-16) -121 + j*(76) --417 + j*(77) --192 + j*(-91) -35 + j*(232) -240 + j*(161) --132 + j*(-16) --149 + j*(72) --26 + j*(-36) --112 + j*(-83) --86 + j*(-100) -83 + j*(-132) --123 + j*(53) --269 + j*(-47) --93 + j*(180) -129 + j*(200) --218 + j*(105) -116 + j*(98) --157 + j*(-165) --252 + j*(-54) -87 + j*(91) -309 + j*(-156) -72 + j*(-159) --16 + j*(-136) --54 + j*(16) --103 + j*(170) -76 + j*(182) --231 + j*(-148) -47 + j*(169) -21 + j*(163) -84 + j*(261) -198 + j*(223) --277 + j*(100) --166 + j*(-125) -125 + j*(-30) --276 + j*(266) -159 + j*(26) -311 + j*(171) --404 + j*(289) --104 + j*(-370) -172 + j*(-347) -59 + j*(-465) --428 + j*(43) -26 + j*(-619) --139 + j*(192) -213 + j*(469) -395 + j*(104) -146 + j*(-270) -77 + j*(257) --204 + j*(245) -61 + j*(264) -317 + j*(351) -395 + j*(379) --250 + j*(-278) -547 + j*(-360) --296 + j*(-69) -71 + j*(260) -456 + j*(-113) -316 + j*(214) -107 + j*(-390) -313 + j*(228) --105 + j*(486) -120 + j*(275) -541 + j*(-306) --351 + j*(-19) --144 + j*(-456) -103 + j*(-197) --262 + j*(-299) -305 + j*(62) --245 + j*(-17) --219 + j*(472) -200 + j*(-195) --155 + j*(-257) --211 + j*(341) -146 + j*(262) --86 + j*(229) --245 + j*(-318) -368 + j*(-296) --375 + j*(305) --582 + j*(149) -412 + j*(-397) -421 + j*(-441) -434 + j*(-191) -141 + j*(325) --331 + j*(88) -610 + j*(43) --328 + j*(305) -351 + j*(-415) -161 + j*(428) -530 + j*(142) --705 + j*(-324) --76 + j*(132) --316 + j*(-183) --307 + j*(187) -148 + j*(361) -183 + j*(94) --168 + j*(360) --266 + j*(129) --301 + j*(-244) --252 + j*(232) --546 + j*(216) --227 + j*(121) --35 + j*(-342) --190 + j*(-325) --59 + j*(523) --171 + j*(-315) -297 + j*(183) -194 + j*(148) --443 + j*(281) --512 + j*(-66) -532 + j*(250) --276 + j*(306) --358 + j*(187) --477 + j*(518) --310 + j*(-158) -167 + j*(-405) -66 + j*(-134) -96 + j*(379) --23 + j*(-460) --404 + j*(-227) --14 + j*(-501) --691 + j*(-200) --339 + j*(30) -648 + j*(317) -347 + j*(-322) --260 + j*(597) --610 + j*(216) -443 + j*(205) -249 + j*(-314) -486 + j*(-170) --298 + j*(87) -141 + j*(238) --60 + j*(-71) -67 + j*(-124) --291 + j*(-540) -174 + j*(-324) --161 + j*(-228) -193 + j*(-37) --153 + j*(-331) -235 + j*(293) --141 + j*(-504) -339 + j*(49) -373 + j*(21) -473 + j*(355) --270 + j*(268) --26 + j*(-260) -379 + j*(-419) -178 + j*(-35) -307 + j*(680) -564 + j*(-397) --474 + j*(-527) -482 + j*(207) -374 + j*(51) -3 + j*(123) -5 + j*(586) -267 + j*(491) -185 + j*(225) -312 + j*(556) -4 + j*(-366) -166 + j*(405) --346 + j*(422) --438 + j*(-416) -390 + j*(-59) -30 + j*(-288) -274 + j*(-242) --114 + j*(-100) --177 + j*(-375) --455 + j*(-292) --272 + j*(301) --218 + j*(-479) -447 + j*(-296) --335 + j*(-378) --427 + j*(-16) -308 + j*(-300) -479 + j*(322) --170 + j*(82) --366 + j*(-153) --701 + j*(-477) --350 + j*(282) --327 + j*(344) --389 + j*(-333) --450 + j*(-218) --3 + j*(682) -260 + j*(-402) -70 + j*(305) -588 + j*(520) --1 + j*(-161) --292 + j*(-104) --267 + j*(434) --195 + j*(404) --435 + j*(542) --376 + j*(-235) --187 + j*(42) -61 + j*(550) --125 + j*(93) --262 + j*(217) -512 + j*(234) -405 + j*(358) -52 + j*(-291) -1 + j*(395) -450 + j*(-216) --172 + j*(432) --180 + j*(-247) -15 + j*(-400) --78 + j*(363) -227 + j*(123) -403 + j*(-133) --124 + j*(258) --400 + j*(-366) -72 + j*(-175) --140 + j*(-51) -90 + j*(-166) --484 + j*(148) --404 + j*(-392) --197 + j*(133) -241 + j*(-45) -122 + j*(-306) --136 + j*(296) --194 + j*(264) -516 + j*(-226) --168 + j*(-320) --14 + j*(-386) -231 + j*(440) -146 + j*(346) -268 + j*(451) -184 + j*(-27) -310 + j*(214) -409 + j*(-258) --361 + j*(-303) -153 + j*(-127) --217 + j*(-438) -107 + j*(476) --204 + j*(403) --313 + j*(315) --328 + j*(-307) --351 + j*(97) -185 + j*(-211) -122 + j*(233) --445 + j*(-503) --212 + j*(-397) --420 + j*(196) -64 + j*(-252) -407 + j*(-336) --265 + j*(280) -281 + j*(-268) -218 + j*(-292) --138 + j*(484) --16 + j*(192) -474 + j*(362) --399 + j*(-2) -73 + j*(-350) -264 + j*(158) -365 + j*(-137) -71 + j*(-62) --389 + j*(-485) --74 + j*(-57) --281 + j*(252) -299 + j*(258) -1 + j*(200) -252 + j*(44) -95 + j*(-210) -180 + j*(-445) --356 + j*(228) -90 + j*(-321) --198 + j*(-281) -441 + j*(-279) --417 + j*(428) --317 + j*(-210) -156 + j*(-520) --59 + j*(-228) -238 + j*(-274) --299 + j*(-308) --270 + j*(-294) --181 + j*(-165) -180 + j*(-48) --172 + j*(-289) -395 + j*(77) -212 + j*(-88) -361 + j*(378) --260 + j*(-753) -205 + j*(-86) --151 + j*(127) -416 + j*(-146) -121 + j*(-566) -65 + j*(-477) -119 + j*(281) -43 + j*(-42) --172 + j*(182) --340 + j*(396) -51 + j*(286) -235 + j*(-410) -296 + j*(-146) --86 + j*(-184) --59 + j*(-322) --381 + j*(236) -98 + j*(-173) --176 + j*(218) --682 + j*(-62) --41 + j*(-211) --525 + j*(-330) -36 + j*(-36) --578 + j*(-367) --245 + j*(380) --305 + j*(301) -333 + j*(-141) --127 + j*(-254) -308 + j*(-378) --358 + j*(177) -231 + j*(216) --112 + j*(459) --436 + j*(-497) -296 + j*(231) --276 + j*(-409) -299 + j*(144) -310 + j*(-267) --309 + j*(-237) --204 + j*(104) -158 + j*(194) -325 + j*(-127) -140 + j*(260) -52 + j*(131) -29 + j*(-135) --162 + j*(345) --5 + j*(132) -69 + j*(-456) -302 + j*(149) -211 + j*(-262) --506 + j*(-175) -292 + j*(182) -52 + j*(-322) -365 + j*(-232) -312 + j*(-269) --319 + j*(21) --315 + j*(-581) --138 + j*(167) --43 + j*(197) --42 + j*(450) --296 + j*(155) --540 + j*(358) --307 + j*(87) --446 + j*(-250) -97 + j*(116) -140 + j*(-486) -300 + j*(-278) --419 + j*(163) --211 + j*(-185) --194 + j*(367) -291 + j*(250) -312 + j*(-236) -195 + j*(81) --465 + j*(-375) -482 + j*(115) -116 + j*(120) -122 + j*(320) --55 + j*(-224) --280 + j*(177) -542 + j*(-264) -416 + j*(103) --152 + j*(-113) --116 + j*(-58) --139 + j*(-262) --165 + j*(-510) --57 + j*(-504) -168 + j*(-228) -474 + j*(-120) --119 + j*(10) -313 + j*(-328) --291 + j*(209) -271 + j*(-57) -358 + j*(-245) -419 + j*(-226) --45 + j*(-529) -344 + j*(-443) -147 + j*(-416) --105 + j*(-279) -40 + j*(4) --409 + j*(212) --322 + j*(-257) --169 + j*(-639) --194 + j*(-323) -311 + j*(-214) --356 + j*(559) -318 + j*(-374) -157 + j*(112) --339 + j*(76) --456 + j*(153) --328 + j*(-325) -504 + j*(113) --447 + j*(219) -173 + j*(284) -194 + j*(-21) --136 + j*(-310) --91 + j*(351) --112 + j*(-317) -474 + j*(227) --348 + j*(124) -368 + j*(-102) -395 + j*(-190) --172 + j*(202) --148 + j*(-287) -393 + j*(-330) -144 + j*(411) --259 + j*(238) -371 + j*(-130) -40 + j*(-457) -129 + j*(-453) --451 + j*(-215) --333 + j*(242) -353 + j*(334) --604 + j*(356) -209 + j*(-318) --358 + j*(-76) --118 + j*(-313) -439 + j*(-315) -60 + j*(-572) --457 + j*(282) --834 + j*(-7) -428 + j*(-140) -325 + j*(215) -42 + j*(263) -301 + j*(151) -140 + j*(-72) -489 + j*(-438) -323 + j*(-402) -194 + j*(-13) -257 + j*(-322) --334 + j*(267) -231 + j*(409) --231 + j*(-271) --265 + j*(394) --324 + j*(-305) --588 + j*(-325) -84 + j*(-489) -366 + j*(43) --291 + j*(108) -533 + j*(-455) --100 + j*(352) -181 + j*(-187) -287 + j*(-428) --322 + j*(17) -90 + j*(-332) -413 + j*(-171) --474 + j*(-153) --167 + j*(-209) -76 + j*(-141) -395 + j*(201) --330 + j*(212) -127 + j*(-255) -120 + j*(-15) --132 + j*(190) --436 + j*(-209) --281 + j*(425) -300 + j*(-408) --162 + j*(-301) --316 + j*(-458) -166 + j*(-491) --384 + j*(-423) -568 + j*(-527) --212 + j*(296) --204 + j*(-298) --229 + j*(117) --159 + j*(-412) -365 + j*(358) -260 + j*(-245) -247 + j*(33) -162 + j*(139) --332 + j*(284) --489 + j*(-540) --221 + j*(-39) --55 + j*(-142) --129 + j*(360) -235 + j*(-252) -513 + j*(104) --58 + j*(-313) -419 + j*(284) --267 + j*(316) -588 + j*(-197) --193 + j*(-361) -370 + j*(556) --269 + j*(106) -153 + j*(-44) --167 + j*(-265) --21 + j*(240) -324 + j*(-368) --233 + j*(-361) --260 + j*(-260) --504 + j*(245) --684 + j*(316) --13 + j*(-153) -89 + j*(-546) -268 + j*(-261) -392 + j*(448) -359 + j*(397) -448 + j*(-398) --400 + j*(-225) --547 + j*(-383) -399 + j*(429) --360 + j*(-187) -36 + j*(-126) --384 + j*(291) -158 + j*(-358) -337 + j*(569) -431 + j*(-49) -581 + j*(30) -158 + j*(-206) -361 + j*(-217) --216 + j*(-233) -309 + j*(-486) -258 + j*(-265) -363 + j*(199) --440 + j*(309) --134 + j*(-397) -441 + j*(298) -356 + j*(285) -148 + j*(-550) -207 + j*(86) -537 + j*(395) --137 + j*(297) --80 + j*(409) -696 + j*(23) -25 + j*(-275) -402 + j*(129) -334 + j*(219) -79 + j*(271) --461 + j*(-98) -21 + j*(-23) --138 + j*(354) -487 + j*(-36) -373 + j*(-1) --540 + j*(-255) -108 + j*(-153) -232 + j*(249) -262 + j*(136) --284 + j*(-388) -254 + j*(-303) -4 + j*(-573) --71 + j*(327) --25 + j*(-76) --33 + j*(-450) -248 + j*(362) -61 + j*(-260) -288 + j*(272) -245 + j*(-42) --204 + j*(277) --479 + j*(-407) --165 + j*(451) -409 + j*(445) --143 + j*(566) --254 + j*(-428) --61 + j*(408) --203 + j*(-141) --38 + j*(893) --53 + j*(235) -170 + j*(-614) -217 + j*(180) -499 + j*(-375) --339 + j*(232) --112 + j*(-235) -290 + j*(233) --400 + j*(214) -470 + j*(363) --634 + j*(-109) --344 + j*(45) -308 + j*(-479) --330 + j*(-6) --141 + j*(-100) --275 + j*(195) -474 + j*(139) -23 + j*(482) --501 + j*(-599) --23 + j*(105) -204 + j*(-323) -220 + j*(119) -471 + j*(-33) --176 + j*(-472) --64 + j*(-11) --98 + j*(158) -94 + j*(-177) --395 + j*(-368) -106 + j*(106) --556 + j*(-269) -404 + j*(389) --13 + j*(-54) --25 + j*(455) -2 + j*(366) -418 + j*(-81) -390 + j*(-341) --173 + j*(-397) -364 + j*(-233) -17 + j*(-495) --489 + j*(86) --287 + j*(419) -93 + j*(431) --31 + j*(212) --218 + j*(-117) --233 + j*(244) -1 + j*(130) --180 + j*(-312) --434 + j*(57) -501 + j*(22) -324 + j*(-359) --497 + j*(-63) -453 + j*(-11) -225 + j*(-460) --413 + j*(-100) --16 + j*(440) -500 + j*(130) --414 + j*(161) -469 + j*(326) -211 + j*(175) -332 + j*(-65) -407 + j*(13) -207 + j*(467) --366 + j*(372) -200 + j*(-223) --301 + j*(-318) --198 + j*(-273) --209 + j*(221) --148 + j*(5) -102 + j*(433) --107 + j*(-116) -303 + j*(337) -356 + j*(98) --203 + j*(369) -452 + j*(281) --542 + j*(421) -54 + j*(371) -222 + j*(-46) -559 + j*(544) -100 + j*(-298) -68 + j*(204) --264 + j*(-267) --97 + j*(-311) --738 + j*(203) -282 + j*(342) --310 + j*(778) --209 + j*(102) -154 + j*(-2) -11 + j*(-8) -153 + j*(222) -4 + j*(-33) -309 + j*(283) --8 + j*(117) --136 + j*(-322) -35 + j*(33) --11 + j*(176) -119 + j*(237) -186 + j*(45) -77 + j*(124) -288 + j*(35) --57 + j*(216) -101 + j*(-8) -119 + j*(-40) -102 + j*(-182) -15 + j*(83) --88 + j*(74) -187 + j*(388) --7 + j*(-26) -284 + j*(-194) -235 + j*(-341) --86 + j*(-122) --98 + j*(-227) --177 + j*(-59) --202 + j*(-35) --58 + j*(-23) --12 + j*(-45) -83 + j*(33) --135 + j*(-110) --112 + j*(-204) --404 + j*(-49) --187 + j*(-67) --158 + j*(168) --105 + j*(-175) -13 + j*(-358) -4 + j*(-224) -35 + j*(-62) -120 + j*(-361) --274 + j*(-179) --63 + j*(23) --110 + j*(-18) --194 + j*(-4) --61 + j*(-28) -138 + j*(-290) -100 + j*(-38) --128 + j*(-204) --246 + j*(-176) -397 + j*(33) -180 + j*(80) --214 + j*(-113) --52 + j*(244) --95 + j*(-3) --87 + j*(-13) -15 + j*(73) -71 + j*(-78) -110 + j*(-1) -4 + j*(-154) -65 + j*(-86) --14 + j*(100) --88 + j*(21) --117 + j*(120) --478 + j*(-64) --50 + j*(-23) -217 + j*(10) --46 + j*(-238) -60 + j*(-23) -235 + j*(-35) --79 + j*(339) --192 + j*(-21) --89 + j*(135) --107 + j*(126) --221 + j*(42) -211 + j*(184) -66 + j*(-160) --168 + j*(-4) --105 + j*(85) -132 + j*(-27) -124 + j*(-130) -174 + j*(-112) -151 + j*(76) -249 + j*(-163) -72 + j*(233) --243 + j*(-77) --294 + j*(-25) --281 + j*(61) -112 + j*(67) --37 + j*(13) -74 + j*(-144) --168 + j*(-35) --13 + j*(-313) --386 + j*(10) --311 + j*(-79) --11 + j*(90) -185 + j*(405) -186 + j*(-17) --127 + j*(-137) -10 + j*(136) --59 + j*(110) -1 + j*(-83) --20 + j*(-180) -214 + j*(361) -231 + j*(62) --104 + j*(-86) --192 + j*(185) --108 + j*(170) --169 + j*(-192) --104 + j*(-171) --28 + j*(-57) --208 + j*(126) -185 + j*(-78) -105 + j*(159) --228 + j*(-110) -340 + j*(82) -235 + j*(214) --80 + j*(-14) -234 + j*(-162) --131 + j*(63) --43 + j*(60) --157 + j*(68) --207 + j*(144) --77 + j*(53) -214 + j*(147) --150 + j*(-83) --100 + j*(90) --43 + j*(90) -97 + j*(129) --34 + j*(-44) -14 + j*(86) --258 + j*(47) -161 + j*(38) -286 + j*(-1) -113 + j*(178) --124 + j*(-255) --3 + j*(347) -136 + j*(-137) -62 + j*(-89) -36 + j*(267) --74 + j*(-311) --1 + j*(109) -96 + j*(-269) -223 + j*(-111) -298 + j*(-105) --149 + j*(9) --303 + j*(36) --265 + j*(276) --324 + j*(-81) --176 + j*(-8) -243 + j*(311) --18 + j*(-35) --212 + j*(177) --35 + j*(158) -20 + j*(121) -70 + j*(64) --201 + j*(-1) --76 + j*(258) --252 + j*(101) -2 + j*(225) -92 + j*(-81) -123 + j*(-123) --125 + j*(78) -146 + j*(-37) -184 + j*(375) -62 + j*(102) --294 + j*(196) --3 + j*(217) --214 + j*(322) -559 + j*(98) --136 + j*(173) -47 + j*(-37) -98 + j*(-22) -234 + j*(-21) -36 + j*(-142) -239 + j*(-272) --58 + j*(198) -390 + j*(37) --132 + j*(-216) --95 + j*(-52) -27 + j*(-119) --8 + j*(143) -122 + j*(110) -145 + j*(-146) -210 + j*(-166) --73 + j*(-25) -136 + j*(45) -150 + j*(-169) -45 + j*(-17) -122 + j*(-30) -110 + j*(-110) -63 + j*(-232) -330 + j*(312) --204 + j*(-26) -204 + j*(129) --87 + j*(88) -240 + j*(73) -129 + j*(-101) --68 + j*(92) -115 + j*(122) -273 + j*(103) --320 + j*(-144) -79 + j*(93) --335 + j*(242) -308 + j*(1) -52 + j*(119) -206 + j*(-37) -106 + j*(-74) --288 + j*(-274) --131 + j*(194) --107 + j*(-123) --418 + j*(120) -165 + j*(74) -209 + j*(27) -143 + j*(-276) -12 + j*(-70) -33 + j*(-74) --44 + j*(-145) -1 + j*(-385) -7 + j*(45) -460 + j*(-204) -53 + j*(266) --216 + j*(-86) -28 + j*(92) -118 + j*(61) -168 + j*(-52) -110 + j*(198) -121 + j*(-107) -98 + j*(75) --211 + j*(338) -16 + j*(-6) --261 + j*(346) -101 + j*(-113) --151 + j*(104) --111 + j*(-175) -38 + j*(172) -83 + j*(-206) -173 + j*(199) --34 + j*(66) --12 + j*(-31) -40 + j*(47) -30 + j*(336) -276 + j*(16) -238 + j*(76) -439 + j*(259) -120 + j*(-16) -125 + j*(37) -139 + j*(104) --79 + j*(-187) --431 + j*(219) --304 + j*(-148) --4 + j*(-105) --141 + j*(-92) -194 + j*(-172) --30 + j*(-248) --45 + j*(157) --4 + j*(109) -170 + j*(193) -153 + j*(-243) --304 + j*(-82) -92 + j*(64) -76 + j*(16) -68 + j*(46) --146 + j*(144) -219 + j*(222) --216 + j*(68) --88 + j*(-248) --170 + j*(42) -79 + j*(-355) -43 + j*(67) -69 + j*(33) --137 + j*(-228) -72 + j*(132) --40 + j*(-29) --1 + j*(107) --73 + j*(333) -285 + j*(-302) -252 + j*(-49) -74 + j*(-91) --83 + j*(156) --304 + j*(321) -100 + j*(-276) --182 + j*(-174) --49 + j*(-325) -78 + j*(-262) --262 + j*(-26) -134 + j*(83) --112 + j*(83) -7 + j*(65) --11 + j*(110) -115 + j*(47) --45 + j*(-115) -1 + j*(-168) --112 + j*(-49) --293 + j*(28) --351 + j*(-62) --10 + j*(27) -226 + j*(-30) --57 + j*(176) -37 + j*(-181) -172 + j*(143) -187 + j*(248) --205 + j*(1) -187 + j*(-23) --280 + j*(-25) -200 + j*(-519) --30 + j*(218) --90 + j*(220) --58 + j*(22) -110 + j*(-327) --165 + j*(30) --2 + j*(-261) -222 + j*(-47) --115 + j*(-274) -284 + j*(65) -166 + j*(339) --2 + j*(192) --54 + j*(-168) -139 + j*(-147) -202 + j*(-148) --88 + j*(-42) --88 + j*(87) --16 + j*(-157) --116 + j*(-215) -254 + j*(57) --135 + j*(-27) -82 + j*(223) --165 + j*(206) -29 + j*(-119) --112 + j*(-28) -241 + j*(330) --164 + j*(-91) --162 + j*(-92) -39 + j*(57) --105 + j*(240) --96 + j*(-112) -266 + j*(274) -272 + j*(-71) --81 + j*(79) -100 + j*(-11) --52 + j*(-24) -325 + j*(-252) --24 + j*(363) -170 + j*(-103) --224 + j*(263) -229 + j*(123) -62 + j*(-281) --139 + j*(-92) --103 + j*(124) -387 + j*(-151) -103 + j*(252) --52 + j*(-88) -150 + j*(-183) --508 + j*(47) -16 + j*(-13) -40 + j*(104) --18 + j*(-61) -436 + j*(25) --60 + j*(-131) -165 + j*(101) -220 + j*(191) --254 + j*(-140) -21 + j*(-212) --81 + j*(-122) --252 + j*(-175) -11 + j*(124) --47 + j*(38) -163 + j*(227) --525 + j*(30) -117 + j*(453) --137 + j*(-71) -136 + j*(34) -127 + j*(26) --360 + j*(-185) -247 + j*(-28) --350 + j*(317) --262 + j*(151) -58 + j*(-221) --10 + j*(156) --387 + j*(64) --25 + j*(223) --42 + j*(110) -33 + j*(378) -35 + j*(90) --264 + j*(78) --112 + j*(109) -123 + j*(68) -276 + j*(-239) --11 + j*(-231) -416 + j*(23) -276 + j*(196) --52 + j*(-30) --125 + j*(6) -297 + j*(47) -186 + j*(-114) -75 + j*(-99) -379 + j*(1) --25 + j*(330) --81 + j*(-228) --118 + j*(-213) --45 + j*(-100) --372 + j*(84) --93 + j*(-155) --169 + j*(-9) -245 + j*(-222) --134 + j*(-5) --188 + j*(303) --162 + j*(-185) -132 + j*(-141) --325 + j*(301) --42 + j*(-164) -256 + j*(151) -52 + j*(69) --128 + j*(325) --165 + j*(134) --162 + j*(-32) --117 + j*(-190) -17 + j*(-82) -173 + j*(-173) -298 + j*(-11) --151 + j*(141) --327 + j*(147) --62 + j*(72) --21 + j*(-19) --10 + j*(-189) --36 + j*(50) -95 + j*(-60) -122 + j*(141) -125 + j*(23) -18 + j*(218) --36 + j*(288) --127 + j*(81) -21 + j*(-100) --216 + j*(-237) -85 + j*(-117) -4 + j*(-219) -260 + j*(-119) -154 + j*(132) --110 + j*(312) --231 + j*(91) -269 + j*(65) --62 + j*(-256) --133 + j*(-183) -84 + j*(-89) -143 + j*(-9) --245 + j*(11) --196 + j*(-218) -85 + j*(-211) --146 + j*(91) --179 + j*(-57) --122 + j*(-66) --112 + j*(45) --354 + j*(-65) -101 + j*(-99) -362 + j*(243) --141 + j*(-321) -210 + j*(114) -127 + j*(223) -257 + j*(-35) --298 + j*(63) --88 + j*(397) --272 + j*(72) -44 + j*(387) --170 + j*(-21) -60 + j*(104) --310 + j*(-85) --327 + j*(213) -326 + j*(-179) --96 + j*(-5) -15 + j*(-286) --76 + j*(27) -103 + j*(124) -5 + j*(-456) --133 + j*(-173) --7 + j*(-293) --62 + j*(-57) -93 + j*(-42) -282 + j*(-146) -133 + j*(252) --98 + j*(63) -14 + j*(138) --192 + j*(108) -100 + j*(216) --214 + j*(-267) -287 + j*(-177) -138 + j*(-223) --74 + j*(92) -210 + j*(134) --143 + j*(40) -119 + j*(-45) -115 + j*(30) -344 + j*(-255) -175 + j*(116) --238 + j*(98) --122 + j*(-103) --223 + j*(378) -213 + j*(103) -23 + j*(163) --150 + j*(130) -116 + j*(257) --257 + j*(-51) --151 + j*(-144) -98 + j*(-243) --285 + j*(-140) -171 + j*(347) -66 + j*(-49) -294 + j*(-273) --100 + j*(-174) --237 + j*(-134) --459 + j*(320) --73 + j*(2) -162 + j*(180) -64 + j*(-307) -263 + j*(-46) --95 + j*(-274) --50 + j*(103) -191 + j*(170) --107 + j*(60) -42 + j*(-159) --35 + j*(-46) --72 + j*(91) -341 + j*(-216) -112 + j*(249) --114 + j*(-213) -11 + j*(71) --42 + j*(-106) --70 + j*(-117) --204 + j*(-8) --30 + j*(59) --257 + j*(263) -190 + j*(-417) --6 + j*(152) --127 + j*(97) --64 + j*(99) --428 + j*(144) --178 + j*(-112) -539 + j*(-2) -338 + j*(-120) -108 + j*(-235) --324 + j*(-28) -16 + j*(160) -70 + j*(188) -11 + j*(73) --49 + j*(-291) -206 + j*(197) -237 + j*(136) -83 + j*(216) -54 + j*(-149) --28 + j*(-105) --37 + j*(-55) -132 + j*(-138) -138 + j*(-161) -55 + j*(-45) --99 + j*(168) -173 + j*(175) -7 + j*(49) --8 + j*(55) -93 + j*(248) -16 + j*(-199) --104 + j*(324) --163 + j*(122) -66 + j*(112) -134 + j*(-49) -25 + j*(-253) --76 + j*(-95) -42 + j*(245) -151 + j*(-187) --153 + j*(-282) -39 + j*(-135) -4 + j*(-163) -75 + j*(190) --126 + j*(-10) -171 + j*(55) --3 + j*(-19) --59 + j*(76) --189 + j*(-52) -125 + j*(-81) -254 + j*(-258) -25 + j*(-116) --359 + j*(333) --127 + j*(110) --243 + j*(156) -184 + j*(33) --265 + j*(5) --120 + j*(4) --265 + j*(-8) -168 + j*(-161) -65 + j*(125) --62 + j*(-164) --208 + j*(-21) --142 + j*(-322) --378 + j*(19) --73 + j*(76) --61 + j*(151) --141 + j*(-202) -132 + j*(133) -228 + j*(-25) -458 + j*(-65) --133 + j*(-45) --233 + j*(85) -126 + j*(-35) -81 + j*(-158) -239 + j*(64) -169 + j*(179) -23 + j*(318) --153 + j*(-144) -92 + j*(-21) -3 + j*(197) -31 + j*(52) -74 + j*(-50) -117 + j*(-38) --108 + j*(-49) -129 + j*(-19) --218 + j*(-81) -123 + j*(-25) -326 + j*(-124) --146 + j*(-104) --19 + j*(-156) --30 + j*(-185) -52 + j*(86) --529 + j*(6) -194 + j*(-97) -109 + j*(278) --315 + j*(-296) -241 + j*(168) -107 + j*(228) --103 + j*(219) -79 + j*(238) -91 + j*(-158) -343 + j*(-144) --165 + j*(-165) --375 + j*(49) -257 + j*(-81) -223 + j*(160) --144 + j*(-144) --11 + j*(252) -70 + j*(-40) -40 + j*(79) -400 + j*(191) -8 + j*(-76) --98 + j*(-105) -8 + j*(33) --69 + j*(-42) -270 + j*(-35) -23 + j*(22) --418 + j*(-221) --38 + j*(-53) -28 + j*(64) -114 + j*(291) -421 + j*(272) --222 + j*(250) --34 + j*(83) -119 + j*(-148) --141 + j*(136) --165 + j*(40) -110 + j*(-94) --341 + j*(105) --62 + j*(25) --187 + j*(107) --132 + j*(221) --17 + j*(1) -279 + j*(-247) -81 + j*(148) -46 + j*(116) --448 + j*(-277) --310 + j*(431) -30 + j*(28) -136 + j*(-87) -8 + j*(24) -257 + j*(-246) --8 + j*(165) --49 + j*(-32) --11 + j*(-11) -34 + j*(-10) --53 + j*(21) -361 + j*(103) --284 + j*(-36) --202 + j*(-190) -62 + j*(88) --69 + j*(190) --66 + j*(-338) -54 + j*(31) --71 + j*(105) --177 + j*(-55) -235 + j*(-53) -28 + j*(104) --363 + j*(80) -144 + j*(2) -250 + j*(192) --60 + j*(1) --206 + j*(-163) -54 + j*(-66) --91 + j*(-169) --78 + j*(-36) -91 + j*(-15) --30 + j*(107) -85 + j*(14) --285 + j*(21) -179 + j*(152) --197 + j*(-69) -86 + j*(-214) -200 + j*(158) -29 + j*(153) --181 + j*(-278) --89 + j*(-222) --172 + j*(-129) --30 + j*(272) -365 + j*(-10) --40 + j*(-85) --8 + j*(-57) --241 + j*(-301) --267 + j*(-530) -38 + j*(-85) --91 + j*(478) --18 + j*(-260) --261 + j*(-103) -41 + j*(69) -376 + j*(74) -59 + j*(342) --450 + j*(-386) --185 + j*(-6) -399 + j*(284) -69 + j*(128) --247 + j*(-365) -88 + j*(-74) -182 + j*(16) --257 + j*(209) --336 + j*(26) --260 + j*(-74) -80 + j*(66) --257 + j*(-243) -139 + j*(-35) --354 + j*(33) -21 + j*(-107) --279 + j*(46) --124 + j*(192) --474 + j*(-165) -61 + j*(-238) --114 + j*(182) --122 + j*(-105) --265 + j*(192) -209 + j*(-58) -134 + j*(-87) --124 + j*(-299) --112 + j*(196) -132 + j*(38) --180 + j*(303) --203 + j*(82) --62 + j*(-222) -37 + j*(371) -128 + j*(148) -194 + j*(198) -11 + j*(-93) -23 + j*(-392) --9 + j*(213) -284 + j*(-231) -108 + j*(-115) --86 + j*(-54) --78 + j*(25) --66 + j*(-118) -139 + j*(-135) -95 + j*(-66) --155 + j*(-134) --136 + j*(13) -37 + j*(147) -105 + j*(-52) -124 + j*(180) -93 + j*(129) -85 + j*(233) -139 + j*(-129) -363 + j*(93) -110 + j*(181) -321 + j*(-131) --116 + j*(-50) -292 + j*(52) -130 + j*(-219) --76 + j*(155) -170 + j*(8) --60 + j*(36) -105 + j*(58) -368 + j*(125) --136 + j*(-108) --142 + j*(69) -21 + j*(-49) -10 + j*(-94) --196 + j*(-4) -488 + j*(313) -86 + j*(-116) -167 + j*(34) --52 + j*(267) --132 + j*(273) --107 + j*(-311) -12 + j*(-185) -148 + j*(-227) --175 + j*(-88) -68 + j*(40) -44 + j*(-27) -158 + j*(-191) --6 + j*(122) -315 + j*(-21) --213 + j*(59) -421 + j*(-175) --81 + j*(275) --93 + j*(80) --29 + j*(-130) --58 + j*(153) --246 + j*(-158) -71 + j*(-250) --354 + j*(120) -37 + j*(195) -460 + j*(-35) --176 + j*(-60) -109 + j*(30) --274 + j*(46) -163 + j*(-293) -339 + j*(124) --288 + j*(103) -256 + j*(-101) --62 + j*(173) --130 + j*(288) -137 + j*(-49) -169 + j*(-1) --69 + j*(-170) --231 + j*(207) -165 + j*(62) --147 + j*(102) --28 + j*(158) --18 + j*(-250) -58 + j*(-124) --211 + j*(-76) --277 + j*(-126) --288 + j*(281) --47 + j*(91) -57 + j*(-258) -158 + j*(31) -173 + j*(-93) -64 + j*(-301) --178 + j*(88) --129 + j*(518) -144 + j*(-270) -146 + j*(-278) -239 + j*(122) -274 + j*(8) -77 + j*(-119) --47 + j*(-154) --2 + j*(219) --204 + j*(267) -118 + j*(166) -42 + j*(-456) --47 + j*(29) --187 + j*(180) --112 + j*(230) -95 + j*(-22) -120 + j*(381) -244 + j*(-168) --9 + j*(103) -143 + j*(97) --337 + j*(1) -228 + j*(18) --43 + j*(92) --42 + j*(6) --16 + j*(483) -35 + j*(257) -100 + j*(-82) -245 + j*(144) -136 + j*(-35) -167 + j*(31) --45 + j*(129) --165 + j*(130) -431 + j*(227) --163 + j*(-289) -157 + j*(-82) -371 + j*(-184) -8 + j*(117) --247 + j*(-31) -57 + j*(120) --107 + j*(-310) --71 + j*(-28) --234 + j*(-110) --88 + j*(80) --275 + j*(75) --202 + j*(311) --124 + j*(-170) -1 + j*(-284) --44 + j*(-331) --148 + j*(-53) --11 + j*(8) -156 + j*(255) -302 + j*(170) --139 + j*(47) -50 + j*(146) --132 + j*(234) --40 + j*(0) -31 + j*(-148) --151 + j*(64) -202 + j*(-64) -207 + j*(42) --194 + j*(48) -100 + j*(-102) -97 + j*(123) -262 + j*(82) --321 + j*(-168) --282 + j*(19) --35 + j*(201) -257 + j*(114) --47 + j*(-174) --59 + j*(-81) -1 + j*(-50) --180 + j*(-216) --141 + j*(-33) --106 + j*(167) -14 + j*(62) -151 + j*(104) --206 + j*(-145) -132 + j*(-35) --2 + j*(94) -107 + j*(101) -65 + j*(93) -30 + j*(-250) -175 + j*(159) -16 + j*(202) --87 + j*(-223) -7 + j*(-244) -58 + j*(-51) -103 + j*(-135) --168 + j*(-313) --325 + j*(132) --136 + j*(-111) --211 + j*(-162) -35 + j*(-76) -354 + j*(196) -132 + j*(-28) --12 + j*(-352) -140 + j*(-337) --144 + j*(-102) --115 + j*(-63) --36 + j*(65) --98 + j*(-89) --119 + j*(53) -91 + j*(-206) -51 + j*(-476) -160 + j*(-76) --222 + j*(-345) --265 + j*(202) -86 + j*(-40) -142 + j*(170) -115 + j*(237) -187 + j*(-6) --32 + j*(-87) --379 + j*(175) --46 + j*(-578) --116 + j*(-57) -30 + j*(19) --80 + j*(115) -13 + j*(100) --116 + j*(121) -30 + j*(237) --226 + j*(165) --220 + j*(-202) -70 + j*(-153) --282 + j*(-106) --322 + j*(-4) --46 + j*(7) -176 + j*(41) -195 + j*(132) --103 + j*(23) --114 + j*(-115) -153 + j*(317) --57 + j*(60) --160 + j*(-151) --236 + j*(167) -203 + j*(-55) --18 + j*(7) --244 + j*(-16) -250 + j*(159) -3 + j*(-170) --54 + j*(33) --42 + j*(-67) -334 + j*(149) --354 + j*(85) --4 + j*(-64) --63 + j*(92) -223 + j*(-244) -4 + j*(-47) -125 + j*(-204) -107 + j*(70) -191 + j*(-337) --331 + j*(185) --441 + j*(74) --96 + j*(178) --70 + j*(83) -152 + j*(100) --117 + j*(371) -184 + j*(-202) --223 + j*(200) --42 + j*(-50) -18 + j*(126) -20 + j*(-46) --298 + j*(203) -46 + j*(146) --153 + j*(-19) -268 + j*(-62) -103 + j*(-322) -157 + j*(694) --23 + j*(105) --129 + j*(183) --28 + j*(132) -21 + j*(37) -30 + j*(173) --101 + j*(121) --100 + j*(189) --272 + j*(-186) -211 + j*(-85) --222 + j*(-71) --218 + j*(-44) --98 + j*(38) -88 + j*(113) -249 + j*(-197) -86 + j*(346) --49 + j*(-60) -235 + j*(230) -62 + j*(-8) --169 + j*(-186) -304 + j*(-342) -119 + j*(65) -34 + j*(-357) -125 + j*(-96) --258 + j*(103) -71 + j*(-79) --179 + j*(193) --139 + j*(-187) --236 + j*(-131) -408 + j*(340) -139 + j*(-67) --29 + j*(21) --59 + j*(99) --19 + j*(-37) -377 + j*(107) --272 + j*(164) -81 + j*(-98) --44 + j*(-69) --203 + j*(-243) --63 + j*(116) --82 + j*(13) --4 + j*(-42) -83 + j*(-158) --216 + j*(-180) --112 + j*(112) --232 + j*(-168) -146 + j*(169) --199 + j*(55) -74 + j*(-52) --69 + j*(-372) --64 + j*(-177) --92 + j*(-14) -1 + j*(-285) --81 + j*(-277) -57 + j*(-180) --185 + j*(-419) --235 + j*(-25) --298 + j*(117) --20 + j*(82) -110 + j*(231) -20 + j*(-115) -223 + j*(71) --54 + j*(18) --82 + j*(-61) --54 + j*(88) -112 + j*(-132) --216 + j*(-183) -144 + j*(135) --95 + j*(361) -126 + j*(194) -4 + j*(-424) -185 + j*(91) --4 + j*(-30) --112 + j*(-177) --479 + j*(195) --301 + j*(-36) --324 + j*(74) -66 + j*(20) --174 + j*(-128) -57 + j*(-160) -1 + j*(-95) -121 + j*(-1) -78 + j*(-13) -8 + j*(-64) --83 + j*(46) --59 + j*(-35) -7 + j*(23) --100 + j*(168) --151 + j*(-72) --171 + j*(-166) -124 + j*(396) --94 + j*(-126) -136 + j*(-111) --80 + j*(-441) -136 + j*(268) -358 + j*(69) -11 + j*(-5) --298 + j*(-37) --37 + j*(144) --185 + j*(4) --16 + j*(282) --12 + j*(-115) --4 + j*(-86) -29 + j*(-469) --443 + j*(-96) --258 + j*(7) -115 + j*(-133) --213 + j*(-262) -279 + j*(-81) -129 + j*(-107) --167 + j*(38) --91 + j*(-312) --202 + j*(335) -262 + j*(37) -1 + j*(-13) -135 + j*(319) -127 + j*(297) -130 + j*(115) --280 + j*(151) --213 + j*(-125) --90 + j*(23) -110 + j*(192) --148 + j*(-175) --91 + j*(-89) -428 + j*(-33) -122 + j*(-108) -206 + j*(-93) --56 + j*(-170) -330 + j*(-283) -243 + j*(18) -257 + j*(-235) -95 + j*(-140) --50 + j*(-323) --146 + j*(214) -167 + j*(229) --22 + j*(23) -72 + j*(-136) -265 + j*(-286) --305 + j*(-121) -6 + j*(165) -124 + j*(-304) -184 + j*(78) -360 + j*(8) --103 + j*(-96) -99 + j*(-48) --266 + j*(145) -206 + j*(-59) -313 + j*(58) --79 + j*(-182) -109 + j*(91) --360 + j*(-320) -153 + j*(227) --165 + j*(87) -34 + j*(-18) -3 + j*(229) -1 + j*(49) -245 + j*(140) --162 + j*(89) --110 + j*(-125) --93 + j*(202) -109 + j*(-93) -90 + j*(-56) -358 + j*(151) -286 + j*(-158) -182 + j*(-62) --204 + j*(49) -20 + j*(279) --105 + j*(-283) --83 + j*(43) --13 + j*(-51) --68 + j*(176) --152 + j*(-12) --129 + j*(231) -9 + j*(143) -102 + j*(-153) --134 + j*(-113) -34 + j*(174) --151 + j*(180) --45 + j*(-171) -206 + j*(-89) -154 + j*(144) --146 + j*(-276) -216 + j*(57) -495 + j*(30) --177 + j*(25) -97 + j*(240) --84 + j*(-176) --194 + j*(-102) -33 + j*(-204) -181 + j*(-70) --52 + j*(280) -47 + j*(64) --77 + j*(67) -408 + j*(27) -171 + j*(74) --318 + j*(177) -98 + j*(136) --166 + j*(124) -21 + j*(223) --105 + j*(143) --185 + j*(162) -11 + j*(6) -218 + j*(118) --149 + j*(190) -42 + j*(121) --117 + j*(100) --86 + j*(32) -13 + j*(-127) -13 + j*(-260) -102 + j*(49) -173 + j*(210) -110 + j*(-64) --13 + j*(329) -145 + j*(-61) -44 + j*(-65) --110 + j*(-280) -226 + j*(-64) -207 + j*(205) --9 + j*(-98) --291 + j*(-194) -59 + j*(129) --104 + j*(-78) -13 + j*(-115) -2 + j*(-84) -47 + j*(-117) --182 + j*(-156) -371 + j*(66) --185 + j*(249) --360 + j*(-141) -74 + j*(-243) -150 + j*(412) -293 + j*(13) -161 + j*(-319) --52 + j*(250) --81 + j*(-110) -35 + j*(25) -62 + j*(146) --134 + j*(-8) --101 + j*(64) --213 + j*(206) -49 + j*(27) --9 + j*(44) --30 + j*(57) --185 + j*(-103) --175 + j*(-29) --315 + j*(127) -294 + j*(-68) --98 + j*(390) -76 + j*(-11) -216 + j*(272) --136 + j*(5) -44 + j*(210) --3 + j*(-24) -182 + j*(-110) --61 + j*(40) --28 + j*(52) --95 + j*(-206) --57 + j*(230) -182 + j*(-40) -128 + j*(-143) -102 + j*(-54) --83 + j*(28) --37 + j*(-208) --220 + j*(183) -158 + j*(-382) -88 + j*(-19) --25 + j*(-37) -75 + j*(60) --63 + j*(-173) --230 + j*(-128) -112 + j*(-43) --158 + j*(-47) -20 + j*(49) --145 + j*(71) --297 + j*(68) --329 + j*(-21) -245 + j*(-95) --303 + j*(88) --72 + j*(151) --126 + j*(-173) -11 + j*(199) -127 + j*(423) -213 + j*(-18) -230 + j*(17) --110 + j*(-47) -347 + j*(166) -165 + j*(46) --402 + j*(100) --34 + j*(-164) -18 + j*(187) --27 + j*(102) -100 + j*(324) --43 + j*(-269) -118 + j*(-268) --69 + j*(187) -192 + j*(-211) -99 + j*(-127) -262 + j*(42) --93 + j*(-35) --245 + j*(-249) --39 + j*(-274) -115 + j*(-197) -179 + j*(8) -395 + j*(33) -324 + j*(-6) --129 + j*(105) -72 + j*(-66) --239 + j*(-16) --112 + j*(189) --334 + j*(-83) -91 + j*(235) --139 + j*(91) --136 + j*(122) -47 + j*(-132) -453 + j*(-16) --150 + j*(-126) --255 + j*(86) -146 + j*(-169) --31 + j*(158) -98 + j*(132) --260 + j*(86) --20 + j*(145) -77 + j*(-175) --227 + j*(271) --25 + j*(115) -76 + j*(267) --192 + j*(66) --274 + j*(-34) --163 + j*(-132) --155 + j*(-195) -91 + j*(46) --137 + j*(-191) --151 + j*(260) --8 + j*(29) --83 + j*(25) -17 + j*(-16) --430 + j*(494) -212 + j*(55) -134 + j*(86) -188 + j*(-2) --11 + j*(151) -209 + j*(27) --37 + j*(40) --202 + j*(90) --25 + j*(327) -81 + j*(-401) --180 + j*(194) --146 + j*(262) -221 + j*(87) -280 + j*(-118) --30 + j*(15) -164 + j*(91) -45 + j*(-315) --325 + j*(43) --283 + j*(-286) --63 + j*(-174) --220 + j*(-100) -190 + j*(-108) -37 + j*(-11) -148 + j*(-88) --103 + j*(-93) -122 + j*(94) --124 + j*(-273) --59 + j*(-193) -13 + j*(77) -3 + j*(-186) -36 + j*(-62) --219 + j*(232) -103 + j*(71) -54 + j*(47) -13 + j*(52) --356 + j*(119) --124 + j*(152) -77 + j*(33) --83 + j*(148) --40 + j*(-25) -35 + j*(-64) --170 + j*(-244) --301 + j*(-208) --61 + j*(140) --197 + j*(-47) --134 + j*(-243) -34 + j*(269) --169 + j*(-330) -65 + j*(46) -167 + j*(47) --118 + j*(-40) -65 + j*(-15) --16 + j*(211) --63 + j*(107) -50 + j*(120) --194 + j*(9) --97 + j*(90) --226 + j*(-82) -59 + j*(-375) -123 + j*(-107) -112 + j*(63) --95 + j*(146) --209 + j*(91) -278 + j*(-85) -190 + j*(134) -296 + j*(-10) --175 + j*(-175) -136 + j*(-52) -166 + j*(-25) -129 + j*(107) --254 + j*(-54) -132 + j*(6) -137 + j*(95) --457 + j*(-166) --146 + j*(34) --46 + j*(-144) -32 + j*(291) -143 + j*(168) -108 + j*(14) -25 + j*(-109) --262 + j*(148) --111 + j*(-62) -170 + j*(-84) --148 + j*(217) --279 + j*(-161) --50 + j*(-172) -261 + j*(-89) --186 + j*(31) --35 + j*(201) --392 + j*(-57) --43 + j*(291) --125 + j*(65) -157 + j*(-12) --43 + j*(40) -173 + j*(-97) -231 + j*(-39) -40 + j*(-25) --184 + j*(-57) -31 + j*(-173) --262 + j*(74) -6 + j*(214) -37 + j*(-114) --296 + j*(-238) -115 + j*(-8) -17 + j*(-50) --165 + j*(134) --115 + j*(127) --419 + j*(-182) --29 + j*(-102) -49 + j*(348) --173 + j*(-4) --431 + j*(31) --60 + j*(21) --130 + j*(-76) --278 + j*(-74) --156 + j*(-45) -383 + j*(187) -241 + j*(-255) -105 + j*(-116) --6 + j*(-184) -327 + j*(-173) --32 + j*(39) -23 + j*(78) -35 + j*(0) -116 + j*(-264) --10 + j*(-5) --44 + j*(110) --103 + j*(-112) --506 + j*(227) -144 + j*(-71) -150 + j*(43) -45 + j*(344) --286 + j*(-126) -24 + j*(-301) --136 + j*(-288) -23 + j*(-66) --247 + j*(-122) -2 + j*(-254) --434 + j*(-101) --262 + j*(86) --265 + j*(-110) --293 + j*(115) --11 + j*(361) -249 + j*(-121) --88 + j*(35) --232 + j*(-86) -296 + j*(8) --125 + j*(4) --14 + j*(-228) --212 + j*(259) -30 + j*(207) -165 + j*(-69) -454 + j*(0) --282 + j*(71) -41 + j*(-194) -264 + j*(-13) --313 + j*(129) -82 + j*(106) -76 + j*(-2) -245 + j*(-102) --92 + j*(245) -242 + j*(-47) --132 + j*(-83) -231 + j*(-56) --64 + j*(-59) --94 + j*(-115) -241 + j*(154) --261 + j*(-173) --56 + j*(157) --54 + j*(-21) --180 + j*(28) -144 + j*(104) -64 + j*(23) --93 + j*(-354) -189 + j*(185) --110 + j*(-22) -209 + j*(-222) -79 + j*(-39) -217 + j*(-105) --21 + j*(-139) -91 + j*(205) -195 + j*(-93) --6 + j*(-144) --231 + j*(117) --18 + j*(-35) -87 + j*(190) -152 + j*(56) -248 + j*(66) --3 + j*(-235) --81 + j*(132) --59 + j*(315) --289 + j*(142) -100 + j*(-118) --191 + j*(355) -52 + j*(-271) -1 + j*(-161) --151 + j*(-81) -198 + j*(357) --202 + j*(-13) -19 + j*(-220) -188 + j*(-258) -90 + j*(105) --168 + j*(25) -37 + j*(-505) -281 + j*(-93) --241 + j*(-156) -49 + j*(-28) -16 + j*(-299) -151 + j*(-229) --42 + j*(136) --228 + j*(43) --124 + j*(148) --7 + j*(19) -250 + j*(-66) -207 + j*(118) -80 + j*(28) --22 + j*(61) -190 + j*(-61) -206 + j*(-161) -27 + j*(-344) --176 + j*(-18) -233 + j*(-76) -64 + j*(-87) -334 + j*(-81) -216 + j*(-3) -1 + j*(499) -57 + j*(-66) --123 + j*(-246) --329 + j*(-81) --113 + j*(-94) -41 + j*(204) --194 + j*(-10) --52 + j*(116) --80 + j*(33) --271 + j*(-388) --288 + j*(-45) --65 + j*(-40) -118 + j*(-59) -296 + j*(-220) --175 + j*(57) -4 + j*(71) --124 + j*(62) -153 + j*(95) -209 + j*(209) -132 + j*(293) --72 + j*(-90) -378 + j*(3) -57 + j*(266) --354 + j*(42) -84 + j*(-270) --52 + j*(303) -211 + j*(-53) -132 + j*(-156) -375 + j*(37) --21 + j*(87) -381 + j*(-107) -86 + j*(-33) -98 + j*(21) --189 + j*(-212) --138 + j*(-247) -330 + j*(-127) -34 + j*(-63) -181 + j*(139) --86 + j*(144) -206 + j*(-378) -165 + j*(29) --133 + j*(183) -52 + j*(-56) --140 + j*(123) --123 + j*(68) --13 + j*(243) --144 + j*(-129) --265 + j*(-195) -148 + j*(139) -117 + j*(-42) --105 + j*(-67) --64 + j*(-123) -20 + j*(-232) --250 + j*(85) --117 + j*(-41) --474 + j*(269) -76 + j*(-93) -23 + j*(-175) --138 + j*(191) -13 + j*(-97) -15 + j*(395) -71 + j*(56) --91 + j*(74) --180 + j*(134) --23 + j*(90) -110 + j*(313) --309 + j*(-167) -13 + j*(44) -146 + j*(276) -105 + j*(-266) --9 + j*(-158) -69 + j*(-4) --45 + j*(-214) -148 + j*(69) -95 + j*(98) -322 + j*(-187) --102 + j*(-109) --287 + j*(66) --108 + j*(-247) -62 + j*(112) -86 + j*(-119) -75 + j*(65) --5 + j*(192) --112 + j*(0) -301 + j*(-56) --206 + j*(83) --30 + j*(192) --293 + j*(-1) -167 + j*(98) -144 + j*(-275) -76 + j*(80) --81 + j*(314) --132 + j*(-187) --124 + j*(-295) --412 + j*(339) -49 + j*(-5) --10 + j*(-172) --36 + j*(-47) --112 + j*(-105) -171 + j*(441) --104 + j*(-93) -128 + j*(211) --76 + j*(-84) -84 + j*(350) -47 + j*(-100) --137 + j*(-182) --22 + j*(-212) -8 + j*(100) --58 + j*(252) -55 + j*(40) --95 + j*(127) -252 + j*(-148) --147 + j*(-35) -202 + j*(-465) -127 + j*(-109) --136 + j*(-75) -122 + j*(67) -34 + j*(-97) --622 + j*(-2) -240 + j*(49) -230 + j*(95) --16 + j*(33) -129 + j*(178) --92 + j*(131) --146 + j*(-288) --11 + j*(-154) -243 + j*(-119) --293 + j*(-419) -12 + j*(146) -11 + j*(258) --267 + j*(-30) -378 + j*(180) --145 + j*(-53) --152 + j*(-247) --127 + j*(-30) -244 + j*(-144) --57 + j*(107) -324 + j*(203) -158 + j*(-66) -308 + j*(-268) -119 + j*(-105) --98 + j*(127) --189 + j*(-178) --35 + j*(-40) -142 + j*(378) --226 + j*(-28) -273 + j*(-14) -65 + j*(-8) --95 + j*(-134) --35 + j*(83) -49 + j*(157) --52 + j*(-219) -14 + j*(280) --33 + j*(-86) -86 + j*(-61) --508 + j*(-100) -161 + j*(-415) --86 + j*(-105) -65 + j*(-98) -233 + j*(69) --90 + j*(115) -47 + j*(171) --141 + j*(-136) -70 + j*(-102) --40 + j*(-204) --239 + j*(-93) -192 + j*(155) --231 + j*(32) --45 + j*(-419) -20 + j*(-41) -7 + j*(42) -258 + j*(-222) -98 + j*(-2) --13 + j*(62) --309 + j*(-131) -158 + j*(96) --309 + j*(-138) --322 + j*(-272) -168 + j*(-258) --395 + j*(131) -187 + j*(-576) --81 + j*(-438) --147 + j*(-62) --220 + j*(-71) --203 + j*(-38) -184 + j*(113) -0 + j*(-317) -167 + j*(-6) --226 + j*(78) --146 + j*(-158) --223 + j*(21) --170 + j*(70) -21 + j*(-109) --54 + j*(103) -407 + j*(-218) --4 + j*(-20) -207 + j*(-315) --80 + j*(-86) -180 + j*(-165) --144 + j*(289) -146 + j*(262) -38 + j*(-47) -352 + j*(281) -290 + j*(-41) --28 + j*(-112) -38 + j*(323) --56 + j*(-105) --68 + j*(74) -249 + j*(117) -13 + j*(223) --66 + j*(356) --146 + j*(-142) --55 + j*(216) -181 + j*(215) -252 + j*(74) -143 + j*(-118) -93 + j*(125) -29 + j*(22) --83 + j*(-94) -66 + j*(21) --62 + j*(146) -264 + j*(-65) --211 + j*(389) --119 + j*(245) -24 + j*(-66) -71 + j*(22) --1 + j*(-225) -80 + j*(-397) --206 + j*(-12) --6 + j*(158) -87 + j*(251) --8 + j*(139) --56 + j*(126) --327 + j*(45) -37 + j*(-74) --45 + j*(381) -94 + j*(-11) --6 + j*(46) --115 + j*(-161) -171 + j*(-400) --3 + j*(44) --228 + j*(208) --20 + j*(-47) --117 + j*(-197) --104 + j*(89) -102 + j*(-254) -76 + j*(-246) --368 + j*(-77) -49 + j*(107) -47 + j*(53) -87 + j*(-298) -199 + j*(-163) -116 + j*(-85) -25 + j*(-167) --1 + j*(74) --2 + j*(-13) -54 + j*(-91) -76 + j*(-262) -72 + j*(-146) --135 + j*(-182) -6 + j*(-18) --217 + j*(178) --46 + j*(69) --9 + j*(-42) --65 + j*(-80) --28 + j*(-10) --97 + j*(-62) -158 + j*(-168) -106 + j*(2) --184 + j*(-18) --233 + j*(16) -158 + j*(294) --172 + j*(-383) --199 + j*(-178) -125 + j*(-46) --41 + j*(17) --365 + j*(247) -262 + j*(-253) --105 + j*(72) --32 + j*(141) --2 + j*(-19) -143 + j*(-65) -42 + j*(125) -37 + j*(-173) -123 + j*(47) -45 + j*(-98) --40 + j*(143) -28 + j*(-257) -97 + j*(-254) -170 + j*(-148) --200 + j*(-47) --126 + j*(158) --278 + j*(21) -124 + j*(130) --147 + j*(-42) -8 + j*(200) --85 + j*(-76) -237 + j*(37) --167 + j*(184) -175 + j*(235) --180 + j*(380) --506 + j*(-137) --172 + j*(148) --28 + j*(23) -18 + j*(-223) --82 + j*(166) -11 + j*(121) -83 + j*(216) --210 + j*(-182) --269 + j*(99) -333 + j*(-19) --129 + j*(-68) -281 + j*(-123) --8 + j*(-74) --146 + j*(36) -91 + j*(-126) --94 + j*(45) --42 + j*(-46) -62 + j*(464) -89 + j*(-21) --281 + j*(67) -101 + j*(-325) -40 + j*(270) --163 + j*(107) --337 + j*(-230) --49 + j*(-117) -94 + j*(200) --100 + j*(119) --252 + j*(49) -164 + j*(40) -337 + j*(72) --47 + j*(-204) --224 + j*(-218) --180 + j*(218) -1 + j*(221) -221 + j*(-285) -259 + j*(-113) --71 + j*(366) --113 + j*(-133) -59 + j*(-132) -82 + j*(-6) --69 + j*(21) --182 + j*(-43) --27 + j*(-281) -80 + j*(-69) --54 + j*(-49) -91 + j*(-78) -214 + j*(-64) --216 + j*(246) --180 + j*(11) -81 + j*(-48) --34 + j*(-7) --8 + j*(57) --26 + j*(45) --324 + j*(264) -185 + j*(-170) --119 + j*(-197) -28 + j*(132) -16 + j*(67) -403 + j*(142) -152 + j*(152) --22 + j*(388) -44 + j*(0) -42 + j*(11) -35 + j*(-54) -182 + j*(-73) -153 + j*(-13) -159 + j*(-34) -316 + j*(83) -289 + j*(194) --134 + j*(-163) -87 + j*(117) -95 + j*(-318) -108 + j*(-79) --322 + j*(431) --1 + j*(314) -69 + j*(-359) -117 + j*(-21) --343 + j*(198) --25 + j*(-99) --10 + j*(-103) --76 + j*(182) --164 + j*(-390) --95 + j*(40) --181 + j*(182) --129 + j*(-161) --130 + j*(111) --20 + j*(1) --223 + j*(49) --129 + j*(119) --90 + j*(-31) -163 + j*(-215) --130 + j*(-217) -111 + j*(30) -40 + j*(63) --132 + j*(1) --240 + j*(-94) -301 + j*(-80) --62 + j*(-7) -85 + j*(-55) -144 + j*(4) --60 + j*(11) --43 + j*(-144) --178 + j*(136) -125 + j*(133) --44 + j*(124) -41 + j*(190) -75 + j*(223) --161 + j*(-218) -131 + j*(7) -21 + j*(102) --467 + j*(-260) -250 + j*(-82) -99 + j*(83) --223 + j*(349) --216 + j*(-151) -129 + j*(-349) -243 + j*(-324) -178 + j*(52) -194 + j*(-74) -146 + j*(200) -136 + j*(43) --378 + j*(-235) --290 + j*(151) -407 + j*(159) --139 + j*(-40) -130 + j*(-59) -135 + j*(353) -89 + j*(100) --30 + j*(-180) --50 + j*(-217) -76 + j*(-12) --197 + j*(-5) --296 + j*(0) --256 + j*(119) -233 + j*(-107) -16 + j*(-327) --274 + j*(325) -91 + j*(24) -47 + j*(-30) -211 + j*(-159) -277 + j*(18) -138 + j*(3) --142 + j*(-59) -212 + j*(-37) -97 + j*(382) -381 + j*(126) -221 + j*(-418) -328 + j*(-99) --93 + j*(-224) --30 + j*(-151) --246 + j*(-29) -230 + j*(13) -97 + j*(242) -8 + j*(-52) --58 + j*(141) -33 + j*(-67) --415 + j*(-201) --23 + j*(-113) --18 + j*(-187) -245 + j*(-151) -69 + j*(-96) --143 + j*(117) -179 + j*(47) -87 + j*(-223) --263 + j*(-198) --29 + j*(-86) -287 + j*(158) --59 + j*(113) -184 + j*(95) -264 + j*(42) --146 + j*(232) --67 + j*(-57) -19 + j*(-152) -187 + j*(182) --253 + j*(-218) -134 + j*(207) -91 + j*(-161) -131 + j*(-104) -132 + j*(-75) -95 + j*(427) --11 + j*(-45) --13 + j*(-20) --47 + j*(227) -86 + j*(66) -94 + j*(-35) --11 + j*(-71) --160 + j*(56) -36 + j*(255) -276 + j*(-119) -49 + j*(108) --98 + j*(-81) --76 + j*(-313) -240 + j*(4) --160 + j*(21) -8 + j*(-165) --163 + j*(261) --270 + j*(-73) -187 + j*(110) --86 + j*(-165) -214 + j*(134) --33 + j*(-112) --421 + j*(278) -19 + j*(46) -53 + j*(228) --442 + j*(-151) -69 + j*(59) --86 + j*(55) -50 + j*(-371) --199 + j*(113) --13 + j*(172) -168 + j*(52) -384 + j*(291) --89 + j*(-129) --343 + j*(-387) --37 + j*(300) --37 + j*(-66) --209 + j*(-116) -112 + j*(2) -87 + j*(-80) --272 + j*(-38) --51 + j*(40) --221 + j*(-138) --182 + j*(-378) --461 + j*(-30) --141 + j*(-149) -269 + j*(-55) -122 + j*(68) -122 + j*(33) --153 + j*(-116) --47 + j*(-1) -285 + j*(30) -102 + j*(-137) -50 + j*(-193) --409 + j*(-35) --162 + j*(171) -354 + j*(41) --216 + j*(101) -33 + j*(256) --114 + j*(203) --353 + j*(-30) -42 + j*(-177) --2 + j*(95) --100 + j*(-156) --117 + j*(-155) --144 + j*(-4) --138 + j*(-194) -33 + j*(-209) --113 + j*(6) --361 + j*(190) -153 + j*(-317) --49 + j*(81) --70 + j*(-52) -104 + j*(-284) -131 + j*(113) -28 + j*(6) -18 + j*(71) -47 + j*(100) -126 + j*(-6) --138 + j*(199) -18 + j*(-209) -158 + j*(-37) -237 + j*(-211) -277 + j*(-17) -87 + j*(151) --173 + j*(-153) -147 + j*(-314) --79 + j*(247) -128 + j*(-87) -26 + j*(-173) -236 + j*(-258) --177 + j*(25) --112 + j*(-148) --136 + j*(-163) --16 + j*(-223) --124 + j*(218) --49 + j*(-257) --156 + j*(-51) --25 + j*(-276) -88 + j*(1) --191 + j*(-42) --81 + j*(-92) -138 + j*(419) -2 + j*(88) --1 + j*(84) -119 + j*(194) --129 + j*(-187) --151 + j*(-66) --141 + j*(11) -107 + j*(-457) -256 + j*(140) -1 + j*(218) -130 + j*(134) -122 + j*(62) -96 + j*(-102) -72 + j*(-88) -59 + j*(-168) --111 + j*(-354) -189 + j*(-89) -224 + j*(-129) --127 + j*(88) -1 + j*(357) -139 + j*(163) -147 + j*(244) -100 + j*(94) -269 + j*(6) -13 + j*(-315) -71 + j*(-104) --110 + j*(30) -18 + j*(-172) --40 + j*(-19) --182 + j*(307) -129 + j*(344) --29 + j*(-144) --138 + j*(-13) -361 + j*(-96) --143 + j*(105) --92 + j*(-118) -16 + j*(52) --119 + j*(187) -296 + j*(-150) --188 + j*(-91) --7 + j*(-250) -83 + j*(-74) --110 + j*(113) --170 + j*(331) --52 + j*(-16) -97 + j*(-301) --269 + j*(-31) --89 + j*(69) -84 + j*(-25) -161 + j*(-239) --80 + j*(156) -148 + j*(-129) -191 + j*(196) --153 + j*(43) --117 + j*(-74) --46 + j*(-340) --41 + j*(-180) -53 + j*(-113) -182 + j*(195) -208 + j*(221) -6 + j*(14) -144 + j*(73) --83 + j*(-97) -30 + j*(223) --98 + j*(-148) --493 + j*(-247) --386 + j*(32) --112 + j*(326) -41 + j*(-60) -155 + j*(-324) -42 + j*(-76) --39 + j*(-154) -123 + j*(409) --132 + j*(-122) -209 + j*(-33) --313 + j*(55) -235 + j*(189) --382 + j*(339) -87 + j*(-11) -101 + j*(1) -186 + j*(-173) -23 + j*(-135) -427 + j*(74) -280 + j*(-122) --69 + j*(-35) -247 + j*(-23) -112 + j*(-204) -110 + j*(-6) --303 + j*(14) -245 + j*(250) --73 + j*(-16) -35 + j*(123) -49 + j*(49) --154 + j*(-42) --281 + j*(-35) --308 + j*(151) -151 + j*(22) -45 + j*(-136) --244 + j*(-184) --175 + j*(-62) -38 + j*(231) -6 + j*(98) --51 + j*(-29) --168 + j*(-286) -60 + j*(-317) -53 + j*(221) --120 + j*(98) --54 + j*(-115) -93 + j*(-67) -139 + j*(57) --66 + j*(108) --183 + j*(54) --59 + j*(-28) --165 + j*(35) --184 + j*(29) --275 + j*(165) -377 + j*(17) --283 + j*(-351) -42 + j*(141) -90 + j*(-40) --74 + j*(-148) -53 + j*(353) -4 + j*(-133) -440 + j*(-84) --33 + j*(113) -83 + j*(76) --175 + j*(-44) -69 + j*(-90) -103 + j*(135) -156 + j*(92) --122 + j*(-37) -48 + j*(-104) -250 + j*(-129) -88 + j*(190) --170 + j*(335) --293 + j*(20) -40 + j*(-365) -140 + j*(-265) -340 + j*(49) --47 + j*(135) -330 + j*(-47) --25 + j*(-161) --59 + j*(112) -185 + j*(186) -125 + j*(-295) --45 + j*(554) -100 + j*(13) -52 + j*(40) --13 + j*(-54) --218 + j*(-153) -11 + j*(-43) --39 + j*(3) -10 + j*(-15) --298 + j*(9) -123 + j*(-210) -179 + j*(-168) -211 + j*(-169) -250 + j*(216) -74 + j*(-95) --288 + j*(59) --35 + j*(135) -23 + j*(127) --22 + j*(190) --76 + j*(-112) -180 + j*(-251) -226 + j*(-145) -30 + j*(37) -79 + j*(137) -83 + j*(-292) -209 + j*(-6) --307 + j*(-122) -119 + j*(-90) -26 + j*(-105) --28 + j*(-279) --95 + j*(-34) --57 + j*(-282) --361 + j*(-175) --83 + j*(-77) --74 + j*(16) -370 + j*(52) --276 + j*(-269) -285 + j*(-62) --129 + j*(-197) --21 + j*(-14) --3 + j*(45) -371 + j*(43) --213 + j*(-98) -196 + j*(23) -187 + j*(62) --165 + j*(173) -61 + j*(-60) -194 + j*(-329) --269 + j*(-18) -160 + j*(-72) -62 + j*(284) -47 + j*(-228) --74 + j*(294) -64 + j*(78) -37 + j*(-100) --81 + j*(50) -18 + j*(-113) -157 + j*(217) -188 + j*(355) -37 + j*(-31) -176 + j*(-282) -190 + j*(28) -81 + j*(-1) --202 + j*(311) --52 + j*(120) --18 + j*(17) --330 + j*(-110) --84 + j*(472) -51 + j*(234) --144 + j*(366) --25 + j*(12) --69 + j*(-14) -540 + j*(-155) -52 + j*(81) -174 + j*(-171) -117 + j*(-86) --15 + j*(-315) -154 + j*(135) -107 + j*(97) --119 + j*(-209) -67 + j*(-233) -14 + j*(58) --94 + j*(159) --81 + j*(1) -107 + j*(-90) --29 + j*(38) --565 + j*(-190) --35 + j*(36) -255 + j*(220) --25 + j*(18) --337 + j*(-27) -89 + j*(-148) --89 + j*(-141) --12 + j*(20) -69 + j*(-27) -228 + j*(-64) -112 + j*(-27) --181 + j*(81) --102 + j*(-2) -61 + j*(257) --170 + j*(8) --4 + j*(-171) --119 + j*(-27) --156 + j*(10) -315 + j*(-231) -264 + j*(260) --37 + j*(129) -69 + j*(-72) -121 + j*(146) --37 + j*(221) --195 + j*(1) -301 + j*(107) -221 + j*(16) --313 + j*(-181) --51 + j*(-94) -140 + j*(-295) -6 + j*(-176) --135 + j*(4) --49 + j*(355) -87 + j*(69) --40 + j*(-108) -81 + j*(187) -51 + j*(-194) --98 + j*(175) --280 + j*(127) -194 + j*(-100) --287 + j*(185) --28 + j*(14) -57 + j*(55) --313 + j*(-42) -175 + j*(-13) --138 + j*(136) --7 + j*(27) -16 + j*(214) --4 + j*(70) --28 + j*(-166) --91 + j*(214) --64 + j*(-305) -293 + j*(-61) -268 + j*(182) -153 + j*(23) --50 + j*(-63) -57 + j*(-17) --127 + j*(47) --107 + j*(-67) -68 + j*(83) -38 + j*(-78) --169 + j*(-76) -132 + j*(134) -202 + j*(197) --224 + j*(140) --37 + j*(643) --233 + j*(16) --227 + j*(-88) --168 + j*(-213) -63 + j*(-224) -88 + j*(28) -8 + j*(165) --273 + j*(-146) --140 + j*(-8) --100 + j*(13) --232 + j*(1) --223 + j*(93) --132 + j*(-45) --20 + j*(248) -156 + j*(-44) -74 + j*(-89) -88 + j*(26) -161 + j*(-94) --11 + j*(-143) --145 + j*(124) --33 + j*(30) -485 + j*(173) -249 + j*(-310) --246 + j*(164) --104 + j*(134) --126 + j*(184) --135 + j*(259) -18 + j*(79) --115 + j*(67) --190 + j*(-126) --159 + j*(183) -184 + j*(-190) -390 + j*(-129) --35 + j*(-129) -342 + j*(363) -110 + j*(-233) -158 + j*(-269) -15 + j*(-55) --204 + j*(-508) -11 + j*(165) --346 + j*(-145) --168 + j*(75) --175 + j*(-120) --25 + j*(294) --119 + j*(337) --119 + j*(111) -11 + j*(-257) --141 + j*(-127) -116 + j*(57) --173 + j*(30) --138 + j*(68) --71 + j*(-35) -14 + j*(250) --11 + j*(-57) -57 + j*(-279) -74 + j*(274) --81 + j*(64) --378 + j*(-80) --279 + j*(211) --79 + j*(194) --6 + j*(261) -156 + j*(-58) --8 + j*(-139) -239 + j*(-23) --117 + j*(-64) --107 + j*(41) --198 + j*(-283) --91 + j*(-135) --43 + j*(-13) -99 + j*(30) -4 + j*(105) --276 + j*(319) --298 + j*(-84) --7 + j*(-237) --286 + j*(9) -74 + j*(122) -10 + j*(344) --185 + j*(161) -139 + j*(187) --332 + j*(-48) --35 + j*(-204) --7 + j*(-144) --6 + j*(266) -78 + j*(25) -37 + j*(78) -96 + j*(183) --107 + j*(-141) -66 + j*(-433) --127 + j*(-27) --96 + j*(138) --1 + j*(-129) --351 + j*(71) --324 + j*(202) --93 + j*(-97) -73 + j*(153) -115 + j*(-252) -156 + j*(172) --312 + j*(-143) --336 + j*(-115) --119 + j*(-85) -47 + j*(-141) -300 + j*(174) --219 + j*(57) -102 + j*(-172) -45 + j*(390) -17 + j*(-127) -31 + j*(135) -344 + j*(83) --76 + j*(140) -53 + j*(57) -199 + j*(192) --69 + j*(165) -5 + j*(216) -525 + j*(152) --233 + j*(-83) --221 + j*(283) -50 + j*(12) -214 + j*(-559) --118 + j*(-131) --77 + j*(-31) --30 + j*(-192) -130 + j*(-141) -215 + j*(296) --64 + j*(65) -209 + j*(-41) -81 + j*(219) --110 + j*(-412) -119 + j*(130) -199 + j*(-42) -72 + j*(-13) --223 + j*(53) -45 + j*(28) -262 + j*(-16) -11 + j*(78) -182 + j*(-139) -73 + j*(211) -183 + j*(11) --7 + j*(171) -65 + j*(-11) --12 + j*(-45) -10 + j*(251) -110 + j*(-240) -187 + j*(-95) --42 + j*(-128) -26 + j*(117) --77 + j*(128) --45 + j*(70) -74 + j*(-117) --28 + j*(109) --175 + j*(-98) -119 + j*(204) -8 + j*(298) --43 + j*(-71) -105 + j*(107) --46 + j*(31) --23 + j*(-230) --141 + j*(-225) --245 + j*(-98) --115 + j*(-24) -52 + j*(330) --5 + j*(218) --179 + j*(37) -50 + j*(52) -40 + j*(127) --165 + j*(-45) -199 + j*(-132) -242 + j*(-7) --489 + j*(-55) --220 + j*(-413) -80 + j*(-27) --104 + j*(103) --245 + j*(383) --40 + j*(-466) -197 + j*(144) --98 + j*(13) --8 + j*(345) -335 + j*(190) -42 + j*(35) -157 + j*(58) -175 + j*(-229) -284 + j*(-218) -421 + j*(283) -272 + j*(-241) --252 + j*(157) --209 + j*(22) --40 + j*(-61) --30 + j*(84) -293 + j*(-244) --286 + j*(241) --197 + j*(-78) --107 + j*(-2) --329 + j*(-105) -93 + j*(-472) -187 + j*(-107) --279 + j*(150) --337 + j*(211) -117 + j*(-244) --221 + j*(267) -224 + j*(70) -174 + j*(168) --124 + j*(-14) -16 + j*(-190) --207 + j*(305) -143 + j*(54) --124 + j*(30) -43 + j*(-15) --67 + j*(-205) -21 + j*(-163) -157 + j*(-183) --59 + j*(-42) --53 + j*(-147) -231 + j*(30) --61 + j*(-77) -4 + j*(-422) --378 + j*(259) -74 + j*(-154) -36 + j*(153) --182 + j*(-66) -189 + j*(-37) --129 + j*(-29) -46 + j*(-117) --88 + j*(-76) --23 + j*(164) --111 + j*(-12) --228 + j*(-86) -134 + j*(-25) --142 + j*(93) --182 + j*(25) -215 + j*(-70) -181 + j*(-52) -212 + j*(156) -421 + j*(-248) -52 + j*(-489) -36 + j*(86) -105 + j*(-277) -283 + j*(-57) -250 + j*(73) -86 + j*(-120) --230 + j*(-105) --86 + j*(-75) --118 + j*(88) -59 + j*(-71) --106 + j*(-66) --314 + j*(-8) --16 + j*(270) --138 + j*(189) --151 + j*(-110) -365 + j*(-158) --216 + j*(-23) -4 + j*(181) --245 + j*(88) --132 + j*(202) --115 + j*(-160) -69 + j*(310) -47 + j*(45) -104 + j*(72) -260 + j*(204) --190 + j*(46) --192 + j*(312) -8 + j*(-155) --162 + j*(90) --115 + j*(44) --37 + j*(-298) --72 + j*(238) -170 + j*(310) -72 + j*(248) --28 + j*(151) -103 + j*(-130) -78 + j*(-173) -120 + j*(-121) -435 + j*(-305) --20 + j*(45) --93 + j*(235) -66 + j*(-35) -204 + j*(4) --134 + j*(50) --397 + j*(-16) -91 + j*(166) -112 + j*(-139) --42 + j*(-366) -25 + j*(223) -79 + j*(-212) --67 + j*(-242) --235 + j*(-83) --160 + j*(62) -124 + j*(347) -110 + j*(-49) -127 + j*(49) -167 + j*(-341) --427 + j*(-66) --172 + j*(82) --130 + j*(-25) --9 + j*(-11) -99 + j*(252) --225 + j*(-153) --220 + j*(175) -141 + j*(122) -110 + j*(288) --286 + j*(149) --47 + j*(218) -322 + j*(127) -159 + j*(101) --252 + j*(185) --443 + j*(-124) -10 + j*(165) -182 + j*(169) --32 + j*(-81) --44 + j*(-41) --229 + j*(50) -157 + j*(421) --155 + j*(-18) --85 + j*(-13) -148 + j*(-432) --298 + j*(-108) --260 + j*(219) -272 + j*(-179) -35 + j*(-123) -137 + j*(8) -29 + j*(-116) -84 + j*(167) -308 + j*(-47) -204 + j*(64) -339 + j*(-60) --224 + j*(-70) -186 + j*(730) --59 + j*(86) -66 + j*(-30) --16 + j*(-260) --309 + j*(200) --143 + j*(-127) -33 + j*(-50) -12 + j*(-74) --113 + j*(-52) --31 + j*(197) -330 + j*(197) -264 + j*(-106) -214 + j*(-164) --8 + j*(431) --143 + j*(66) -98 + j*(66) --65 + j*(92) -233 + j*(145) --93 + j*(133) -28 + j*(-104) --283 + j*(89) -91 + j*(-319) -53 + j*(111) -57 + j*(139) -90 + j*(88) -45 + j*(66) --43 + j*(140) -307 + j*(127) -173 + j*(-86) -115 + j*(-327) -255 + j*(-238) -212 + j*(-170) -173 + j*(279) -49 + j*(142) -6 + j*(3) -218 + j*(184) --39 + j*(-110) --10 + j*(-238) -30 + j*(303) -35 + j*(-55) -6 + j*(-54) -140 + j*(-167) -62 + j*(52) -204 + j*(-169) --64 + j*(163) --135 + j*(70) -82 + j*(63) -21 + j*(80) --81 + j*(-139) --84 + j*(76) --129 + j*(-13) --10 + j*(-159) -27 + j*(192) --158 + j*(118) -81 + j*(-167) -64 + j*(-67) --82 + j*(48) --18 + j*(102) --343 + j*(83) -161 + j*(-159) --10 + j*(460) --13 + j*(-252) -148 + j*(-252) --69 + j*(61) --152 + j*(48) -38 + j*(137) -90 + j*(40) -39 + j*(-65) -85 + j*(244) --76 + j*(-138) --209 + j*(59) --16 + j*(-194) -424 + j*(175) --57 + j*(-143) -21 + j*(239) -93 + j*(93) -75 + j*(151) --66 + j*(-127) -124 + j*(57) -78 + j*(142) --124 + j*(107) --184 + j*(-105) --43 + j*(83) -86 + j*(50) --46 + j*(1) -108 + j*(-211) -47 + j*(-100) --136 + j*(-327) -45 + j*(124) -471 + j*(-310) --72 + j*(52) --329 + j*(-104) -34 + j*(260) -433 + j*(-45) --202 + j*(-414) --115 + j*(-4) --67 + j*(143) --21 + j*(462) -74 + j*(-28) --301 + j*(-155) -107 + j*(-202) --85 + j*(26) --31 + j*(322) -416 + j*(352) --236 + j*(-16) -15 + j*(235) --250 + j*(120) --171 + j*(-234) -380 + j*(-51) -301 + j*(91) -118 + j*(79) -20 + j*(-35) -106 + j*(175) --217 + j*(-156) -146 + j*(156) --88 + j*(237) -573 + j*(-96) -68 + j*(90) -31 + j*(-156) --256 + j*(41) -119 + j*(249) -40 + j*(115) -82 + j*(131) -71 + j*(67) --373 + j*(37) -78 + j*(-76) --20 + j*(71) --38 + j*(-23) -117 + j*(-29) --78 + j*(-358) --199 + j*(-98) -228 + j*(165) -51 + j*(-88) --136 + j*(300) -76 + j*(46) --58 + j*(-200) -82 + j*(-96) --204 + j*(-250) -209 + j*(462) --178 + j*(20) --187 + j*(236) -296 + j*(-223) --211 + j*(-119) --232 + j*(199) --223 + j*(-18) -101 + j*(165) --349 + j*(-64) --121 + j*(-27) --192 + j*(513) -35 + j*(-97) -139 + j*(103) -209 + j*(-49) -97 + j*(73) -105 + j*(3) -54 + j*(-61) --60 + j*(257) -112 + j*(57) -193 + j*(-144) -88 + j*(24) -150 + j*(-133) -42 + j*(90) -409 + j*(-157) --37 + j*(-123) -156 + j*(136) --146 + j*(61) -153 + j*(-356) --45 + j*(-37) --69 + j*(198) --408 + j*(202) --18 + j*(102) -259 + j*(-2) -220 + j*(-238) --82 + j*(-42) -68 + j*(65) --25 + j*(144) -303 + j*(-100) -6 + j*(81) --25 + j*(47) -106 + j*(245) --204 + j*(-276) -59 + j*(23) --472 + j*(161) --196 + j*(-26) -266 + j*(-304) -132 + j*(-221) --108 + j*(28) --82 + j*(-34) --107 + j*(-3) --110 + j*(91) --11 + j*(-317) -106 + j*(76) -28 + j*(-119) -32 + j*(-52) --256 + j*(33) --46 + j*(-450) --10 + j*(-294) -454 + j*(-266) -89 + j*(-168) -100 + j*(-173) -240 + j*(71) -69 + j*(-199) --110 + j*(71) --36 + j*(18) --145 + j*(103) --317 + j*(-51) -11 + j*(62) -184 + j*(78) -182 + j*(-217) --168 + j*(-93) --58 + j*(75) --173 + j*(-167) --139 + j*(153) -47 + j*(-235) -128 + j*(-67) --226 + j*(143) --220 + j*(-101) -240 + j*(-123) --86 + j*(-377) -52 + j*(30) --39 + j*(-147) -236 + j*(-35) -150 + j*(-226) --52 + j*(-192) --37 + j*(187) --201 + j*(52) --146 + j*(116) --168 + j*(123) -54 + j*(-331) --33 + j*(-58) --139 + j*(-2) -23 + j*(-123) -94 + j*(-83) -127 + j*(158) --29 + j*(-93) -148 + j*(269) --21 + j*(227) --178 + j*(-3) --72 + j*(-140) -35 + j*(13) --14 + j*(122) --113 + j*(63) --177 + j*(6) --291 + j*(250) --184 + j*(260) --119 + j*(-229) --255 + j*(-19) --83 + j*(-202) -14 + j*(-102) --83 + j*(91) -100 + j*(-115) --289 + j*(83) --209 + j*(-58) --3 + j*(-247) -164 + j*(-134) -380 + j*(18) -40 + j*(-62) --132 + j*(-80) --1 + j*(-203) --175 + j*(-139) -50 + j*(92) --28 + j*(-29) -181 + j*(40) --241 + j*(40) -221 + j*(166) -81 + j*(-112) -4 + j*(-86) --7 + j*(-132) --78 + j*(-117) --152 + j*(92) --62 + j*(-200) --28 + j*(72) -186 + j*(-240) --9 + j*(148) -81 + j*(-139) --62 + j*(-86) --14 + j*(-98) -125 + j*(-161) --198 + j*(306) --57 + j*(33) -122 + j*(-140) --69 + j*(-103) --66 + j*(308) --9 + j*(206) --63 + j*(33) -175 + j*(15) --42 + j*(-182) -6 + j*(45) --218 + j*(15) --93 + j*(-39) -30 + j*(81) -66 + j*(405) --52 + j*(373) -467 + j*(55) -17 + j*(81) -145 + j*(226) --86 + j*(-193) --112 + j*(-109) -203 + j*(-74) --12 + j*(-225) -52 + j*(-145) --61 + j*(330) -98 + j*(-218) -114 + j*(-56) -31 + j*(-127) --337 + j*(-109) -212 + j*(-71) --111 + j*(-33) -113 + j*(250) -195 + j*(-205) --23 + j*(88) -151 + j*(-217) -105 + j*(-339) -139 + j*(275) --42 + j*(407) -215 + j*(-210) --390 + j*(-214) --330 + j*(-141) --125 + j*(-173) -164 + j*(-199) -262 + j*(43) -172 + j*(355) -69 + j*(151) --35 + j*(-54) --218 + j*(-117) -13 + j*(276) --42 + j*(-181) -176 + j*(-191) --174 + j*(-44) --300 + j*(-130) -29 + j*(-37) --274 + j*(-3) --23 + j*(57) -122 + j*(-143) -215 + j*(17) -78 + j*(110) --305 + j*(83) --4 + j*(43) -92 + j*(-425) --323 + j*(-36) --18 + j*(-63) -63 + j*(8) -50 + j*(170) -105 + j*(79) --18 + j*(-273) --66 + j*(-273) -86 + j*(-55) -173 + j*(-37) --87 + j*(30) -107 + j*(-247) -57 + j*(134) --118 + j*(518) -164 + j*(-260) -155 + j*(-93) -95 + j*(42) -293 + j*(-62) --26 + j*(250) -129 + j*(216) -86 + j*(69) -191 + j*(1) -214 + j*(-134) --308 + j*(-433) --33 + j*(-70) --98 + j*(57) -116 + j*(19) --248 + j*(185) -74 + j*(-148) --2 + j*(-165) -32 + j*(238) --4 + j*(170) --112 + j*(-122) -343 + j*(62) -145 + j*(72) --62 + j*(383) --105 + j*(-106) --480 + j*(200) -184 + j*(346) -83 + j*(-158) -187 + j*(170) --105 + j*(-212) --326 + j*(140) -240 + j*(-288) -107 + j*(-84) --231 + j*(-215) --162 + j*(99) --205 + j*(202) --89 + j*(170) -128 + j*(-134) -31 + j*(-245) --21 + j*(45) --5 + j*(32) --71 + j*(138) --300 + j*(55) -31 + j*(-25) --2 + j*(153) -163 + j*(-122) --132 + j*(-221) -192 + j*(62) --168 + j*(4) --10 + j*(-241) -193 + j*(-8) -31 + j*(-57) --58 + j*(-64) --134 + j*(-218) -78 + j*(-81) --13 + j*(107) --163 + j*(-23) --287 + j*(189) --226 + j*(-65) -54 + j*(-36) -25 + j*(260) -177 + j*(167) --83 + j*(245) --95 + j*(-302) -97 + j*(-70) -135 + j*(-128) -15 + j*(-54) -57 + j*(-5) -33 + j*(9) -196 + j*(297) --26 + j*(-111) --112 + j*(211) --215 + j*(54) --286 + j*(-7) -157 + j*(81) -626 + j*(96) -157 + j*(170) --2 + j*(116) --131 + j*(10) -443 + j*(48) --343 + j*(-14) --46 + j*(136) -235 + j*(98) -298 + j*(-99) -27 + j*(-122) --303 + j*(269) --65 + j*(-224) -86 + j*(119) -363 + j*(-146) -289 + j*(112) -416 + j*(-343) -23 + j*(62) -359 + j*(-118) -43 + j*(-156) -3 + j*(-25) --28 + j*(112) -100 + j*(211) --28 + j*(47) --169 + j*(18) -107 + j*(-104) --50 + j*(-117) -269 + j*(-52) -13 + j*(-81) --108 + j*(12) --103 + j*(-257) --258 + j*(93) --202 + j*(211) --117 + j*(-83) -5 + j*(-173) --289 + j*(281) --30 + j*(175) --20 + j*(-96) -177 + j*(40) --42 + j*(-80) --156 + j*(-88) --87 + j*(56) -112 + j*(42) --115 + j*(-334) -121 + j*(123) --197 + j*(308) -43 + j*(-219) --191 + j*(-131) -19 + j*(-239) --103 + j*(-7) --67 + j*(-83) --372 + j*(-101) -211 + j*(-40) --242 + j*(-88) --66 + j*(-199) --8 + j*(30) -183 + j*(-58) -59 + j*(220) -288 + j*(62) -233 + j*(109) -23 + j*(127) --99 + j*(-173) --48 + j*(-95) -182 + j*(167) -146 + j*(-223) -209 + j*(-64) -23 + j*(243) -65 + j*(78) --36 + j*(30) --384 + j*(-61) -187 + j*(9) --46 + j*(-52) -187 + j*(-119) -26 + j*(199) --296 + j*(-226) -224 + j*(-408) --184 + j*(221) --184 + j*(174) -83 + j*(107) --125 + j*(-95) -417 + j*(197) -10 + j*(-238) -32 + j*(-39) --59 + j*(161) -74 + j*(272) -291 + j*(139) --144 + j*(81) --321 + j*(0) -125 + j*(-56) --44 + j*(32) -57 + j*(-141) --115 + j*(32) -91 + j*(103) --204 + j*(-151) --112 + j*(-84) --49 + j*(42) -67 + j*(-351) --51 + j*(61) --269 + j*(54) --247 + j*(-315) -38 + j*(-28) -17 + j*(-354) -157 + j*(-127) -267 + j*(85) -137 + j*(-86) --77 + j*(-158) -344 + j*(-275) --101 + j*(136) --156 + j*(-459) --9 + j*(-119) -344 + j*(33) -16 + j*(-237) -74 + j*(-71) --19 + j*(321) -228 + j*(-115) --228 + j*(82) --291 + j*(49) --216 + j*(-457) --161 + j*(-90) --145 + j*(85) --417 + j*(130) --32 + j*(51) --341 + j*(-24) -60 + j*(174) --70 + j*(220) --177 + j*(-25) --42 + j*(-177) -141 + j*(-44) -126 + j*(-156) -180 + j*(-93) -239 + j*(-163) --242 + j*(-108) -74 + j*(133) -24 + j*(-28) --310 + j*(242) -134 + j*(201) --296 + j*(119) --98 + j*(-12) -69 + j*(71) --313 + j*(-73) -28 + j*(-25) -62 + j*(-102) --325 + j*(136) -322 + j*(-87) -64 + j*(247) --152 + j*(86) -95 + j*(-110) -145 + j*(344) -95 + j*(-163) --30 + j*(-364) -276 + j*(-101) -104 + j*(-206) -119 + j*(-93) --153 + j*(324) --3 + j*(-38) -70 + j*(83) --1 + j*(-329) --12 + j*(122) -41 + j*(104) --51 + j*(-198) -129 + j*(61) -4 + j*(23) -214 + j*(-16) --95 + j*(90) --84 + j*(-9) --159 + j*(78) --108 + j*(278) -156 + j*(-250) -106 + j*(172) -184 + j*(155) -159 + j*(47) --63 + j*(87) --8 + j*(115) --214 + j*(-180) --78 + j*(-164) -63 + j*(-165) --56 + j*(290) --69 + j*(-195) --155 + j*(53) -139 + j*(180) -205 + j*(-108) -30 + j*(342) --103 + j*(37) --204 + j*(-105) --125 + j*(-243) -211 + j*(306) --264 + j*(-107) --119 + j*(-308) -34 + j*(163) -5 + j*(112) -279 + j*(43) -209 + j*(-43) -15 + j*(157) -262 + j*(-8) -26 + j*(194) -170 + j*(-77) --65 + j*(-503) -18 + j*(-21) -228 + j*(-116) --71 + j*(54) -98 + j*(-200) -273 + j*(0) --126 + j*(-49) -118 + j*(-24) --1 + j*(21) --122 + j*(74) -247 + j*(-27) --94 + j*(252) -31 + j*(-20) -153 + j*(44) -38 + j*(-140) -62 + j*(200) --21 + j*(-37) -126 + j*(191) --3 + j*(-28) -261 + j*(284) --329 + j*(-189) -23 + j*(-105) -200 + j*(-269) -113 + j*(36) -61 + j*(151) --50 + j*(49) --150 + j*(-70) --115 + j*(-88) --46 + j*(-153) -100 + j*(92) --61 + j*(138) --35 + j*(-166) --185 + j*(189) -254 + j*(-180) -47 + j*(464) -24 + j*(273) --240 + j*(-223) --3 + j*(-196) --204 + j*(189) --33 + j*(-244) --112 + j*(-252) --103 + j*(-173) --12 + j*(-321) --150 + j*(-90) --26 + j*(238) -209 + j*(-52) -217 + j*(262) --211 + j*(69) -165 + j*(177) -13 + j*(-94) --110 + j*(-168) -167 + j*(-127) --100 + j*(64) -98 + j*(164) -138 + j*(-101) -97 + j*(-344) --255 + j*(33) --40 + j*(-127) -99 + j*(-166) --106 + j*(-271) -240 + j*(18) --58 + j*(-147) --145 + j*(50) --203 + j*(-132) -12 + j*(-170) --270 + j*(175) --47 + j*(-71) -279 + j*(-226) -181 + j*(202) -24 + j*(13) -65 + j*(148) --98 + j*(240) -36 + j*(206) -134 + j*(12) --144 + j*(-184) --402 + j*(83) --103 + j*(119) --62 + j*(-148) --113 + j*(202) --266 + j*(41) -185 + j*(-2) --196 + j*(-76) --123 + j*(-203) --195 + j*(-21) --23 + j*(232) --156 + j*(225) -219 + j*(152) -155 + j*(-184) --100 + j*(-13) --29 + j*(-129) -357 + j*(-53) -192 + j*(-126) --6 + j*(-172) -57 + j*(114) -183 + j*(-358) -47 + j*(-211) --42 + j*(131) --194 + j*(-122) --171 + j*(304) -31 + j*(95) --160 + j*(281) -37 + j*(-166) --142 + j*(37) -6 + j*(342) --55 + j*(-177) --20 + j*(-42) --351 + j*(87) -225 + j*(-8) -92 + j*(258) -71 + j*(83) -103 + j*(-59) -182 + j*(42) -78 + j*(-264) --153 + j*(-325) --160 + j*(25) -21 + j*(91) --123 + j*(-245) -81 + j*(-151) -277 + j*(63) --86 + j*(-250) --173 + j*(30) -86 + j*(-86) -11 + j*(95) -61 + j*(-32) --122 + j*(25) --52 + j*(-103) --93 + j*(445) -105 + j*(16) --68 + j*(-42) -129 + j*(-107) --199 + j*(-258) --273 + j*(108) -93 + j*(4) -176 + j*(-44) -98 + j*(-21) --145 + j*(-4) --192 + j*(22) --33 + j*(96) --176 + j*(-115) --29 + j*(47) --221 + j*(98) -139 + j*(249) -260 + j*(-54) --64 + j*(-2) -252 + j*(-52) -150 + j*(-151) -6 + j*(145) --78 + j*(136) -315 + j*(91) -30 + j*(91) --70 + j*(2) -105 + j*(-147) --159 + j*(380) -475 + j*(-3) -221 + j*(130) -224 + j*(-352) -23 + j*(180) -57 + j*(19) --322 + j*(94) --28 + j*(-117) -156 + j*(-285) -68 + j*(109) --77 + j*(-47) -87 + j*(-23) -392 + j*(44) --187 + j*(-203) --108 + j*(-540) --227 + j*(45) -2 + j*(-269) --64 + j*(204) --185 + j*(-205) --119 + j*(2) -404 + j*(-132) --144 + j*(20) -160 + j*(181) --283 + j*(86) -33 + j*(-139) --195 + j*(69) -117 + j*(-152) --308 + j*(-221) -337 + j*(127) --18 + j*(-202) -118 + j*(-132) -13 + j*(-235) --29 + j*(-47) -206 + j*(41) --243 + j*(306) -5 + j*(137) --48 + j*(42) --547 + j*(-230) --20 + j*(53) --49 + j*(0) -20 + j*(211) --115 + j*(359) -22 + j*(158) --108 + j*(-13) -169 + j*(-289) -92 + j*(69) --124 + j*(95) -113 + j*(-54) --382 + j*(-159) -274 + j*(214) --21 + j*(224) -29 + j*(59) -496 + j*(233) --115 + j*(-141) -246 + j*(-170) --75 + j*(-33) -251 + j*(-71) -7 + j*(144) -119 + j*(-99) -197 + j*(16) -52 + j*(-139) -17 + j*(-294) --66 + j*(177) --299 + j*(-142) -139 + j*(142) -34 + j*(126) -16 + j*(260) -90 + j*(44) --303 + j*(196) -67 + j*(-71) -74 + j*(179) -211 + j*(-202) -349 + j*(378) -444 + j*(3) -31 + j*(98) --217 + j*(-99) -35 + j*(98) --111 + j*(211) -253 + j*(69) -312 + j*(-1) -139 + j*(163) --30 + j*(5) --177 + j*(112) --195 + j*(211) --254 + j*(-32) --90 + j*(8) -170 + j*(-214) -254 + j*(257) --179 + j*(6) --69 + j*(202) -98 + j*(128) --197 + j*(-299) --250 + j*(-177) -156 + j*(-23) --64 + j*(-156) --35 + j*(-64) -32 + j*(101) --92 + j*(-60) -180 + j*(22) -21 + j*(134) -166 + j*(-83) -423 + j*(7) -12 + j*(219) -37 + j*(168) -1 + j*(118) -42 + j*(-40) --148 + j*(-71) --93 + j*(-12) --103 + j*(-221) -298 + j*(49) -56 + j*(91) -340 + j*(52) --117 + j*(132) -10 + j*(24) --24 + j*(151) --82 + j*(-61) -126 + j*(-199) --42 + j*(249) -102 + j*(74) -53 + j*(126) -245 + j*(161) --50 + j*(285) -106 + j*(136) -235 + j*(-6) -120 + j*(-202) -165 + j*(-13) --181 + j*(81) -318 + j*(-256) --25 + j*(137) -153 + j*(128) -123 + j*(-73) -61 + j*(51) --190 + j*(268) --363 + j*(214) -11 + j*(42) -75 + j*(-95) --62 + j*(-16) --15 + j*(-403) --33 + j*(-66) -95 + j*(64) --129 + j*(-220) --33 + j*(33) --38 + j*(-90) -103 + j*(-49) -252 + j*(227) -25 + j*(-282) -98 + j*(64) -151 + j*(-88) --182 + j*(117) --89 + j*(-91) --313 + j*(-100) --117 + j*(-107) -8 + j*(-174) --83 + j*(-45) --324 + j*(83) -47 + j*(70) -97 + j*(81) -223 + j*(375) -43 + j*(13) --156 + j*(103) --112 + j*(117) --36 + j*(65) --18 + j*(174) --209 + j*(-86) -173 + j*(-186) -130 + j*(-262) -1 + j*(74) --180 + j*(31) --285 + j*(295) --158 + j*(-69) --165 + j*(86) --221 + j*(-175) --166 + j*(47) --202 + j*(162) -263 + j*(47) -187 + j*(-681) -63 + j*(-173) -74 + j*(119) -23 + j*(-364) --226 + j*(-106) --11 + j*(293) -32 + j*(243) -63 + j*(-235) --28 + j*(42) --165 + j*(228) -375 + j*(98) --142 + j*(115) -131 + j*(85) -41 + j*(-390) -202 + j*(339) --311 + j*(91) -194 + j*(-33) -49 + j*(479) -59 + j*(-524) -310 + j*(266) -131 + j*(-93) -77 + j*(6) --170 + j*(180) -45 + j*(165) --6 + j*(151) -291 + j*(-45) --74 + j*(163) -70 + j*(148) -209 + j*(-54) --52 + j*(296) -426 + j*(-81) -6 + j*(100) -305 + j*(14) -37 + j*(95) -11 + j*(294) --152 + j*(-21) --30 + j*(-151) -47 + j*(-141) -391 + j*(12) --60 + j*(-167) -16 + j*(110) -161 + j*(6) -213 + j*(158) -35 + j*(-8) -231 + j*(-83) -119 + j*(190) --35 + j*(191) -35 + j*(339) --9 + j*(35) -249 + j*(-193) --153 + j*(162) -175 + j*(-298) --35 + j*(150) --11 + j*(-353) -231 + j*(-64) --139 + j*(-264) --25 + j*(203) -105 + j*(-223) -94 + j*(125) -150 + j*(-11) -170 + j*(71) -69 + j*(13) -128 + j*(126) --145 + j*(44) --33 + j*(166) --4 + j*(153) --42 + j*(0) --281 + j*(40) --43 + j*(230) --202 + j*(-315) -210 + j*(-83) -193 + j*(-252) -221 + j*(-6) --262 + j*(81) --247 + j*(58) -66 + j*(122) -73 + j*(-110) --47 + j*(-16) --62 + j*(54) -153 + j*(-28) --28 + j*(-310) -55 + j*(-151) -92 + j*(27) --258 + j*(-75) -206 + j*(-6) -66 + j*(60) --139 + j*(-156) -50 + j*(134) --24 + j*(103) -165 + j*(155) -30 + j*(206) -67 + j*(74) -5 + j*(-52) --168 + j*(-119) -69 + j*(59) -54 + j*(-223) --196 + j*(1) -217 + j*(-269) -88 + j*(282) --47 + j*(33) --124 + j*(-10) --184 + j*(-282) --325 + j*(94) -40 + j*(331) --44 + j*(-128) -56 + j*(163) --107 + j*(-361) -278 + j*(120) -62 + j*(84) -206 + j*(219) --192 + j*(-233) -170 + j*(-263) -71 + j*(-114) -260 + j*(293) --4 + j*(91) --110 + j*(-105) --269 + j*(-175) --282 + j*(210) -213 + j*(-96) -312 + j*(33) --138 + j*(-117) -18 + j*(-124) -75 + j*(-114) --409 + j*(21) --54 + j*(98) -78 + j*(-160) -42 + j*(-13) --27 + j*(-368) --54 + j*(191) -87 + j*(95) --26 + j*(110) -15 + j*(-362) -325 + j*(-46) --42 + j*(-44) -108 + j*(-125) --49 + j*(117) --66 + j*(71) --21 + j*(-75) --243 + j*(-115) --77 + j*(46) -162 + j*(222) -165 + j*(131) -72 + j*(-66) --47 + j*(21) -112 + j*(-103) -130 + j*(-159) -64 + j*(-24) -124 + j*(-74) --255 + j*(204) -144 + j*(221) -28 + j*(-227) --13 + j*(278) -328 + j*(190) -253 + j*(482) -187 + j*(-18) --191 + j*(-597) -204 + j*(-31) --57 + j*(144) --252 + j*(-190) -221 + j*(-197) -35 + j*(139) -43 + j*(-66) --35 + j*(-119) -288 + j*(-279) -195 + j*(100) -215 + j*(312) --47 + j*(-114) --228 + j*(-92) -49 + j*(216) --376 + j*(82) --26 + j*(-35) -280 + j*(58) --412 + j*(-246) --158 + j*(-41) --95 + j*(316) -124 + j*(-209) --127 + j*(105) -69 + j*(89) --215 + j*(272) -88 + j*(-143) -112 + j*(-29) -69 + j*(40) --50 + j*(-23) -163 + j*(7) -69 + j*(-132) -60 + j*(115) -25 + j*(-206) --172 + j*(176) --535 + j*(-53) -141 + j*(52) -179 + j*(69) -65 + j*(29) -12 + j*(-180) --205 + j*(64) -82 + j*(136) -62 + j*(-64) -194 + j*(264) --332 + j*(177) --65 + j*(373) -34 + j*(107) --112 + j*(208) -140 + j*(-209) -269 + j*(4) --247 + j*(-40) --70 + j*(68) --179 + j*(-117) -102 + j*(-54) -148 + j*(-216) -446 + j*(35) -281 + j*(-202) --71 + j*(-89) -180 + j*(161) --77 + j*(-236) --33 + j*(-301) --11 + j*(-132) -71 + j*(-301) --94 + j*(43) --209 + j*(-148) -204 + j*(-35) -137 + j*(-66) -8 + j*(54) --186 + j*(-173) --82 + j*(-146) --218 + j*(-95) -202 + j*(-250) -212 + j*(-194) --2 + j*(-124) --425 + j*(190) --10 + j*(-141) --445 + j*(27) --66 + j*(-164) -13 + j*(-260) --109 + j*(132) -79 + j*(165) -39 + j*(259) -173 + j*(110) -35 + j*(264) --13 + j*(197) --47 + j*(-209) --219 + j*(-66) -93 + j*(142) --129 + j*(-158) -49 + j*(213) -270 + j*(57) --144 + j*(-371) --7 + j*(40) -276 + j*(-67) --144 + j*(94) --177 + j*(-30) --61 + j*(-129) --596 + j*(331) --67 + j*(214) --144 + j*(59) --301 + j*(-268) --146 + j*(-204) --117 + j*(-105) -90 + j*(24) --30 + j*(35) --166 + j*(-23) -92 + j*(-79) -106 + j*(-62) -127 + j*(400) --154 + j*(68) -31 + j*(354) -144 + j*(-104) -56 + j*(170) --74 + j*(25) --240 + j*(204) --111 + j*(-112) --57 + j*(69) -17 + j*(-59) --76 + j*(86) --168 + j*(262) --66 + j*(97) --360 + j*(224) --159 + j*(42) --131 + j*(-4) --68 + j*(-267) -110 + j*(151) --110 + j*(-136) --171 + j*(-18) --81 + j*(-235) --236 + j*(173) -378 + j*(-101) --203 + j*(47) -61 + j*(47) -12 + j*(349) -291 + j*(73) --470 + j*(73) -339 + j*(48) --1 + j*(-18) --132 + j*(-96) -86 + j*(63) --191 + j*(-190) --142 + j*(-22) --134 + j*(-180) --326 + j*(52) --198 + j*(-278) --88 + j*(146) --207 + j*(33) --192 + j*(-90) --55 + j*(-57) --156 + j*(64) --332 + j*(327) -235 + j*(-50) -65 + j*(373) -107 + j*(-127) -122 + j*(98) -123 + j*(-29) --61 + j*(-6) --35 + j*(58) -96 + j*(-22) -35 + j*(63) -123 + j*(-92) -172 + j*(-159) -240 + j*(57) --175 + j*(92) --87 + j*(-8) -122 + j*(-253) --236 + j*(-38) --163 + j*(300) --310 + j*(40) -87 + j*(-207) -454 + j*(68) --103 + j*(-186) -250 + j*(115) -474 + j*(156) -51 + j*(22) -31 + j*(2) -75 + j*(-193) --36 + j*(168) -162 + j*(-11) -86 + j*(187) --86 + j*(-121) -77 + j*(-82) -222 + j*(-158) --19 + j*(-135) -188 + j*(279) --4 + j*(198) -54 + j*(30) --199 + j*(173) -37 + j*(206) --16 + j*(359) -24 + j*(-164) -211 + j*(-117) -56 + j*(99) --17 + j*(32) -100 + j*(-287) --289 + j*(9) -122 + j*(158) -318 + j*(13) -59 + j*(-168) -78 + j*(218) --42 + j*(191) --202 + j*(-32) -74 + j*(99) --167 + j*(98) -64 + j*(343) -119 + j*(-105) --218 + j*(131) --116 + j*(-496) -44 + j*(267) --109 + j*(222) -42 + j*(40) --15 + j*(164) --74 + j*(308) --1 + j*(-144) --284 + j*(186) -146 + j*(-49) --244 + j*(240) --19 + j*(-161) -43 + j*(320) --136 + j*(20) -247 + j*(0) -69 + j*(-146) --141 + j*(400) --21 + j*(-227) -139 + j*(-40) -275 + j*(-26) --157 + j*(34) -28 + j*(83) --578 + j*(-7) --135 + j*(73) -76 + j*(148) --310 + j*(-154) -210 + j*(123) -52 + j*(-453) --257 + j*(14) -23 + j*(20) -130 + j*(202) -45 + j*(223) -299 + j*(-381) --103 + j*(-58) -39 + j*(40) --42 + j*(86) -161 + j*(-38) -129 + j*(-187) --84 + j*(-164) -8 + j*(-97) -110 + j*(172) -247 + j*(356) --310 + j*(-209) -46 + j*(13) -291 + j*(-132) -44 + j*(228) --43 + j*(166) --258 + j*(121) --17 + j*(-28) -327 + j*(-172) -336 + j*(153) -321 + j*(-74) -83 + j*(-168) -3 + j*(-115) -28 + j*(276) -124 + j*(-30) -88 + j*(-173) -341 + j*(-122) --32 + j*(288) -143 + j*(150) --389 + j*(-63) --136 + j*(4) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -]; diff --git a/txsig0.m b/txsig0.m deleted file mode 100644 index e795208a15..0000000000 --- a/txsig0.m +++ /dev/null @@ -1,61441 +0,0 @@ -txs0 = [-194 + j*(-202) --136 + j*(186) -248 + j*(59) -61 + j*(-331) --327 + j*(-134) --161 + j*(205) -70 + j*(64) --84 + j*(-35) --82 + j*(168) -170 + j*(116) -105 + j*(-159) --163 + j*(-94) --102 + j*(147) -100 + j*(89) -31 + j*(-79) --114 + j*(4) --25 + j*(144) -112 + j*(64) -41 + j*(-65) --84 + j*(9) --18 + j*(151) -137 + j*(129) -190 + j*(9) -163 + j*(-89) -85 + j*(-173) --68 + j*(-154) --93 + j*(26) -119 + j*(64) -183 + j*(-209) --139 + j*(-343) --365 + j*(-29) --107 + j*(252) -180 + j*(51) -11 + j*(-232) --279 + j*(-96) --200 + j*(193) -42 + j*(170) -37 + j*(-5) --93 + j*(13) --81 + j*(137) -21 + j*(187) -158 + j*(174) -303 + j*(-10) -155 + j*(-324) --275 + j*(-277) --348 + j*(180) -57 + j*(327) -197 + j*(1) --89 + j*(-71) --107 + j*(244) -254 + j*(283) -382 + j*(-61) -137 + j*(-263) --69 + j*(-141) --19 + j*(32) -138 + j*(8) -135 + j*(-159) --20 + j*(-175) --9 + j*(-51) -126 + j*(-153) --52 + j*(-384) --409 + j*(-234) --389 + j*(165) --78 + j*(276) -81 + j*(133) -94 + j*(11) -42 + j*(-99) --103 + j*(-112) --155 + j*(25) --57 + j*(74) --47 + j*(23) --64 + j*(69) -36 + j*(51) --16 + j*(-105) --230 + j*(-46) --211 + j*(189) --51 + j*(221) --39 + j*(208) -67 + j*(312) -308 + j*(188) -240 + j*(-112) --30 + j*(-91) --16 + j*(126) -153 + j*(117) -170 + j*(12) -156 + j*(-11) -173 + j*(-64) -130 + j*(-112) -123 + j*(-123) -100 + j*(-220) --86 + j*(-247) --170 + j*(-43) -21 + j*(40) -64 + j*(-161) --175 + j*(-176) --196 + j*(100) -91 + j*(138) -151 + j*(-144) --111 + j*(-234) --230 + j*(-19) --85 + j*(96) --11 + j*(9) --78 + j*(-10) --66 + j*(57) --17 + j*(30) --70 + j*(21) --45 + j*(133) -139 + j*(109) -154 + j*(-121) --70 + j*(-189) --165 + j*(-28) --98 + j*(46) --93 + j*(60) --33 + j*(136) -93 + j*(59) --5 + j*(-81) --144 + j*(55) -36 + j*(194) -176 + j*(-16) --49 + j*(-146) --166 + j*(75) -32 + j*(179) -109 + j*(33) -25 + j*(9) -74 + j*(42) -80 + j*(-77) --93 + j*(-79) --105 + j*(128) -111 + j*(162) -170 + j*(-36) --4 + j*(-98) --60 + j*(74) -142 + j*(148) -281 + j*(-80) -70 + j*(-296) --184 + j*(-135) --49 + j*(103) -166 + j*(-62) --46 + j*(-301) --354 + j*(-80) --202 + j*(281) -147 + j*(244) -206 + j*(-15) -78 + j*(-109) -20 + j*(-95) --17 + j*(-116) --112 + j*(-98) --159 + j*(30) --44 + j*(146) -110 + j*(66) -59 + j*(-88) --69 + j*(-35) -13 + j*(67) -104 + j*(-51) --37 + j*(-129) --83 + j*(6) -40 + j*(-13) --67 + j*(-129) --181 + j*(74) -120 + j*(185) -238 + j*(-213) --223 + j*(-363) --411 + j*(107) --2 + j*(288) -109 + j*(-43) --169 + j*(-46) --73 + j*(214) -182 + j*(56) --7 + j*(-186) --223 + j*(5) --57 + j*(177) -38 + j*(27) --137 + j*(19) --122 + j*(259) -152 + j*(303) -272 + j*(86) -172 + j*(-42) -145 + j*(-28) -195 + j*(-117) -64 + j*(-272) --177 + j*(-182) --171 + j*(71) -32 + j*(98) -31 + j*(-51) --99 + j*(11) -8 + j*(153) -159 + j*(35) -35 + j*(-93) --64 + j*(65) -149 + j*(186) -355 + j*(-29) -238 + j*(-317) --43 + j*(-356) --204 + j*(-183) --149 + j*(-11) --34 + j*(-13) --62 + j*(-84) --139 + j*(-6) --34 + j*(103) -103 + j*(-2) -18 + j*(-142) --96 + j*(-79) --27 + j*(-25) --26 + j*(-159) --263 + j*(-175) --385 + j*(125) --127 + j*(377) -177 + j*(252) -168 + j*(13) -60 + j*(5) -144 + j*(21) -160 + j*(-194) --136 + j*(-288) --318 + j*(5) --82 + j*(217) -93 + j*(27) --91 + j*(-98) --199 + j*(90) --41 + j*(188) -8 + j*(95) --67 + j*(132) -27 + j*(257) -204 + j*(201) -247 + j*(55) -214 + j*(-49) -131 + j*(-134) --10 + j*(-97) -16 + j*(65) -221 + j*(31) -221 + j*(-237) --64 + j*(-323) --230 + j*(-107) --126 + j*(61) --33 + j*(42) --40 + j*(42) -20 + j*(91) -120 + j*(29) -89 + j*(-100) --38 + j*(-103) --58 + j*(13) -58 + j*(46) -122 + j*(-83) -0 + j*(-199) --163 + j*(-120) --140 + j*(45) --11 + j*(53) --18 + j*(-31) --82 + j*(17) -11 + j*(74) -59 + j*(-59) --120 + j*(-101) --171 + j*(128) -76 + j*(203) -172 + j*(-20) -10 + j*(-92) -9 + j*(9) -75 + j*(-86) --111 + j*(-147) --175 + j*(105) -122 + j*(173) -203 + j*(-151) --111 + j*(-262) --245 + j*(-17) --110 + j*(93) --74 + j*(53) --79 + j*(90) --29 + j*(81) --96 + j*(72) --87 + j*(255) -197 + j*(303) -325 + j*(8) -103 + j*(-132) -39 + j*(30) -215 + j*(1) -166 + j*(-223) --55 + j*(-224) --98 + j*(-93) --86 + j*(-68) --130 + j*(-1) --34 + j*(97) -81 + j*(-18) --69 + j*(-147) --237 + j*(30) --83 + j*(245) -132 + j*(166) -120 + j*(25) -91 + j*(37) -170 + j*(-23) -83 + j*(-180) --124 + j*(-100) --45 + j*(129) -206 + j*(34) -113 + j*(-245) --176 + j*(-175) --128 + j*(87) -92 + j*(37) -29 + j*(-153) --144 + j*(-103) --128 + j*(23) --92 + j*(30) --112 + j*(88) --8 + j*(170) -122 + j*(83) -81 + j*(-45) --4 + j*(-42) --18 + j*(-16) --43 + j*(-1) --42 + j*(64) -40 + j*(78) -47 + j*(6) --19 + j*(44) -76 + j*(154) -281 + j*(49) -264 + j*(-238) --18 + j*(-369) --266 + j*(-198) --245 + j*(78) --7 + j*(177) -168 + j*(-5) -40 + j*(-248) --272 + j*(-207) --366 + j*(132) --85 + j*(356) -208 + j*(202) -177 + j*(-63) -3 + j*(-96) --23 + j*(-18) --3 + j*(-49) --109 + j*(-69) --184 + j*(77) --69 + j*(223) -105 + j*(208) -198 + j*(93) -202 + j*(-50) -97 + j*(-165) --67 + j*(-153) --146 + j*(-14) --83 + j*(126) -72 + j*(153) -183 + j*(23) -98 + j*(-141) --86 + j*(-95) --59 + j*(91) -134 + j*(71) -122 + j*(-134) --97 + j*(-146) --147 + j*(77) -66 + j*(191) -257 + j*(23) -194 + j*(-226) --39 + j*(-298) --208 + j*(-178) --243 + j*(-25) --216 + j*(119) --76 + j*(247) -144 + j*(186) -151 + j*(-23) -4 + j*(-19) -91 + j*(98) -249 + j*(-80) -41 + j*(-301) --199 + j*(-124) --54 + j*(63) -53 + j*(-95) --144 + j*(-161) --214 + j*(38) --77 + j*(104) --69 + j*(55) --69 + j*(140) -83 + j*(153) -127 + j*(-1) -25 + j*(-45) -27 + j*(0) -44 + j*(-57) --45 + j*(-78) --70 + j*(5) --9 + j*(15) --13 + j*(-43) --80 + j*(-61) --170 + j*(-14) --212 + j*(145) --59 + j*(313) -175 + j*(250) -221 + j*(59) -145 + j*(-12) -130 + j*(-25) -116 + j*(-76) -69 + j*(-121) --23 + j*(-160) --188 + j*(-76) --166 + j*(193) -141 + j*(249) -243 + j*(-24) -41 + j*(-97) -64 + j*(44) -183 + j*(-84) --27 + j*(-175) --50 + j*(114) -363 + j*(58) -303 + j*(-504) --333 + j*(-527) --450 + j*(41) --40 + j*(153) --25 + j*(-122) --240 + j*(-37) --124 + j*(148) --1 + j*(45) --100 + j*(14) --57 + j*(126) -62 + j*(41) --56 + j*(-71) --175 + j*(71) --45 + j*(213) -107 + j*(142) -114 + j*(21) -66 + j*(-37) --12 + j*(-71) --130 + j*(-15) --141 + j*(177) -85 + j*(297) -323 + j*(107) -219 + j*(-204) --95 + j*(-180) --118 + j*(100) -119 + j*(148) -185 + j*(-22) -117 + j*(-76) -129 + j*(-119) -34 + j*(-238) --174 + j*(-164) --153 + j*(57) -23 + j*(79) -60 + j*(-21) -45 + j*(-59) -23 + j*(-130) --110 + j*(-151) --168 + j*(-12) --75 + j*(34) --113 + j*(-22) --182 + j*(123) -25 + j*(248) -192 + j*(50) -38 + j*(-102) --52 + j*(12) -51 + j*(23) -1 + j*(-83) --116 + j*(-6) --47 + j*(104) -17 + j*(71) -16 + j*(99) -153 + j*(109) -215 + j*(-111) --33 + j*(-237) --202 + j*(0) -14 + j*(183) -216 + j*(-10) -61 + j*(-235) --169 + j*(-145) --139 + j*(46) --11 + j*(21) --91 + j*(-76) --228 + j*(60) --99 + j*(269) -136 + j*(210) -139 + j*(28) -42 + j*(33) -100 + j*(93) -185 + j*(6) -139 + j*(-114) -26 + j*(-142) --59 + j*(-71) --20 + j*(39) -111 + j*(11) -86 + j*(-144) --77 + j*(-129) --51 + j*(8) -54 + j*(-62) --78 + j*(-164) --202 + j*(-3) --66 + j*(136) -41 + j*(61) -23 + j*(25) -78 + j*(16) -68 + j*(-111) --93 + j*(-116) --100 + j*(38) -25 + j*(27) --13 + j*(-73) --98 + j*(-31) --88 + j*(21) --105 + j*(69) --13 + j*(190) -216 + j*(78) -108 + j*(-244) --277 + j*(-153) --214 + j*(264) -196 + j*(235) -199 + j*(-131) --99 + j*(-150) --117 + j*(66) -24 + j*(66) --5 + j*(-31) --98 + j*(15) --83 + j*(126) -14 + j*(186) -138 + j*(156) -200 + j*(43) -163 + j*(-57) -107 + j*(-97) -49 + j*(-122) --23 + j*(-93) --13 + j*(-21) -56 + j*(-54) --11 + j*(-151) --169 + j*(-84) --148 + j*(123) -69 + j*(170) -175 + j*(-24) -16 + j*(-158) --123 + j*(-22) -7 + j*(114) -156 + j*(-19) -43 + j*(-183) --119 + j*(-129) --136 + j*(-23) --138 + j*(41) --78 + j*(157) -117 + j*(136) -134 + j*(-84) --78 + j*(-120) --107 + j*(64) -33 + j*(69) --13 + j*(-21) --76 + j*(95) -91 + j*(178) -231 + j*(29) -181 + j*(-138) -58 + j*(-223) --117 + j*(-201) --183 + j*(-8) --10 + j*(71) -25 + j*(-103) --186 + j*(-88) --157 + j*(153) -59 + j*(127) -13 + j*(-8) --35 + j*(103) -158 + j*(102) -157 + j*(-132) --30 + j*(-143) --12 + j*(-71) --68 + j*(-188) --312 + j*(-68) --202 + j*(255) -106 + j*(181) -32 + j*(-31) --72 + j*(78) -74 + j*(97) -14 + j*(-49) --103 + j*(99) -141 + j*(182) -200 + j*(-136) --147 + j*(-175) --165 + j*(148) -81 + j*(121) --36 + j*(-28) --121 + j*(200) -169 + j*(290) -270 + j*(55) -179 + j*(21) -314 + j*(-1) -285 + j*(-309) --81 + j*(-343) --148 + j*(-45) -36 + j*(-34) --51 + j*(-122) --74 + j*(53) -172 + j*(23) -110 + j*(-277) --204 + j*(-220) --161 + j*(42) -7 + j*(-23) --116 + j*(-115) --186 + j*(62) -4 + j*(139) -91 + j*(-23) --27 + j*(-114) --117 + j*(-51) --107 + j*(23) --71 + j*(40) --76 + j*(35) --93 + j*(89) --12 + j*(156) -100 + j*(99) -95 + j*(0) -68 + j*(-22) -71 + j*(-80) --33 + j*(-146) --141 + j*(-59) --110 + j*(25) --114 + j*(23) --142 + j*(128) -8 + j*(211) -113 + j*(82) -28 + j*(33) -90 + j*(103) -182 + j*(-69) --69 + j*(-202) --224 + j*(82) -57 + j*(229) -154 + j*(-28) --82 + j*(-46) --26 + j*(180) -177 + j*(80) -50 + j*(-60) --1 + j*(112) -234 + j*(100) -214 + j*(-171) --30 + j*(-161) --8 + j*(3) -81 + j*(-49) -11 + j*(-83) -39 + j*(-25) -76 + j*(-131) --100 + j*(-167) --144 + j*(49) -84 + j*(95) -136 + j*(-136) --80 + j*(-215) --209 + j*(-57) --156 + j*(109) -3 + j*(178) -167 + j*(73) -132 + j*(-123) --33 + j*(-134) --35 + j*(-33) -21 + j*(-82) --76 + j*(-132) --132 + j*(-34) --72 + j*(-1) --93 + j*(-41) --139 + j*(23) --83 + j*(71) --75 + j*(44) --97 + j*(95) --10 + j*(140) -38 + j*(66) --10 + j*(60) -47 + j*(98) -87 + j*(-15) --70 + j*(-41) --76 + j*(173) -202 + j*(187) -267 + j*(-129) --20 + j*(-264) --206 + j*(-71) --133 + j*(107) --13 + j*(140) -75 + j*(89) -69 + j*(-3) --16 + j*(7) -30 + j*(97) -139 + j*(17) -36 + j*(-110) --91 + j*(18) -63 + j*(139) -184 + j*(-37) -4 + j*(-156) --102 + j*(13) -51 + j*(100) -123 + j*(-25) -40 + j*(-88) --7 + j*(-67) --64 + j*(-44) --83 + j*(100) -135 + j*(192) -322 + j*(-47) -141 + j*(-305) --98 + j*(-221) --71 + j*(-95) --74 + j*(-156) --224 + j*(-89) --173 + j*(126) -46 + j*(119) -59 + j*(-66) --92 + j*(-74) --102 + j*(55) -17 + j*(83) -78 + j*(-22) --5 + j*(-134) --163 + j*(-98) --198 + j*(73) --69 + j*(168) -25 + j*(117) -40 + j*(82) -81 + j*(57) -89 + j*(-18) -42 + j*(-52) -33 + j*(-74) --54 + j*(-149) --226 + j*(-48) --151 + j*(182) -61 + j*(127) --40 + j*(-22) --134 + j*(177) -169 + j*(257) -239 + j*(-114) --183 + j*(-148) --180 + j*(333) -346 + j*(337) -386 + j*(-156) -13 + j*(-190) -69 + j*(57) -272 + j*(-112) -67 + j*(-338) --147 + j*(-214) --138 + j*(-105) --197 + j*(-58) --168 + j*(129) -66 + j*(134) -58 + j*(-88) --147 + j*(-33) --42 + j*(170) -154 + j*(37) -13 + j*(-136) --124 + j*(11) -17 + j*(112) -87 + j*(-14) --11 + j*(-47) --3 + j*(23) -49 + j*(-22) --16 + j*(-62) --42 + j*(8) -30 + j*(13) -21 + j*(-71) --76 + j*(-71) --110 + j*(18) --71 + j*(82) --9 + j*(115) -81 + j*(99) -123 + j*(-4) -43 + j*(-77) --13 + j*(-18) -59 + j*(-4) -41 + j*(-132) --149 + j*(-117) --168 + j*(110) -54 + j*(157) -94 + j*(-24) --43 + j*(-18) -30 + j*(95) -135 + j*(-37) --33 + j*(-132) --107 + j*(57) -92 + j*(104) -111 + j*(-83) --29 + j*(-65) -56 + j*(11) -83 + j*(-171) --190 + j*(-189) --227 + j*(131) -93 + j*(187) -159 + j*(-101) --77 + j*(-175) --156 + j*(-15) --83 + j*(51) --49 + j*(43) --36 + j*(27) --81 + j*(19) --98 + j*(130) -69 + j*(174) -136 + j*(-19) --67 + j*(-74) --95 + j*(139) -124 + j*(143) -112 + j*(-52) --35 + j*(-11) -42 + j*(84) -90 + j*(-14) --3 + j*(-4) -95 + j*(69) -164 + j*(-132) --128 + j*(-231) --281 + j*(105) -27 + j*(307) -236 + j*(92) -127 + j*(-53) -91 + j*(-12) -117 + j*(-66) -21 + j*(-92) -17 + j*(26) -163 + j*(13) -181 + j*(-146) -79 + j*(-215) -19 + j*(-230) --83 + j*(-263) --221 + j*(-168) --188 + j*(5) --35 + j*(-1) --52 + j*(-155) --252 + j*(-163) --347 + j*(56) --194 + j*(232) --23 + j*(169) --54 + j*(60) --143 + j*(129) --72 + j*(266) -100 + j*(289) -249 + j*(188) -310 + j*(-8) -184 + j*(-207) --50 + j*(-197) --107 + j*(-20) -9 + j*(33) -37 + j*(-66) --71 + j*(-104) --163 + j*(-24) --169 + j*(118) --42 + j*(227) -118 + j*(168) -116 + j*(40) -59 + j*(55) -148 + j*(66) -160 + j*(-96) --42 + j*(-122) --75 + j*(100) -170 + j*(142) -241 + j*(-99) -49 + j*(-201) --41 + j*(-86) -25 + j*(-41) -37 + j*(-102) --24 + j*(-126) --75 + j*(-99) --100 + j*(-59) --117 + j*(-15) --122 + j*(64) --17 + j*(167) -188 + j*(89) -176 + j*(-187) --116 + j*(-242) --204 + j*(13) -1 + j*(68) --25 + j*(-117) --233 + j*(-18) --103 + j*(222) -136 + j*(86) --18 + j*(-122) --207 + j*(60) --23 + j*(254) -156 + j*(115) -74 + j*(1) -53 + j*(74) -169 + j*(38) -151 + j*(-116) -9 + j*(-153) --66 + j*(-77) --56 + j*(-2) -1 + j*(18) -27 + j*(-35) --42 + j*(-64) --83 + j*(21) -1 + j*(78) -62 + j*(10) -25 + j*(-33) -25 + j*(-25) -24 + j*(-86) --94 + j*(-115) --179 + j*(21) --87 + j*(153) -40 + j*(136) -84 + j*(81) -120 + j*(39) -149 + j*(-49) -94 + j*(-165) --58 + j*(-222) --250 + j*(-126) --292 + j*(157) --4 + j*(361) -327 + j*(146) -220 + j*(-244) --158 + j*(-236) --211 + j*(86) -41 + j*(154) -88 + j*(-45) --88 + j*(-61) --89 + j*(115) -85 + j*(123) -98 + j*(-33) --39 + j*(-42) --38 + j*(100) -124 + j*(104) -147 + j*(-66) --16 + j*(-96) --28 + j*(74) -194 + j*(75) -242 + j*(-210) --58 + j*(-366) --318 + j*(-151) --255 + j*(142) --24 + j*(223) -139 + j*(105) -119 + j*(-82) --71 + j*(-118) --136 + j*(92) -116 + j*(196) -286 + j*(-92) -3 + j*(-344) --312 + j*(-116) --159 + j*(211) -137 + j*(116) -62 + j*(-134) --164 + j*(-58) --81 + j*(167) -156 + j*(90) -97 + j*(-168) --182 + j*(-148) --221 + j*(134) -23 + j*(240) -168 + j*(72) -91 + j*(-66) --8 + j*(-58) --41 + j*(-9) --33 + j*(50) -40 + j*(79) -105 + j*(7) -54 + j*(-72) --13 + j*(-45) -8 + j*(-11) -19 + j*(-43) --23 + j*(-54) --45 + j*(-25) --45 + j*(-5) --40 + j*(20) --13 + j*(32) --4 + j*(18) -0 + j*(25) -30 + j*(4) --22 + j*(-54) --124 + j*(45) -15 + j*(223) -294 + j*(79) -206 + j*(-286) --193 + j*(-308) --334 + j*(42) --115 + j*(271) -130 + j*(213) -218 + j*(28) -136 + j*(-144) --40 + j*(-163) --117 + j*(-43) --76 + j*(32) --50 + j*(56) -8 + j*(89) -77 + j*(14) --23 + j*(-69) --119 + j*(71) -39 + j*(196) -177 + j*(67) -111 + j*(-15) -162 + j*(22) -255 + j*(-180) --35 + j*(-395) --370 + j*(-116) --168 + j*(276) -217 + j*(171) -198 + j*(-155) --37 + j*(-199) --114 + j*(-66) --65 + j*(12) -12 + j*(21) -74 + j*(-71) --16 + j*(-208) --224 + j*(-183) --316 + j*(28) --198 + j*(214) --19 + j*(222) -58 + j*(128) -44 + j*(74) -54 + j*(69) -66 + j*(15) --12 + j*(-14) --53 + j*(98) -100 + j*(182) -267 + j*(35) -209 + j*(-199) --7 + j*(-283) --209 + j*(-177) --248 + j*(46) --88 + j*(182) -49 + j*(96) --12 + j*(27) --16 + j*(144) -192 + j*(141) -260 + j*(-132) -6 + j*(-308) --255 + j*(-176) --310 + j*(85) --154 + j*(310) -153 + j*(320) -295 + j*(34) -78 + j*(-156) --93 + j*(13) -53 + j*(149) -153 + j*(42) -105 + j*(16) -206 + j*(45) -294 + j*(-177) -48 + j*(-372) --206 + j*(-206) --146 + j*(11) --28 + j*(11) --23 + j*(-14) -11 + j*(-11) -11 + j*(-80) --82 + j*(-71) --68 + j*(40) -57 + j*(23) -50 + j*(-105) --58 + j*(-122) --83 + j*(-64) --75 + j*(-74) --138 + j*(-86) --218 + j*(-9) --206 + j*(144) --28 + j*(240) -173 + j*(89) -70 + j*(-199) --288 + j*(-182) --414 + j*(196) --140 + j*(471) -180 + j*(421) -344 + j*(233) -393 + j*(-2) -255 + j*(-228) -6 + j*(-238) --80 + j*(-84) --32 + j*(-26) --45 + j*(-15) --14 + j*(54) -83 + j*(-1) --13 + j*(-116) --156 + j*(29) -28 + j*(211) -238 + j*(10) -42 + j*(-211) --158 + j*(-20) -36 + j*(136) -151 + j*(-74) --80 + j*(-159) --156 + j*(83) -73 + j*(162) -150 + j*(-23) -24 + j*(-78) -12 + j*(1) -81 + j*(-30) -38 + j*(-105) --42 + j*(-90) --61 + j*(-25) --17 + j*(21) -47 + j*(-12) -19 + j*(-93) --73 + j*(-64) --35 + j*(26) -56 + j*(-37) --26 + j*(-142) --135 + j*(-66) --85 + j*(6) --86 + j*(-47) --186 + j*(16) --110 + j*(165) -38 + j*(110) --9 + j*(1) --79 + j*(61) --27 + j*(107) --32 + j*(104) -21 + j*(213) -260 + j*(155) -242 + j*(-181) --134 + j*(-202) --160 + j*(181) -224 + j*(190) -216 + j*(-189) --139 + j*(-156) --69 + j*(175) -260 + j*(72) -172 + j*(-259) --123 + j*(-233) --154 + j*(-45) --105 + j*(-16) --145 + j*(29) --96 + j*(141) -24 + j*(151) -79 + j*(110) -144 + j*(78) -197 + j*(-41) -103 + j*(-162) --15 + j*(-137) --24 + j*(-78) --23 + j*(-83) --43 + j*(-78) --48 + j*(-87) --113 + j*(-107) --196 + j*(-16) --129 + j*(103) --30 + j*(62) --91 + j*(1) --163 + j*(100) --78 + j*(225) -67 + j*(235) -181 + j*(153) -216 + j*(4) -111 + j*(-110) --6 + j*(-66) -16 + j*(-4) -25 + j*(-49) --65 + j*(-36) --69 + j*(85) -42 + j*(132) -122 + j*(88) -175 + j*(18) -159 + j*(-100) -31 + j*(-126) -30 + j*(-3) -199 + j*(-62) -119 + j*(-332) --223 + j*(-313) --296 + j*(4) --91 + j*(117) --18 + j*(42) -1 + j*(54) -105 + j*(-19) -12 + j*(-202) --216 + j*(-123) --162 + j*(92) --13 + j*(24) --153 + j*(-72) --262 + j*(153) --11 + j*(321) -198 + j*(113) -51 + j*(-77) --103 + j*(44) -4 + j*(185) -151 + j*(115) -144 + j*(-12) -74 + j*(-54) -22 + j*(-39) -2 + j*(20) -88 + j*(78) -228 + j*(-34) -148 + j*(-286) --177 + j*(-305) --310 + j*(6) --71 + j*(195) -112 + j*(17) --47 + j*(-148) --235 + j*(1) --142 + j*(242) -117 + j*(265) -272 + j*(52) -167 + j*(-184) --72 + j*(-199) --171 + j*(-28) --112 + j*(79) --78 + j*(122) -5 + j*(219) -218 + j*(185) -282 + j*(-69) -71 + j*(-206) --76 + j*(-67) -15 + j*(54) -127 + j*(-10) -110 + j*(-136) --12 + j*(-192) --136 + j*(-111) --108 + j*(28) -11 + j*(23) --10 + j*(-81) --129 + j*(-52) --131 + j*(86) --10 + j*(163) -151 + j*(122) -234 + j*(-81) -56 + j*(-294) --225 + j*(-198) --224 + j*(59) --66 + j*(95) --71 + j*(54) --40 + j*(144) -126 + j*(98) -96 + j*(-96) --75 + j*(-85) --69 + j*(23) --50 + j*(-3) --115 + j*(64) -8 + j*(177) -144 + j*(28) --23 + j*(-90) --106 + j*(107) -122 + j*(170) -179 + j*(-56) -0 + j*(-101) -4 + j*(23) -95 + j*(-48) --16 + j*(-141) --111 + j*(-45) --58 + j*(23) --47 + j*(-2) --88 + j*(36) --48 + j*(116) -69 + j*(120) -136 + j*(-18) --23 + j*(-159) --256 + j*(24) --80 + j*(365) -330 + j*(245) -287 + j*(-135) -37 + j*(-103) -168 + j*(-3) -186 + j*(-301) --249 + j*(-327) --316 + j*(146) -108 + j*(220) -131 + j*(-115) --116 + j*(-52) -32 + j*(124) -145 + j*(-91) --105 + j*(-140) --87 + j*(123) -180 + j*(47) -63 + j*(-209) --160 + j*(-81) --38 + j*(88) -64 + j*(-7) -20 + j*(-28) -115 + j*(-38) -99 + j*(-277) --234 + j*(-341) --409 + j*(-42) --264 + j*(163) --161 + j*(181) --78 + j*(243) -97 + j*(187) -78 + j*(-12) --109 + j*(10) --78 + j*(188) -74 + j*(170) -57 + j*(90) -52 + j*(166) -225 + j*(163) -296 + j*(-59) -115 + j*(-217) --72 + j*(-135) --82 + j*(17) --6 + j*(81) -66 + j*(100) -185 + j*(84) -301 + j*(-90) -166 + j*(-356) --186 + j*(-339) --274 + j*(-1) -9 + j*(103) -66 + j*(-180) --290 + j*(-209) --366 + j*(228) -91 + j*(401) -346 + j*(-5) -26 + j*(-292) --251 + j*(-59) --98 + j*(175) -66 + j*(78) --12 + j*(8) --7 + j*(115) -160 + j*(83) -155 + j*(-130) --54 + j*(-180) --153 + j*(-28) --89 + j*(84) --6 + j*(110) -89 + j*(86) -142 + j*(-53) --13 + j*(-197) --251 + j*(-72) --217 + j*(242) -96 + j*(346) -317 + j*(132) -251 + j*(-104) -109 + j*(-132) -105 + j*(-97) -118 + j*(-192) --37 + j*(-279) --204 + j*(-156) --153 + j*(13) --40 + j*(-14) --92 + j*(-90) --186 + j*(-26) --175 + j*(81) --127 + j*(153) --21 + j*(222) -151 + j*(170) -187 + j*(-21) -50 + j*(-118) --42 + j*(-59) --39 + j*(-8) --21 + j*(18) -40 + j*(1) -13 + j*(-132) --224 + j*(-133) --315 + j*(181) --11 + j*(388) -260 + j*(185) -177 + j*(-47) -52 + j*(-30) -74 + j*(-1) -69 + j*(-54) -11 + j*(-70) --47 + j*(-48) --98 + j*(51) -21 + j*(202) -278 + j*(107) -259 + j*(-214) --47 + j*(-292) --184 + j*(-76) --87 + j*(51) --16 + j*(53) -48 + j*(52) -106 + j*(-47) -0 + j*(-146) --110 + j*(-61) --61 + j*(11) --78 + j*(-21) --138 + j*(102) -61 + j*(233) -269 + j*(23) -98 + j*(-221) --117 + j*(-100) --11 + j*(49) -83 + j*(-84) --86 + j*(-168) --194 + j*(12) --35 + j*(151) -134 + j*(22) -34 + j*(-185) --217 + j*(-127) --222 + j*(148) -38 + j*(204) -94 + j*(-13) --94 + j*(-19) --34 + j*(184) -206 + j*(78) -87 + j*(-186) --176 + j*(-74) --70 + j*(165) -139 + j*(65) -45 + j*(-117) --125 + j*(-42) --93 + j*(124) -66 + j*(168) -198 + j*(37) -115 + j*(-163) --119 + j*(-122) --93 + j*(118) -155 + j*(82) -110 + j*(-169) --119 + j*(-132) --86 + j*(26) --31 + j*(-42) --178 + j*(-10) --111 + j*(211) -130 + j*(144) -46 + j*(-66) --131 + j*(70) -38 + j*(249) -221 + j*(107) -157 + j*(-16) -155 + j*(-5) -179 + j*(-116) -18 + j*(-182) --58 + j*(-21) -92 + j*(47) -168 + j*(-78) -130 + j*(-164) -100 + j*(-258) --71 + j*(-373) --326 + j*(-263) --372 + j*(6) --234 + j*(173) --55 + j*(218) -138 + j*(98) -81 + j*(-190) --284 + j*(-191) --366 + j*(220) -19 + j*(387) -223 + j*(95) -37 + j*(-59) --33 + j*(66) -74 + j*(77) -67 + j*(-16) -18 + j*(-8) -35 + j*(-17) --20 + j*(-47) --59 + j*(38) -51 + j*(74) -84 + j*(-63) --71 + j*(-116) --163 + j*(29) --78 + j*(157) -45 + j*(167) -136 + j*(98) -145 + j*(-29) -32 + j*(-86) --31 + j*(0) -45 + j*(35) -37 + j*(-54) --79 + j*(-17) --37 + j*(136) -124 + j*(117) -135 + j*(4) -116 + j*(9) -202 + j*(-54) -114 + j*(-238) --129 + j*(-163) --43 + j*(97) -244 + j*(-28) -110 + j*(-376) --279 + j*(-310) --317 + j*(26) --120 + j*(119) --50 + j*(67) --16 + j*(54) --6 + j*(-23) --122 + j*(-19) --99 + j*(146) -88 + j*(121) -55 + j*(-42) --49 + j*(33) -95 + j*(83) -111 + j*(-130) --130 + j*(-122) --85 + j*(98) -86 + j*(-28) --152 + j*(-158) --274 + j*(185) -112 + j*(320) -233 + j*(-37) --53 + j*(-80) -35 + j*(146) -236 + j*(-71) --59 + j*(-267) --232 + j*(49) -74 + j*(153) -74 + j*(-140) --220 + j*(-44) --60 + j*(252) -216 + j*(71) -47 + j*(-149) --83 + j*(-3) -47 + j*(13) --41 + j*(-135) --235 + j*(13) --110 + j*(233) -67 + j*(183) -64 + j*(119) -117 + j*(146) -194 + j*(61) -143 + j*(-20) -128 + j*(15) -204 + j*(-31) -170 + j*(-153) -68 + j*(-177) -22 + j*(-149) --2 + j*(-132) -5 + j*(-116) --2 + j*(-176) --142 + j*(-200) --238 + j*(-6) --39 + j*(161) -194 + j*(-13) -81 + j*(-310) --246 + j*(-333) --436 + j*(-70) --335 + j*(222) --67 + j*(279) -45 + j*(95) --96 + j*(21) --137 + j*(187) -50 + j*(249) -135 + j*(106) -70 + j*(63) -136 + j*(97) -212 + j*(-73) -5 + j*(-238) --239 + j*(-66) --150 + j*(211) -103 + j*(215) -163 + j*(35) -57 + j*(-25) -30 + j*(62) -146 + j*(84) -233 + j*(-52) -152 + j*(-210) --9 + j*(-251) --136 + j*(-193) --221 + j*(-83) --220 + j*(81) --87 + j*(194) -66 + j*(155) -107 + j*(48) -74 + j*(-18) -21 + j*(-40) --28 + j*(-1) -13 + j*(69) -110 + j*(30) -85 + j*(-83) --18 + j*(-68) -13 + j*(9) -90 + j*(-57) -10 + j*(-161) --117 + j*(-118) --137 + j*(-20) --113 + j*(33) --80 + j*(78) --25 + j*(77) --42 + j*(56) --46 + j*(147) -124 + j*(187) -217 + j*(-13) -31 + j*(-104) -2 + j*(95) -279 + j*(64) -256 + j*(-303) --119 + j*(-344) --187 + j*(-61) --23 + j*(-69) --168 + j*(-178) --296 + j*(68) --33 + j*(220) -90 + j*(-9) --116 + j*(-49) --62 + j*(161) -171 + j*(33) -8 + j*(-227) --273 + j*(-74) --165 + j*(191) -39 + j*(132) -1 + j*(-1) --91 + j*(30) --94 + j*(113) --35 + j*(174) -59 + j*(161) -62 + j*(87) -10 + j*(141) -151 + j*(231) -321 + j*(64) -194 + j*(-141) -42 + j*(-47) -175 + j*(44) -270 + j*(-148) -98 + j*(-295) --53 + j*(-226) --73 + j*(-174) --142 + j*(-168) --224 + j*(-60) --188 + j*(91) --53 + j*(160) -82 + j*(100) -92 + j*(-41) --30 + j*(-74) --54 + j*(42) -82 + j*(57) -119 + j*(-100) --28 + j*(-187) --156 + j*(-103) --156 + j*(23) --69 + j*(81) --1 + j*(32) --45 + j*(-26) --103 + j*(35) --39 + j*(94) --1 + j*(37) --69 + j*(52) --14 + j*(148) -107 + j*(83) -38 + j*(-28) --47 + j*(65) -69 + j*(149) -162 + j*(56) -148 + j*(-6) -187 + j*(-57) -151 + j*(-212) --47 + j*(-245) --120 + j*(-114) --88 + j*(-104) --215 + j*(-94) --254 + j*(150) -25 + j*(280) -215 + j*(49) -75 + j*(-141) --57 + j*(-86) --49 + j*(-52) --116 + j*(-78) --218 + j*(32) --154 + j*(216) -44 + j*(256) -159 + j*(120) -93 + j*(11) -29 + j*(79) -168 + j*(136) -289 + j*(-55) -121 + j*(-248) --80 + j*(-144) --9 + j*(2) -95 + j*(-88) --16 + j*(-204) --158 + j*(-133) --169 + j*(-13) --126 + j*(45) --87 + j*(78) --39 + j*(97) -15 + j*(76) -16 + j*(18) --62 + j*(27) --51 + j*(170) -177 + j*(209) -314 + j*(-57) -86 + j*(-280) --158 + j*(-137) --91 + j*(60) -25 + j*(33) -6 + j*(-6) -29 + j*(25) -83 + j*(-34) -33 + j*(-112) --38 + j*(-119) --115 + j*(-112) --223 + j*(7) --120 + j*(232) -189 + j*(190) -219 + j*(-157) --121 + j*(-256) --274 + j*(45) --37 + j*(234) -153 + j*(59) -25 + j*(-115) --133 + j*(-16) --61 + j*(133) -59 + j*(97) -47 + j*(34) -62 + j*(63) -148 + j*(-17) -33 + j*(-173) --186 + j*(-53) --88 + j*(214) -206 + j*(169) -242 + j*(-101) -56 + j*(-220) --110 + j*(-164) --190 + j*(8) --42 + j*(207) -250 + j*(103) -214 + j*(-243) --114 + j*(-279) --187 + j*(-39) --49 + j*(-1) --78 + j*(-83) --148 + j*(-26) --132 + j*(13) --185 + j*(52) --146 + j*(223) -103 + j*(230) -155 + j*(-30) --83 + j*(-110) --197 + j*(76) --116 + j*(229) -21 + j*(315) -247 + j*(280) -337 + j*(28) -148 + j*(-100) -95 + j*(46) -279 + j*(8) -224 + j*(-229) -4 + j*(-213) -19 + j*(-83) -58 + j*(-142) --37 + j*(-124) -52 + j*(-28) -164 + j*(-220) --91 + j*(-414) --366 + j*(-209) --298 + j*(42) --187 + j*(81) --144 + j*(138) -12 + j*(137) -37 + j*(-57) --192 + j*(-78) --225 + j*(185) -33 + j*(250) -116 + j*(46) --38 + j*(-6) --51 + j*(135) -100 + j*(148) -154 + j*(6) -57 + j*(-79) --26 + j*(-34) --6 + j*(18) -17 + j*(-15) --52 + j*(-29) --91 + j*(77) -27 + j*(167) -163 + j*(81) -145 + j*(-67) -37 + j*(-111) --34 + j*(-67) --49 + j*(-6) --13 + j*(38) -33 + j*(25) -28 + j*(-11) -10 + j*(5) -55 + j*(19) -85 + j*(-62) --13 + j*(-122) --99 + j*(-35) --28 + j*(44) -11 + j*(-31) --107 + j*(-26) --80 + j*(164) -177 + j*(151) -196 + j*(-140) --95 + j*(-177) --123 + j*(104) -161 + j*(116) -181 + j*(-173) --81 + j*(-233) --182 + j*(-49) --103 + j*(49) --45 + j*(55) --7 + j*(40) --18 + j*(9) --38 + j*(62) -76 + j*(97) -147 + j*(-59) -1 + j*(-163) --95 + j*(-69) --64 + j*(-48) --163 + j*(-59) --209 + j*(148) -40 + j*(250) -170 + j*(28) -2 + j*(-81) --56 + j*(37) -15 + j*(49) --16 + j*(30) -20 + j*(98) -111 + j*(29) -21 + j*(-49) --20 + j*(66) -112 + j*(75) -100 + j*(-32) -85 + j*(42) -291 + j*(-49) -173 + j*(-420) --298 + j*(-370) --324 + j*(59) --48 + j*(74) --159 + j*(-41) --181 + j*(245) -249 + j*(251) -287 + j*(-256) --209 + j*(-344) --335 + j*(52) --99 + j*(153) --103 + j*(59) --148 + j*(183) -20 + j*(267) -143 + j*(168) -164 + j*(77) -154 + j*(-22) -39 + j*(-74) --16 + j*(31) -81 + j*(57) -69 + j*(-30) -8 + j*(27) -122 + j*(63) -148 + j*(-88) -8 + j*(-102) -31 + j*(-4) -88 + j*(-91) --49 + j*(-115) --43 + j*(47) -124 + j*(12) -73 + j*(-129) -17 + j*(-69) -127 + j*(-136) --30 + j*(-349) --322 + j*(-190) --207 + j*(65) --92 + j*(-72) --361 + j*(-65) --357 + j*(356) -94 + j*(453) -255 + j*(125) -100 + j*(25) -146 + j*(93) -240 + j*(-49) -127 + j*(-201) --4 + j*(-204) --99 + j*(-184) --204 + j*(-93) --183 + j*(53) --101 + j*(95) --60 + j*(116) -37 + j*(127) -93 + j*(2) --21 + j*(-56) --40 + j*(37) -48 + j*(-22) --98 + j*(-139) --279 + j*(56) --123 + j*(288) -81 + j*(230) -97 + j*(149) -161 + j*(140) -210 + j*(7) -93 + j*(-68) -64 + j*(6) -116 + j*(-44) --8 + j*(-90) --49 + j*(92) -177 + j*(143) -261 + j*(-70) -144 + j*(-159) -139 + j*(-167) -78 + j*(-310) --162 + j*(-307) --234 + j*(-112) --184 + j*(-62) --274 + j*(4) --209 + j*(250) -97 + j*(261) -163 + j*(23) -49 + j*(-13) -113 + j*(1) -88 + j*(-163) --120 + j*(-135) --76 + j*(54) -69 + j*(-40) --93 + j*(-144) --165 + j*(64) -66 + j*(83) -15 + j*(-163) --262 + j*(-41) --98 + j*(272) -240 + j*(97) -84 + j*(-248) --245 + j*(-141) --202 + j*(138) --9 + j*(141) --1 + j*(28) --83 + j*(39) --77 + j*(132) -23 + j*(163) -81 + j*(83) -12 + j*(46) -16 + j*(149) -179 + j*(144) -218 + j*(-46) -69 + j*(-117) -20 + j*(-46) -28 + j*(-66) --68 + j*(-49) --46 + j*(98) -112 + j*(77) -72 + j*(-54) --12 + j*(48) -187 + j*(113) -289 + j*(-169) --6 + j*(-335) --197 + j*(-103) --42 + j*(43) -20 + j*(-68) --81 + j*(-54) --11 + j*(52) -110 + j*(-62) --29 + j*(-222) --240 + j*(-105) --187 + j*(134) -35 + j*(152) -90 + j*(-28) --54 + j*(-78) --71 + j*(60) -93 + j*(36) -40 + j*(-177) --226 + j*(-124) --188 + j*(163) -86 + j*(129) -23 + j*(-124) --231 + j*(-31) --148 + j*(234) -86 + j*(197) -88 + j*(45) -25 + j*(46) -52 + j*(56) -45 + j*(24) -30 + j*(45) -59 + j*(49) -66 + j*(45) -127 + j*(57) -200 + j*(-73) -43 + j*(-219) --136 + j*(-70) -16 + j*(93) -148 + j*(-98) --89 + j*(-221) --221 + j*(32) -6 + j*(159) -101 + j*(-30) --57 + j*(-80) --86 + j*(57) -13 + j*(91) -62 + j*(70) -149 + j*(31) -168 + j*(-148) --50 + j*(-239) --175 + j*(-48) --16 + j*(45) -9 + j*(-124) --214 + j*(-118) --241 + j*(146) --8 + j*(228) -90 + j*(82) -18 + j*(32) -32 + j*(85) -107 + j*(50) -110 + j*(-39) -56 + j*(-98) --40 + j*(-115) --132 + j*(-23) --74 + j*(122) -91 + j*(100) -89 + j*(-47) --24 + j*(-38) -23 + j*(49) -101 + j*(-47) --33 + j*(-129) --115 + j*(35) -75 + j*(115) -168 + j*(-95) --33 + j*(-216) --160 + j*(-74) --98 + j*(11) --95 + j*(-8) --118 + j*(54) --52 + j*(83) --64 + j*(42) --121 + j*(134) -11 + j*(265) -197 + j*(185) -222 + j*(35) -206 + j*(-37) -188 + j*(-154) -32 + j*(-243) --110 + j*(-148) --96 + j*(-51) --106 + j*(-40) --139 + j*(66) -8 + j*(163) -144 + j*(21) -14 + j*(-112) --97 + j*(24) -70 + j*(129) -204 + j*(-57) -37 + j*(-243) --178 + j*(-142) --157 + j*(46) --51 + j*(66) --57 + j*(59) -1 + j*(157) -222 + j*(100) -239 + j*(-216) --88 + j*(-344) --288 + j*(-112) --199 + j*(47) --189 + j*(48) --208 + j*(198) -13 + j*(298) -150 + j*(100) --20 + j*(11) --41 + j*(216) -219 + j*(242) -327 + j*(5) -231 + j*(-164) -106 + j*(-264) --136 + j*(-272) --288 + j*(7) --48 + j*(240) -183 + j*(67) -69 + j*(-98) -8 + j*(-6) -122 + j*(-62) --15 + j*(-235) --255 + j*(-78) --135 + j*(192) -119 + j*(133) -104 + j*(-75) --58 + j*(-89) --105 + j*(45) -6 + j*(143) -162 + j*(75) -156 + j*(-111) --13 + j*(-154) --62 + j*(-30) -33 + j*(-12) -28 + j*(-91) --11 + j*(-88) -13 + j*(-136) --122 + j*(-258) --389 + j*(-124) --364 + j*(233) --42 + j*(342) -110 + j*(139) -2 + j*(38) --25 + j*(129) -90 + j*(124) -81 + j*(5) --28 + j*(35) -36 + j*(149) -177 + j*(70) -100 + j*(-72) --10 + j*(13) -117 + j*(105) -227 + j*(-49) -110 + j*(-186) -2 + j*(-158) --42 + j*(-147) --136 + j*(-84) --80 + j*(61) -59 + j*(-19) --93 + j*(-139) --214 + j*(105) -108 + j*(238) -248 + j*(-132) --146 + j*(-269) --270 + j*(115) -57 + j*(209) -85 + j*(-21) --40 + j*(62) -174 + j*(110) -185 + j*(-214) --194 + j*(-202) --136 + j*(186) -248 + j*(59) -61 + j*(-331) --327 + j*(-134) --161 + j*(205) -70 + j*(64) --84 + j*(-35) --82 + j*(168) -170 + j*(116) -105 + j*(-159) --163 + j*(-94) --102 + j*(147) -100 + j*(89) -31 + j*(-79) --114 + j*(4) --25 + j*(144) -112 + j*(64) -41 + j*(-65) --84 + j*(9) --18 + j*(151) -137 + j*(129) -190 + j*(9) -163 + j*(-89) -85 + j*(-173) --68 + j*(-154) --93 + j*(26) -119 + j*(64) -183 + j*(-209) --139 + j*(-343) --365 + j*(-29) --107 + j*(252) -180 + j*(51) -11 + j*(-232) --279 + j*(-96) --200 + j*(193) -42 + j*(170) -37 + j*(-5) --93 + j*(13) --81 + j*(137) -21 + j*(187) -158 + j*(174) -303 + j*(-10) -155 + j*(-324) --275 + j*(-277) --348 + j*(180) -57 + j*(327) -197 + j*(1) --89 + j*(-71) --107 + j*(244) -254 + j*(283) -382 + j*(-61) -137 + j*(-263) --69 + j*(-141) --19 + j*(32) -138 + j*(8) -135 + j*(-159) --20 + j*(-175) --9 + j*(-51) -126 + j*(-153) --52 + j*(-384) --409 + j*(-234) --389 + j*(165) --78 + j*(276) -81 + j*(133) -94 + j*(11) -42 + j*(-99) --103 + j*(-112) --155 + j*(25) --57 + j*(74) --47 + j*(23) --64 + j*(69) -36 + j*(51) --16 + j*(-105) --230 + j*(-46) --211 + j*(189) --51 + j*(221) --39 + j*(208) -67 + j*(312) -308 + j*(188) -240 + j*(-112) --30 + j*(-91) --16 + j*(126) -153 + j*(117) -170 + j*(12) -156 + j*(-11) -173 + j*(-64) -130 + j*(-112) -123 + j*(-123) -100 + j*(-220) --86 + j*(-247) --170 + j*(-43) -21 + j*(40) -64 + j*(-161) --175 + j*(-176) --196 + j*(100) -91 + j*(138) -151 + j*(-144) --111 + j*(-234) --230 + j*(-19) --85 + j*(96) --11 + j*(9) --78 + j*(-10) --66 + j*(57) --17 + j*(30) --70 + j*(21) --45 + j*(133) -139 + j*(109) -154 + j*(-121) --70 + j*(-189) --165 + j*(-28) --98 + j*(46) --93 + j*(60) --33 + j*(136) -93 + j*(59) --5 + j*(-81) --144 + j*(55) -36 + j*(194) -176 + j*(-16) --49 + j*(-146) --166 + j*(75) -32 + j*(179) -109 + j*(33) -25 + j*(9) -74 + j*(42) -80 + j*(-77) --93 + j*(-79) --105 + j*(128) -111 + j*(162) -170 + j*(-36) --4 + j*(-98) --60 + j*(74) -142 + j*(148) -281 + j*(-80) -70 + j*(-296) --184 + j*(-135) --49 + j*(103) -166 + j*(-62) --46 + j*(-301) --354 + j*(-80) --202 + j*(281) -147 + j*(244) -206 + j*(-15) -78 + j*(-109) -20 + j*(-95) --17 + j*(-116) --112 + j*(-98) --159 + j*(30) --44 + j*(146) -110 + j*(66) -59 + j*(-88) --69 + j*(-35) -13 + j*(67) -104 + j*(-51) --37 + j*(-129) --83 + j*(6) -40 + j*(-13) --67 + j*(-129) --181 + j*(74) -120 + j*(185) -238 + j*(-213) --223 + j*(-363) --411 + j*(107) --2 + j*(288) -109 + j*(-43) --169 + j*(-46) --73 + j*(214) -182 + j*(56) --7 + j*(-186) --223 + j*(5) --57 + j*(177) -38 + j*(27) --137 + j*(19) --122 + j*(259) -152 + j*(303) -272 + j*(86) --58 + j*(-93) --100 + j*(0) --47 + j*(62) --12 + j*(48) --19 + j*(68) -38 + j*(112) -134 + j*(77) -177 + j*(-38) -98 + j*(-164) --70 + j*(-146) --91 + j*(26) -86 + j*(44) -100 + j*(-155) --105 + j*(-187) --153 + j*(-31) --88 + j*(-11) --148 + j*(4) --104 + j*(144) -77 + j*(93) -1 + j*(-83) --163 + j*(29) --42 + j*(179) -59 + j*(88) -6 + j*(103) -173 + j*(161) -295 + j*(-125) --27 + j*(-320) --240 + j*(-48) --51 + j*(89) --64 + j*(-56) --240 + j*(108) --5 + j*(366) -302 + j*(178) -229 + j*(-81) -117 + j*(-100) -71 + j*(-159) --107 + j*(-115) --44 + j*(127) -263 + j*(4) -87 + j*(-390) --380 + j*(-223) --282 + j*(247) -94 + j*(209) -51 + j*(-11) --28 + j*(110) -204 + j*(122) -228 + j*(-181) --72 + j*(-256) --180 + j*(-27) --45 + j*(78) -35 + j*(24) -47 + j*(-24) -25 + j*(-95) --91 + j*(-107) --139 + j*(34) -9 + j*(113) -112 + j*(-32) --18 + j*(-163) --177 + j*(-57) --107 + j*(117) -78 + j*(79) -77 + j*(-130) --155 + j*(-194) --317 + j*(21) --192 + j*(254) -25 + j*(245) -75 + j*(124) -42 + j*(116) -113 + j*(134) -172 + j*(31) -92 + j*(-42) -69 + j*(21) -177 + j*(-21) -120 + j*(-209) --117 + j*(-191) --136 + j*(36) -48 + j*(42) -5 + j*(-117) --158 + j*(-22) --24 + j*(159) -185 + j*(-5) -11 + j*(-269) --325 + j*(-140) --317 + j*(235) --3 + j*(373) -219 + j*(210) -212 + j*(26) -151 + j*(-43) -105 + j*(-101) --23 + j*(-127) --122 + j*(30) -38 + j*(196) -255 + j*(71) -202 + j*(-150) -57 + j*(-155) -62 + j*(-115) -39 + j*(-182) --60 + j*(-165) --47 + j*(-109) --64 + j*(-175) --222 + j*(-132) --204 + j*(82) -8 + j*(83) -1 + j*(-105) --180 + j*(-86) --175 + j*(76) --64 + j*(91) --54 + j*(36) --90 + j*(42) --106 + j*(91) --60 + j*(166) -63 + j*(159) -100 + j*(40) -21 + j*(1) -16 + j*(33) -9 + j*(-4) --69 + j*(47) -34 + j*(168) -188 + j*(21) -13 + j*(-138) --121 + j*(76) -148 + j*(175) -223 + j*(-135) --93 + j*(-193) --115 + j*(88) -107 + j*(58) -14 + j*(-93) --54 + j*(69) -182 + j*(64) -148 + j*(-245) --184 + j*(-229) --210 + j*(34) --93 + j*(59) --148 + j*(106) --1 + j*(295) -303 + j*(149) -215 + j*(-178) --49 + j*(-133) -8 + j*(54) -163 + j*(-39) -81 + j*(-192) --59 + j*(-179) --118 + j*(-100) --118 + j*(-17) --53 + j*(13) --23 + j*(-49) --103 + j*(-74) --150 + j*(24) --73 + j*(118) -40 + j*(91) -52 + j*(-34) --111 + j*(-65) --180 + j*(177) -151 + j*(338) -451 + j*(-25) -139 + j*(-444) --315 + j*(-242) --226 + j*(152) -42 + j*(132) -35 + j*(14) -57 + j*(62) -177 + j*(-66) --3 + j*(-282) --297 + j*(-113) --188 + j*(219) -132 + j*(180) -148 + j*(-101) --95 + j*(-163) --209 + j*(33) --90 + j*(197) -86 + j*(182) -173 + j*(62) -156 + j*(-76) -34 + j*(-168) --134 + j*(-119) --182 + j*(73) --31 + j*(220) -190 + j*(178) -297 + j*(-51) -141 + j*(-304) --197 + j*(-269) --278 + j*(76) -25 + j*(207) -144 + j*(-59) --113 + j*(-132) --148 + j*(136) -122 + j*(145) -107 + j*(-110) --127 + j*(-78) --93 + j*(135) -77 + j*(127) -96 + j*(30) -80 + j*(14) -95 + j*(-9) -99 + j*(-38) -117 + j*(-107) -3 + j*(-215) --190 + j*(-97) --77 + j*(134) -146 + j*(0) --30 + j*(-206) --221 + j*(6) -1 + j*(166) -99 + j*(-44) --90 + j*(-54) --4 + j*(112) -129 + j*(-68) --141 + j*(-153) --177 + j*(202) -255 + j*(204) -247 + j*(-276) --231 + j*(-282) --257 + j*(129) -39 + j*(151) -18 + j*(-12) --31 + j*(76) -124 + j*(52) -65 + j*(-145) --137 + j*(-75) --69 + j*(94) -24 + j*(14) --105 + j*(13) --45 + j*(247) -314 + j*(206) -386 + j*(-235) --34 + j*(-457) --368 + j*(-156) --218 + j*(197) -83 + j*(174) -133 + j*(-45) -3 + j*(-134) --103 + j*(-102) --164 + j*(-21) --149 + j*(93) --49 + j*(140) -1 + j*(98) --2 + j*(107) -66 + j*(122) -112 + j*(45) -75 + j*(13) -108 + j*(7) -89 + j*(-122) --135 + j*(-112) --146 + j*(194) -220 + j*(252) -347 + j*(-121) -47 + j*(-301) --122 + j*(-133) --78 + j*(-59) --132 + j*(-39) --121 + j*(107) -43 + j*(123) -65 + j*(3) -0 + j*(6) -28 + j*(19) --25 + j*(-3) --30 + j*(155) -253 + j*(176) -336 + j*(-194) --51 + j*(-327) --173 + j*(32) -180 + j*(102) -216 + j*(-272) --151 + j*(-323) --221 + j*(-20) -2 + j*(30) -21 + j*(-152) --139 + j*(-194) --252 + j*(-92) --257 + j*(56) --141 + j*(144) --59 + j*(66) --171 + j*(40) --189 + j*(245) -78 + j*(329) -228 + j*(83) -52 + j*(-64) --35 + j*(65) -88 + j*(93) -81 + j*(-29) --19 + j*(4) -51 + j*(73) -91 + j*(-49) --89 + j*(-61) --86 + j*(194) -256 + j*(208) -338 + j*(-194) --61 + j*(-372) --310 + j*(-57) --134 + j*(196) -39 + j*(155) -78 + j*(124) -184 + j*(71) -158 + j*(-110) --35 + j*(-86) -41 + j*(105) -264 + j*(-45) -71 + j*(-322) --231 + j*(-133) --52 + j*(143) -177 + j*(-59) --62 + j*(-261) --265 + j*(-12) --57 + j*(189) -100 + j*(47) -11 + j*(-28) -30 + j*(59) -171 + j*(-17) -115 + j*(-232) --136 + j*(-275) --298 + j*(-68) --198 + j*(163) -26 + j*(162) -63 + j*(-18) --88 + j*(-41) --87 + j*(114) -82 + j*(100) -62 + j*(-83) --148 + j*(-65) --165 + j*(178) -78 + j*(281) -283 + j*(105) -230 + j*(-146) -14 + j*(-204) --83 + j*(-59) -19 + j*(8) -47 + j*(-107) --103 + j*(-122) --119 + j*(39) -34 + j*(43) -8 + j*(-108) --144 + j*(-64) --92 + j*(64) --23 + j*(-25) --202 + j*(-58) --268 + j*(207) --1 + j*(356) -174 + j*(184) -100 + j*(89) -133 + j*(158) -271 + j*(72) -241 + j*(-103) -148 + j*(-155) -100 + j*(-218) --76 + j*(-274) --255 + j*(-100) --162 + j*(118) --14 + j*(100) --36 + j*(74) -29 + j*(173) -219 + j*(96) -190 + j*(-135) --16 + j*(-155) --52 + j*(0) -69 + j*(35) -124 + j*(-68) -57 + j*(-160) --52 + j*(-144) --59 + j*(-53) -17 + j*(-84) --78 + j*(-204) --276 + j*(-84) --190 + j*(167) -47 + j*(124) -13 + j*(-64) --138 + j*(-23) --124 + j*(95) --76 + j*(151) -35 + j*(229) -257 + j*(121) -202 + j*(-192) --126 + j*(-186) --129 + j*(104) -112 + j*(78) -50 + j*(-122) --115 + j*(-42) --47 + j*(78) -13 + j*(50) -39 + j*(70) -154 + j*(0) -69 + j*(-195) --146 + j*(-127) --76 + j*(21) --59 + j*(-121) --358 + j*(-37) --269 + j*(436) -284 + j*(436) -382 + j*(-49) -68 + j*(-164) -28 + j*(-40) -11 + j*(-114) --161 + j*(-1) -25 + j*(226) -277 + j*(-13) -2 + j*(-267) --229 + j*(18) -38 + j*(206) -164 + j*(-23) --12 + j*(-69) -23 + j*(59) -113 + j*(-27) -19 + j*(-70) -52 + j*(20) -153 + j*(-98) -1 + j*(-229) --131 + j*(-111) --78 + j*(-48) --129 + j*(-68) --166 + j*(77) -5 + j*(139) -53 + j*(0) --34 + j*(21) -91 + j*(74) -140 + j*(-159) --173 + j*(-236) --292 + j*(107) -22 + j*(258) -171 + j*(2) --24 + j*(-113) --100 + j*(34) -14 + j*(82) -34 + j*(-3) --37 + j*(-2) --23 + j*(80) -86 + j*(86) -136 + j*(-40) -23 + j*(-136) --95 + j*(-59) --56 + j*(43) -0 + j*(30) --11 + j*(40) -77 + j*(76) -170 + j*(-75) -3 + j*(-244) --219 + j*(-118) --163 + j*(91) --27 + j*(72) --74 + j*(15) --110 + j*(128) -45 + j*(200) -165 + j*(61) -72 + j*(-80) --64 + j*(-24) --37 + j*(105) -81 + j*(119) -138 + j*(49) -156 + j*(-16) -142 + j*(-117) -9 + j*(-184) --108 + j*(-65) --1 + j*(55) -105 + j*(-69) --52 + j*(-182) --187 + j*(-1) --2 + j*(153) -178 + j*(-25) -27 + j*(-255) --250 + j*(-187) --313 + j*(76) --156 + j*(240) --13 + j*(222) -21 + j*(215) -143 + j*(276) -366 + j*(147) -343 + j*(-151) -117 + j*(-214) -105 + j*(-119) -141 + j*(-264) --132 + j*(-344) --269 + j*(-49) --8 + j*(69) -23 + j*(-182) --247 + j*(-142) --164 + j*(129) -55 + j*(-15) --192 + j*(-189) --375 + j*(148) --27 + j*(369) -183 + j*(85) --32 + j*(-37) --41 + j*(161) -185 + j*(100) -115 + j*(-148) --120 + j*(-119) --140 + j*(70) --25 + j*(124) -41 + j*(73) -18 + j*(6) --73 + j*(35) --45 + j*(182) -153 + j*(185) -195 + j*(-16) -21 + j*(-59) -9 + j*(117) -218 + j*(127) -294 + j*(-98) -137 + j*(-260) --60 + j*(-227) --136 + j*(-63) --22 + j*(70) -148 + j*(-11) -111 + j*(-217) --107 + j*(-260) --231 + j*(-105) --192 + j*(38) --115 + j*(89) --54 + j*(93) --22 + j*(81) -1 + j*(84) -52 + j*(76) -77 + j*(13) -37 + j*(-25) -25 + j*(8) -88 + j*(-7) -87 + j*(-119) --45 + j*(-185) --189 + j*(-96) --198 + j*(83) --51 + j*(183) -87 + j*(113) -77 + j*(4) -25 + j*(16) -90 + j*(40) -155 + j*(-81) -42 + j*(-221) --137 + j*(-199) --225 + j*(-76) --243 + j*(45) --204 + j*(182) --61 + j*(288) -133 + j*(248) -224 + j*(81) -153 + j*(-76) -4 + j*(-97) --74 + j*(21) -14 + j*(138) -168 + j*(95) -193 + j*(-69) -64 + j*(-153) --27 + j*(-81) -20 + j*(-16) -66 + j*(-81) --18 + j*(-142) --101 + j*(-75) --67 + j*(-4) --41 + j*(-32) --103 + j*(-24) --98 + j*(81) -29 + j*(103) -74 + j*(-22) --47 + j*(-78) --127 + j*(41) --26 + j*(160) -125 + j*(113) -160 + j*(-31) -75 + j*(-139) --60 + j*(-154) --174 + j*(-51) --153 + j*(119) -6 + j*(189) -113 + j*(96) -94 + j*(30) -121 + j*(30) -172 + j*(-88) -10 + j*(-219) --187 + j*(-54) --39 + j*(184) -237 + j*(52) -151 + j*(-251) --156 + j*(-244) --231 + j*(13) --58 + j*(145) -87 + j*(50) -42 + j*(-88) --91 + j*(-62) --61 + j*(79) -98 + j*(30) -33 + j*(-157) --182 + j*(-86) --115 + j*(130) -73 + j*(50) --46 + j*(-101) --185 + j*(64) -5 + j*(214) -159 + j*(35) -18 + j*(-108) --103 + j*(-11) --60 + j*(83) --4 + j*(95) -47 + j*(91) -85 + j*(33) -40 + j*(-16) -4 + j*(17) -15 + j*(41) -26 + j*(81) -150 + j*(123) -303 + j*(-62) -138 + j*(-344) --212 + j*(-277) --256 + j*(30) --73 + j*(128) --6 + j*(70) -5 + j*(75) -61 + j*(65) -85 + j*(18) -101 + j*(-24) -77 + j*(-115) --62 + j*(-132) --110 + j*(13) -10 + j*(68) -47 + j*(-10) -30 + j*(-11) -99 + j*(-71) --31 + j*(-247) --332 + j*(-99) --231 + j*(294) -177 + j*(280) -240 + j*(-62) -8 + j*(-164) --102 + j*(-46) --88 + j*(66) -23 + j*(156) -206 + j*(66) -171 + j*(-167) --32 + j*(-187) --60 + j*(-83) --61 + j*(-118) --185 + j*(-63) --129 + j*(107) -15 + j*(49) --84 + j*(-28) --100 + j*(136) -112 + j*(112) -54 + j*(-110) --141 + j*(-11) -1 + j*(137) -76 + j*(-54) --173 + j*(-47) --104 + j*(264) -245 + j*(156) -110 + j*(-190) --223 + j*(-24) --37 + j*(310) -304 + j*(158) -242 + j*(-159) --3 + j*(-188) --87 + j*(-29) -23 + j*(78) -160 + j*(-24) -63 + j*(-215) --173 + j*(-147) --156 + j*(84) -15 + j*(103) -30 + j*(21) -25 + j*(35) -62 + j*(-1) -10 + j*(-11) -81 + j*(68) -237 + j*(-103) -16 + j*(-366) --320 + j*(-170) --194 + j*(140) -1 + j*(51) --114 + j*(-6) --73 + j*(151) -81 + j*(52) --91 + j*(-49) --141 + j*(226) -212 + j*(274) -280 + j*(-65) -42 + j*(-98) -131 + j*(21) -194 + j*(-222) --152 + j*(-291) --223 + j*(76) -125 + j*(115) -122 + j*(-217) --176 + j*(-213) --190 + j*(-3) --119 + j*(-14) --219 + j*(14) --203 + j*(210) --6 + j*(287) -149 + j*(202) -209 + j*(55) -133 + j*(-83) -2 + j*(-46) -74 + j*(49) -179 + j*(-95) -3 + j*(-258) --199 + j*(-132) --170 + j*(35) --119 + j*(71) --83 + j*(136) -38 + j*(141) -54 + j*(34) --25 + j*(61) -61 + j*(153) -182 + j*(53) -131 + j*(-63) -85 + j*(-67) -73 + j*(-127) --61 + j*(-151) --122 + j*(-9) --18 + j*(52) -4 + j*(-5) --14 + j*(23) -58 + j*(1) --18 + j*(-116) --194 + j*(16) --37 + j*(268) -283 + j*(143) -243 + j*(-203) --57 + j*(-267) --205 + j*(-64) --112 + j*(121) -74 + j*(116) -119 + j*(-62) --58 + j*(-122) --123 + j*(66) -80 + j*(141) -176 + j*(-57) -19 + j*(-171) --87 + j*(-83) --71 + j*(-20) --68 + j*(3) --41 + j*(40) --4 + j*(32) --2 + j*(34) -58 + j*(47) -114 + j*(-51) -21 + j*(-151) --78 + j*(-112) --97 + j*(-73) --161 + j*(-37) --148 + j*(109) -38 + j*(129) -73 + j*(-78) --150 + j*(-136) --269 + j*(67) --170 + j*(247) --1 + j*(320) -208 + j*(259) -281 + j*(28) -121 + j*(-89) -81 + j*(-4) -174 + j*(-98) --25 + j*(-274) --297 + j*(-57) --144 + j*(271) -159 + j*(225) -216 + j*(40) -196 + j*(-65) -116 + j*(-190) --76 + j*(-161) --54 + j*(21) -95 + j*(-53) --59 + j*(-198) --228 + j*(7) --27 + j*(187) -124 + j*(35) -44 + j*(-49) -60 + j*(-37) -15 + j*(-174) --230 + j*(-104) --174 + j*(205) -130 + j*(169) -79 + j*(-66) --72 + j*(47) -117 + j*(155) -221 + j*(-62) -61 + j*(-147) -62 + j*(-91) -47 + j*(-239) --243 + j*(-231) --281 + j*(124) -54 + j*(195) -121 + j*(-86) --101 + j*(-129) --133 + j*(22) --74 + j*(42) --87 + j*(78) -10 + j*(142) -106 + j*(36) -32 + j*(-50) -4 + j*(-21) --4 + j*(-89) --188 + j*(-73) --204 + j*(218) -144 + j*(295) -277 + j*(-48) --11 + j*(-194) --123 + j*(30) -61 + j*(74) -34 + j*(-107) --177 + j*(-31) --98 + j*(231) -204 + j*(197) -244 + j*(-111) --33 + j*(-225) --197 + j*(-1) --30 + j*(187) -153 + j*(67) -63 + j*(-95) --81 + j*(-9) -12 + j*(141) -190 + j*(67) -177 + j*(-129) -13 + j*(-197) --107 + j*(-113) --117 + j*(-1) --60 + j*(71) -23 + j*(88) -100 + j*(35) -88 + j*(-69) --11 + j*(-82) --11 + j*(6) -96 + j*(-40) -5 + j*(-206) --248 + j*(-99) --163 + j*(227) -199 + j*(185) -191 + j*(-167) --119 + j*(-162) --76 + j*(105) -180 + j*(8) -55 + j*(-266) --228 + j*(-161) --160 + j*(80) -11 + j*(8) --114 + j*(-124) --274 + j*(42) --139 + j*(257) -96 + j*(208) -119 + j*(18) --11 + j*(-27) --40 + j*(74) -57 + j*(83) -52 + j*(-25) --79 + j*(-2) --48 + j*(165) -156 + j*(155) -175 + j*(-50) --1 + j*(-70) -21 + j*(83) -192 + j*(18) -117 + j*(-190) --97 + j*(-135) --58 + j*(47) -81 + j*(-12) --18 + j*(-130) --134 + j*(4) -12 + j*(124) -128 + j*(-17) -5 + j*(-112) --49 + j*(-5) -57 + j*(1) -31 + j*(-127) --113 + j*(-108) --129 + j*(9) --81 + j*(48) --56 + j*(81) -28 + j*(83) -38 + j*(-24) --100 + j*(-11) --66 + j*(181) -176 + j*(162) -204 + j*(-91) -9 + j*(-158) --65 + j*(-59) --69 + j*(-22) --90 + j*(67) -57 + j*(156) -198 + j*(-14) -37 + j*(-180) --115 + j*(-44) -4 + j*(60) -52 + j*(-54) --56 + j*(-61) --39 + j*(26) --1 + j*(-2) --39 + j*(29) -76 + j*(92) -187 + j*(-96) --28 + j*(-264) --224 + j*(-92) --122 + j*(61) --80 + j*(-1) --158 + j*(60) --59 + j*(183) -66 + j*(103) -13 + j*(32) -11 + j*(85) -72 + j*(45) -11 + j*(-5) --17 + j*(65) -42 + j*(86) -44 + j*(95) -161 + j*(163) -363 + j*(-30) -178 + j*(-357) --187 + j*(-235) --96 + j*(74) -130 + j*(-52) --52 + j*(-229) --209 + j*(-28) --30 + j*(89) -23 + j*(-59) --107 + j*(-59) --92 + j*(40) --68 + j*(20) --115 + j*(91) -22 + j*(194) -168 + j*(57) -70 + j*(-71) -26 + j*(-2) -120 + j*(-66) --8 + j*(-235) --249 + j*(-124) --223 + j*(129) --40 + j*(185) -47 + j*(116) -68 + j*(49) -35 + j*(-7) --30 + j*(8) --28 + j*(79) -33 + j*(113) -123 + j*(102) -204 + j*(-24) -76 + j*(-203) --170 + j*(-90) --69 + j*(195) -245 + j*(95) -158 + j*(-240) --174 + j*(-190) --177 + j*(107) -42 + j*(163) -142 + j*(49) -151 + j*(-68) -50 + j*(-195) --172 + j*(-136) --173 + j*(142) -119 + j*(221) -278 + j*(-36) -114 + j*(-250) --102 + j*(-200) --130 + j*(-32) --1 + j*(11) -24 + j*(-122) --148 + j*(-151) --196 + j*(33) --47 + j*(76) --72 + j*(-30) --170 + j*(101) -50 + j*(231) -221 + j*(-35) --45 + j*(-224) --215 + j*(4) --42 + j*(105) --57 + j*(-28) --194 + j*(96) --16 + j*(271) -156 + j*(112) -44 + j*(19) -76 + j*(128) -238 + j*(-6) -78 + j*(-228) --148 + j*(-119) --98 + j*(23) --104 + j*(-27) --246 + j*(102) --106 + j*(381) -239 + j*(347) -337 + j*(71) -212 + j*(-62) -150 + j*(-42) -183 + j*(-61) -163 + j*(-170) -12 + j*(-219) --98 + j*(-71) -46 + j*(55) -183 + j*(-117) --18 + j*(-289) --238 + j*(-91) --73 + j*(152) -176 + j*(39) -127 + j*(-198) --57 + j*(-233) --146 + j*(-152) --180 + j*(-85) --200 + j*(1) --144 + j*(107) -1 + j*(119) -73 + j*(-41) --114 + j*(-161) --310 + j*(48) --119 + j*(334) -217 + j*(216) -178 + j*(-86) --22 + j*(-79) -32 + j*(16) -74 + j*(-133) --153 + j*(-197) --279 + j*(30) --129 + j*(180) --37 + j*(119) --78 + j*(130) --8 + j*(230) -156 + j*(186) -185 + j*(20) -64 + j*(-52) -2 + j*(38) -104 + j*(86) -163 + j*(-53) -3 + j*(-146) --120 + j*(19) -37 + j*(163) -194 + j*(24) -87 + j*(-128) --36 + j*(-46) -44 + j*(45) -132 + j*(-40) -68 + j*(-155) --65 + j*(-154) --138 + j*(-47) --95 + j*(70) -10 + j*(97) -74 + j*(43) -95 + j*(-16) -81 + j*(-103) --44 + j*(-167) --199 + j*(-45) --132 + j*(197) -158 + j*(233) -322 + j*(-40) -137 + j*(-305) --164 + j*(-239) --192 + j*(28) -18 + j*(87) -59 + j*(-82) --100 + j*(-79) --55 + j*(91) -147 + j*(14) -74 + j*(-220) --156 + j*(-181) --140 + j*(-11) --47 + j*(-61) --153 + j*(-135) --257 + j*(-30) --238 + j*(66) --244 + j*(126) --209 + j*(260) --46 + j*(312) -22 + j*(236) -9 + j*(281) -201 + j*(363) -430 + j*(145) -317 + j*(-176) -32 + j*(-187) --30 + j*(-4) -60 + j*(49) -90 + j*(29) -136 + j*(47) -245 + j*(-40) -196 + j*(-244) --38 + j*(-298) --174 + j*(-123) --88 + j*(11) --17 + j*(-28) --68 + j*(-49) --83 + j*(29) --5 + j*(65) -43 + j*(22) -53 + j*(-15) -59 + j*(-69) --15 + j*(-142) --151 + j*(-98) --187 + j*(67) --66 + j*(193) -110 + j*(187) -238 + j*(45) -207 + j*(-169) -2 + j*(-263) --160 + j*(-136) --109 + j*(12) --6 + j*(-22) --65 + j*(-117) --212 + j*(-54) --209 + j*(144) --12 + j*(242) -166 + j*(105) -113 + j*(-104) --93 + j*(-127) --184 + j*(53) --57 + j*(207) -129 + j*(167) -175 + j*(4) -84 + j*(-77) -45 + j*(-45) -97 + j*(-89) -6 + j*(-246) --279 + j*(-209) --381 + j*(130) --100 + j*(376) -206 + j*(229) -187 + j*(-40) --4 + j*(-87) --64 + j*(35) -8 + j*(90) -42 + j*(54) -29 + j*(59) -69 + j*(88) -132 + j*(49) -135 + j*(-20) -111 + j*(-54) -91 + j*(-91) -34 + j*(-111) --1 + j*(-77) -13 + j*(-76) --38 + j*(-104) --95 + j*(-18) -4 + j*(59) -75 + j*(-46) --35 + j*(-94) --40 + j*(23) -91 + j*(-29) --1 + j*(-185) --167 + j*(-86) --81 + j*(33) --61 + j*(-68) --223 + j*(7) --105 + j*(243) -148 + j*(127) -32 + j*(-69) --72 + j*(95) -171 + j*(127) -173 + j*(-175) --131 + j*(-167) --89 + j*(83) -95 + j*(-29) --90 + j*(-171) --210 + j*(43) --22 + j*(119) --40 + j*(-27) --184 + j*(100) -2 + j*(282) -200 + j*(127) -130 + j*(-17) -111 + j*(-9) -117 + j*(-129) --94 + j*(-177) --190 + j*(54) -12 + j*(165) -109 + j*(14) -8 + j*(-57) --64 + j*(-12) --117 + j*(70) --55 + j*(274) -291 + j*(320) -506 + j*(-68) -216 + j*(-407) --111 + j*(-269) --52 + j*(-72) -22 + j*(-175) --177 + j*(-229) --292 + j*(14) --74 + j*(188) -116 + j*(2) --67 + j*(-202) --332 + j*(-25) --221 + j*(295) -78 + j*(299) -143 + j*(116) -87 + j*(101) -180 + j*(128) -279 + j*(-5) -235 + j*(-170) -111 + j*(-284) --101 + j*(-310) --286 + j*(-110) --165 + j*(149) -86 + j*(95) -54 + j*(-112) --113 + j*(-77) --71 + j*(54) -33 + j*(-2) --43 + j*(-102) --169 + j*(-28) --141 + j*(131) -21 + j*(176) -119 + j*(57) -62 + j*(-42) -23 + j*(-21) -62 + j*(-74) --66 + j*(-185) --256 + j*(-33) --129 + j*(194) -70 + j*(87) --54 + j*(-48) --144 + j*(112) -21 + j*(165) -12 + j*(29) --115 + j*(135) -61 + j*(291) -226 + j*(127) -120 + j*(44) -197 + j*(144) -371 + j*(-76) -93 + j*(-339) --199 + j*(-67) -62 + j*(204) -298 + j*(-40) -105 + j*(-233) --4 + j*(-117) -64 + j*(-120) --18 + j*(-175) --41 + j*(-80) -53 + j*(-147) --121 + j*(-286) --337 + j*(-67) --146 + j*(177) -47 + j*(35) --89 + j*(-62) --99 + j*(100) -95 + j*(51) -17 + j*(-166) --212 + j*(-88) --161 + j*(119) --18 + j*(93) --62 + j*(25) --94 + j*(119) -40 + j*(178) -163 + j*(55) -100 + j*(-137) --139 + j*(-170) --284 + j*(79) --76 + j*(322) -199 + j*(191) -124 + j*(-40) --28 + j*(47) -128 + j*(159) -260 + j*(-51) -57 + j*(-220) --107 + j*(-76) --18 + j*(35) -21 + j*(-42) --72 + j*(-40) --78 + j*(76) -26 + j*(135) -158 + j*(83) -202 + j*(-102) -0 + j*(-253) --227 + j*(-74) --90 + j*(181) -142 + j*(74) -46 + j*(-95) --36 + j*(17) -120 + j*(2) -25 + j*(-218) --256 + j*(-74) --93 + j*(234) -197 + j*(65) -5 + j*(-176) --179 + j*(49) -68 + j*(189) -176 + j*(-54) --35 + j*(-127) --68 + j*(35) -38 + j*(34) -17 + j*(-4) -62 + j*(30) -120 + j*(-97) --59 + j*(-191) --181 + j*(-20) --69 + j*(86) --48 + j*(62) --11 + j*(187) -285 + j*(157) -341 + j*(-256) --76 + j*(-428) --305 + j*(-126) --152 + j*(51) --106 + j*(-14) --175 + j*(42) --112 + j*(139) --47 + j*(139) --3 + j*(173) -124 + j*(151) -150 + j*(21) -98 + j*(-5) -159 + j*(-37) -103 + j*(-225) --169 + j*(-203) --190 + j*(72) -42 + j*(92) -26 + j*(-97) --136 + j*(-57) --112 + j*(64) --71 + j*(72) --46 + j*(134) -115 + j*(112) -98 + j*(-119) --182 + j*(-112) --197 + j*(175) -30 + j*(197) --2 + j*(75) --61 + j*(226) -189 + j*(305) -315 + j*(74) -192 + j*(-13) -255 + j*(34) -334 + j*(-185) -63 + j*(-341) --110 + j*(-105) -100 + j*(14) -175 + j*(-221) --57 + j*(-315) --185 + j*(-172) --187 + j*(-81) --210 + j*(38) --52 + j*(190) -195 + j*(50) -103 + j*(-244) --187 + j*(-214) --216 + j*(17) --74 + j*(57) --68 + j*(-6) --95 + j*(25) --50 + j*(40) --60 + j*(-6) --115 + j*(25) --94 + j*(90) --54 + j*(87) --71 + j*(102) --31 + j*(175) -88 + j*(174) -153 + j*(68) -116 + j*(-25) -47 + j*(-53) --10 + j*(-28) --8 + j*(33) -66 + j*(31) -66 + j*(-81) --95 + j*(-101) --158 + j*(102) -57 + j*(216) -211 + j*(13) -25 + j*(-153) --134 + j*(28) -48 + j*(187) -210 + j*(25) -92 + j*(-111) -34 + j*(-24) -149 + j*(-68) -56 + j*(-260) --198 + j*(-196) --202 + j*(29) --91 + j*(60) --122 + j*(81) --25 + j*(231) -221 + j*(131) -146 + j*(-146) --112 + j*(-62) -26 + j*(181) -291 + j*(2) -134 + j*(-296) --140 + j*(-214) --124 + j*(-47) --105 + j*(-64) --187 + j*(31) --49 + j*(195) -172 + j*(66) -89 + j*(-181) --160 + j*(-173) --251 + j*(30) --158 + j*(216) -66 + j*(269) -252 + j*(84) -152 + j*(-173) --115 + j*(-153) --155 + j*(78) -22 + j*(159) -121 + j*(59) -110 + j*(-18) -107 + j*(-64) -78 + j*(-160) --71 + j*(-231) --272 + j*(-127) --298 + j*(153) --40 + j*(322) -209 + j*(154) -129 + j*(-89) --78 + j*(-45) --30 + j*(139) -154 + j*(100) -146 + j*(-78) -5 + j*(-105) --30 + j*(-6) -42 + j*(25) -78 + j*(-33) -49 + j*(-81) -10 + j*(-93) --25 + j*(-88) --45 + j*(-66) --37 + j*(-63) --71 + j*(-98) --168 + j*(-62) --174 + j*(75) --57 + j*(114) --51 + j*(44) --114 + j*(128) -53 + j*(245) -244 + j*(46) -56 + j*(-189) --183 + j*(-27) --54 + j*(180) -86 + j*(95) -33 + j*(69) -147 + j*(130) -258 + j*(-103) --43 + j*(-267) --233 + j*(59) -105 + j*(238) -250 + j*(-105) --94 + j*(-200) --133 + j*(144) -221 + j*(134) -185 + j*(-224) --156 + j*(-179) --106 + j*(123) -157 + j*(67) -100 + j*(-156) --79 + j*(-107) --30 + j*(28) -83 + j*(-28) -36 + j*(-136) --61 + j*(-124) --77 + j*(-66) --62 + j*(-59) --79 + j*(-62) --92 + j*(-49) --110 + j*(-57) --182 + j*(-35) --214 + j*(95) --91 + j*(204) -60 + j*(141) -56 + j*(3) --45 + j*(-40) --129 + j*(17) --141 + j*(137) --25 + j*(233) -122 + j*(161) -86 + j*(21) --23 + j*(67) -54 + j*(190) -211 + j*(124) -212 + j*(-29) -135 + j*(-88) -77 + j*(-112) --6 + j*(-95) --18 + j*(2) -88 + j*(3) -71 + j*(-130) --93 + j*(-113) --89 + j*(60) -63 + j*(59) -40 + j*(-63) --64 + j*(4) -46 + j*(124) -199 + j*(3) -110 + j*(-165) --14 + j*(-121) -27 + j*(-78) --1 + j*(-172) --158 + j*(-121) --114 + j*(62) -56 + j*(11) --25 + j*(-129) --136 + j*(-5) -47 + j*(67) -91 + j*(-194) --243 + j*(-243) --317 + j*(116) -11 + j*(177) -3 + j*(-127) --325 + j*(-47) --234 + j*(315) -100 + j*(265) -64 + j*(33) --65 + j*(122) -97 + j*(205) -181 + j*(7) --6 + j*(-79) --92 + j*(75) -12 + j*(163) -88 + j*(139) -138 + j*(116) -185 + j*(54) -168 + j*(-6) -181 + j*(-8) -240 + j*(-107) -139 + j*(-284) --102 + j*(-268) --188 + j*(-57) --70 + j*(79) -58 + j*(59) -124 + j*(-29) -103 + j*(-166) --71 + j*(-239) --239 + j*(-76) --129 + j*(154) -112 + j*(103) -102 + j*(-105) --44 + j*(-100) -5 + j*(-24) -39 + j*(-165) --192 + j*(-214) --280 + j*(54) --28 + j*(146) -11 + j*(-100) --272 + j*(-77) --240 + j*(257) -103 + j*(257) -129 + j*(-45) --126 + j*(-84) --192 + j*(124) --57 + j*(243) -98 + j*(217) -176 + j*(70) -47 + j*(-66) --117 + j*(63) -3 + j*(264) -213 + j*(202) -236 + j*(78) -286 + j*(42) -349 + j*(-157) -115 + j*(-352) --127 + j*(-173) -20 + j*(19) -157 + j*(-155) --40 + j*(-293) --196 + j*(-150) --152 + j*(-35) --146 + j*(-13) --134 + j*(73) --30 + j*(105) -13 + j*(47) -10 + j*(41) -62 + j*(22) -60 + j*(-71) --35 + j*(-108) --110 + j*(-59) --139 + j*(27) --74 + j*(130) -66 + j*(100) -47 + j*(-45) --98 + j*(-1) --24 + j*(165) -166 + j*(89) -119 + j*(-95) --11 + j*(-73) -14 + j*(-10) -33 + j*(-52) --2 + j*(-54) -25 + j*(-62) --21 + j*(-153) --182 + j*(-127) --233 + j*(45) --139 + j*(170) -1 + j*(206) -148 + j*(111) -108 + j*(-99) --129 + j*(-91) --134 + j*(153) -90 + j*(165) -76 + j*(2) --10 + j*(93) -205 + j*(142) -282 + j*(-177) --66 + j*(-310) --218 + j*(-15) -1 + j*(78) --14 + j*(-107) --235 + j*(-4) --125 + j*(271) -153 + j*(228) -177 + j*(35) -113 + j*(18) -173 + j*(6) -194 + j*(-136) -57 + j*(-248) --127 + j*(-214) --227 + j*(-45) --142 + j*(150) -74 + j*(161) -149 + j*(-24) -10 + j*(-123) --74 + j*(-17) -27 + j*(42) -69 + j*(-86) --99 + j*(-143) --210 + j*(53) --30 + j*(233) -194 + j*(115) -153 + j*(-89) -27 + j*(-88) -62 + j*(-47) -72 + j*(-163) --100 + j*(-204) --189 + j*(-44) --81 + j*(39) --68 + j*(-37) --172 + j*(21) --89 + j*(191) -129 + j*(135) -123 + j*(-83) --49 + j*(-111) --71 + j*(-8) --25 + j*(-44) --149 + j*(-86) --254 + j*(98) --92 + j*(288) -134 + j*(214) -148 + j*(37) -54 + j*(-8) -28 + j*(28) -52 + j*(37) -73 + j*(12) -54 + j*(-32) -0 + j*(-33) --11 + j*(12) -13 + j*(13) --25 + j*(10) --30 + j*(112) -132 + j*(161) -252 + j*(-8) -144 + j*(-168) -29 + j*(-141) -30 + j*(-132) --53 + j*(-196) --215 + j*(-105) --197 + j*(113) --7 + j*(194) -131 + j*(92) -123 + j*(-40) -34 + j*(-86) --18 + j*(-30) -45 + j*(15) -116 + j*(-76) -27 + j*(-212) --169 + j*(-191) --255 + j*(8) --118 + j*(182) -92 + j*(132) -102 + j*(-62) --54 + j*(-100) --85 + j*(8) --28 + j*(4) --95 + j*(-16) --102 + j*(118) -75 + j*(128) -71 + j*(-64) --132 + j*(-17) --40 + j*(214) -228 + j*(106) -140 + j*(-165) --86 + j*(-104) --25 + j*(43) -59 + j*(-49) --69 + j*(-115) --153 + j*(-3) --126 + j*(90) --95 + j*(182) -64 + j*(298) -332 + j*(189) -383 + j*(-132) -158 + j*(-334) --75 + j*(-292) --163 + j*(-157) --159 + j*(-76) --169 + j*(-34) --181 + j*(57) --85 + j*(127) --28 + j*(52) --142 + j*(67) --79 + j*(303) -290 + j*(274) -351 + j*(-153) --33 + j*(-279) --140 + j*(3) -62 + j*(5) --73 + j*(-185) --316 + j*(36) --100 + j*(343) -207 + j*(205) -150 + j*(-18) -44 + j*(9) -76 + j*(36) -62 + j*(19) -93 + j*(89) -264 + j*(37) -279 + j*(-225) -16 + j*(-364) --221 + j*(-199) --173 + j*(59) -66 + j*(86) -129 + j*(-153) --130 + j*(-253) --272 + j*(4) --43 + j*(154) -59 + j*(-58) --181 + j*(-96) --188 + j*(203) -158 + j*(231) -231 + j*(-121) --78 + j*(-242) --231 + j*(-1) --73 + j*(164) -84 + j*(79) -61 + j*(-66) --76 + j*(-97) --165 + j*(21) --100 + j*(154) -40 + j*(170) -131 + j*(82) -130 + j*(-43) -13 + j*(-129) --132 + j*(-51) --111 + j*(118) -43 + j*(163) -134 + j*(69) -128 + j*(-24) -84 + j*(-93) --4 + j*(-115) --61 + j*(-58) --43 + j*(-29) --78 + j*(-49) --159 + j*(25) --115 + j*(165) -18 + j*(211) -129 + j*(172) -212 + j*(86) -221 + j*(-52) -125 + j*(-137) -45 + j*(-125) -16 + j*(-107) --10 + j*(-80) -27 + j*(-62) -37 + j*(-163) --149 + j*(-210) --275 + j*(22) --55 + j*(215) -170 + j*(40) -67 + j*(-195) --156 + j*(-200) --302 + j*(-58) --322 + j*(194) --71 + j*(402) -238 + j*(243) -168 + j*(-30) -2 + j*(40) -160 + j*(127) -233 + j*(-122) --49 + j*(-212) --134 + j*(47) -83 + j*(91) -67 + j*(-90) --89 + j*(-14) -31 + j*(129) -164 + j*(5) -69 + j*(-88) -65 + j*(-21) -152 + j*(-116) -13 + j*(-266) --174 + j*(-155) --125 + j*(-5) --59 + j*(-30) --108 + j*(-16) --58 + j*(72) -64 + j*(13) -32 + j*(-130) --104 + j*(-166) --220 + j*(-107) --293 + j*(26) --243 + j*(204) --74 + j*(280) -58 + j*(226) -134 + j*(148) -170 + j*(0) -11 + j*(-155) --245 + j*(-18) --176 + j*(311) -156 + j*(342) -262 + j*(116) -193 + j*(44) -262 + j*(13) -243 + j*(-202) --38 + j*(-252) --123 + j*(7) -99 + j*(65) -106 + j*(-138) --89 + j*(-102) --18 + j*(80) -149 + j*(-20) -48 + j*(-172) --64 + j*(-101) --25 + j*(-78) --115 + j*(-115) --180 + j*(65) -54 + j*(159) -156 + j*(-105) --135 + j*(-199) --218 + j*(101) -74 + j*(163) -98 + j*(-118) --190 + j*(-112) --197 + j*(192) -77 + j*(262) -214 + j*(89) -193 + j*(-59) -103 + j*(-161) --49 + j*(-148) --66 + j*(-4) -71 + j*(-13) -25 + j*(-175) --161 + j*(-125) --121 + j*(42) --14 + j*(-19) --148 + j*(-78) --216 + j*(136) -24 + j*(252) -177 + j*(52) -52 + j*(-83) --16 + j*(-22) -18 + j*(-40) --71 + j*(-76) --123 + j*(59) -44 + j*(127) -129 + j*(-62) --69 + j*(-186) --238 + j*(-18) --142 + j*(175) -23 + j*(151) -30 + j*(36) --66 + j*(38) --69 + j*(160) -87 + j*(211) -202 + j*(57) -70 + j*(-105) --125 + j*(11) --36 + j*(258) -256 + j*(247) -360 + j*(-23) -197 + j*(-205) -21 + j*(-161) --1 + j*(-37) -98 + j*(21) -211 + j*(-69) -178 + j*(-262) --44 + j*(-342) --214 + j*(-179) --140 + j*(-1) --15 + j*(-43) --81 + j*(-137) --187 + j*(-45) --99 + j*(74) -3 + j*(-13) --115 + j*(-96) --217 + j*(71) --26 + j*(221) -170 + j*(42) -25 + j*(-180) --197 + j*(-85) --160 + j*(109) --40 + j*(117) --26 + j*(94) -37 + j*(112) -98 + j*(-15) --82 + j*(-117) --240 + j*(110) --1 + j*(338) -275 + j*(139) -134 + j*(-122) --68 + j*(-4) -70 + j*(153) -226 + j*(2) -109 + j*(-165) --36 + j*(-118) --52 + j*(-29) --26 + j*(29) -66 + j*(57) -154 + j*(-70) -16 + j*(-228) --197 + j*(-118) --143 + j*(106) -51 + j*(93) -57 + j*(-57) --50 + j*(-73) --76 + j*(-7) --59 + j*(15) --70 + j*(35) --49 + j*(91) -35 + j*(104) -85 + j*(16) --7 + j*(-52) --91 + j*(71) -88 + j*(199) -296 + j*(-21) -82 + j*(-317) --267 + j*(-149) --164 + j*(194) -119 + j*(135) -63 + j*(-51) --30 + j*(45) -124 + j*(87) -167 + j*(-99) -21 + j*(-161) --25 + j*(-115) --90 + j*(-147) --234 + j*(-19) --102 + j*(209) -148 + j*(103) -43 + j*(-117) --130 + j*(21) -50 + j*(173) -204 + j*(-17) -57 + j*(-162) --29 + j*(-80) -25 + j*(-93) --62 + j*(-186) --221 + j*(-114) --245 + j*(52) --156 + j*(170) --15 + j*(185) -43 + j*(71) --71 + j*(38) --92 + j*(211) -127 + j*(278) -246 + j*(107) -192 + j*(24) -250 + j*(10) -283 + j*(-182) -70 + j*(-308) --66 + j*(-182) --13 + j*(-148) --116 + j*(-216) --252 + j*(-37) --62 + j*(138) -112 + j*(-57) --100 + j*(-228) --281 + j*(-28) --136 + j*(136) --43 + j*(33) --157 + j*(18) --152 + j*(171) --5 + j*(194) -13 + j*(103) --39 + j*(147) -66 + j*(231) -209 + j*(132) -166 + j*(-13) -83 + j*(9) -156 + j*(37) -194 + j*(-104) -38 + j*(-194) --76 + j*(-85) --24 + j*(-7) --20 + j*(-30) --55 + j*(39) -60 + j*(112) -179 + j*(-3) -111 + j*(-139) -19 + j*(-146) --33 + j*(-150) --140 + j*(-105) --130 + j*(66) -59 + j*(73) -48 + j*(-127) --174 + j*(-85) --111 + j*(163) -148 + j*(89) -57 + j*(-166) --199 + j*(-43) --42 + j*(231) -268 + j*(74) -163 + j*(-266) --154 + j*(-243) --196 + j*(-18) --93 + j*(25) --111 + j*(3) --117 + j*(85) --22 + j*(112) --1 + j*(53) --16 + j*(87) -100 + j*(93) -138 + j*(-99) --95 + j*(-192) --242 + j*(38) --50 + j*(209) -101 + j*(59) --30 + j*(-54) --123 + j*(69) --38 + j*(158) -14 + j*(148) -58 + j*(201) -231 + j*(191) -325 + j*(-23) -185 + j*(-195) -45 + j*(-173) -7 + j*(-163) --122 + j*(-169) --247 + j*(42) --34 + j*(297) -319 + j*(155) -280 + j*(-231) --61 + j*(-281) --139 + j*(-29) -41 + j*(18) -45 + j*(-135) --93 + j*(-124) --81 + j*(-28) --38 + j*(-63) --110 + j*(-82) --141 + j*(-9) --116 + j*(16) --156 + j*(40) --140 + j*(154) --14 + j*(196) -58 + j*(135) -78 + j*(104) -120 + j*(43) -58 + j*(-41) --25 + j*(34) -86 + j*(121) -199 + j*(-7) -112 + j*(-131) -44 + j*(-110) -33 + j*(-158) --121 + j*(-179) --187 + j*(18) -6 + j*(85) -30 + j*(-119) --228 + j*(-107) --243 + j*(201) -52 + j*(291) -208 + j*(91) -141 + j*(-68) -42 + j*(-112) --58 + j*(-93) --100 + j*(0) --47 + j*(62) --12 + j*(48) --19 + j*(68) -38 + j*(112) -134 + j*(77) -177 + j*(-38) -98 + j*(-164) --70 + j*(-146) --91 + j*(26) -86 + j*(44) -100 + j*(-155) --105 + j*(-187) --153 + j*(-31) --88 + j*(-11) --148 + j*(4) --104 + j*(144) -77 + j*(93) -1 + j*(-83) --163 + j*(29) --42 + j*(179) -59 + j*(88) -6 + j*(103) -173 + j*(161) -295 + j*(-125) --27 + j*(-320) --240 + j*(-48) --51 + j*(89) --64 + j*(-56) --240 + j*(108) --5 + j*(366) -302 + j*(178) -229 + j*(-81) -117 + j*(-100) -71 + j*(-159) --107 + j*(-115) --44 + j*(127) -263 + j*(4) -87 + j*(-390) --380 + j*(-223) --282 + j*(247) -94 + j*(209) -51 + j*(-11) --28 + j*(110) -204 + j*(122) -228 + j*(-181) --72 + j*(-256) --180 + j*(-27) --45 + j*(78) -35 + j*(24) -47 + j*(-24) -25 + j*(-95) --91 + j*(-107) --139 + j*(34) -9 + j*(113) -112 + j*(-32) --18 + j*(-163) --177 + j*(-57) --107 + j*(117) -78 + j*(79) -77 + j*(-130) --155 + j*(-194) --317 + j*(21) --192 + j*(254) -25 + j*(245) -75 + j*(124) -42 + j*(116) -113 + j*(134) -172 + j*(31) -92 + j*(-42) -69 + j*(21) -177 + j*(-21) -120 + j*(-209) --117 + j*(-191) --136 + j*(36) -48 + j*(42) -5 + j*(-117) --158 + j*(-22) --24 + j*(159) -185 + j*(-5) -11 + j*(-269) --325 + j*(-140) --317 + j*(235) --3 + j*(373) -219 + j*(210) -212 + j*(26) -151 + j*(-43) -105 + j*(-101) --23 + j*(-127) --122 + j*(30) -38 + j*(196) -255 + j*(71) -202 + j*(-150) -57 + j*(-155) -62 + j*(-115) -39 + j*(-182) --60 + j*(-165) --47 + j*(-109) --64 + j*(-175) --222 + j*(-132) --204 + j*(82) -8 + j*(83) -1 + j*(-105) --180 + j*(-86) --175 + j*(76) --64 + j*(91) --54 + j*(36) --90 + j*(42) --106 + j*(91) --60 + j*(166) -63 + j*(159) -100 + j*(40) -21 + j*(1) -16 + j*(33) -9 + j*(-4) --69 + j*(47) -34 + j*(168) -188 + j*(21) -13 + j*(-138) --121 + j*(76) -148 + j*(175) -223 + j*(-135) --93 + j*(-193) --115 + j*(88) -107 + j*(58) -14 + j*(-93) --54 + j*(69) -182 + j*(64) -148 + j*(-245) --184 + j*(-229) --210 + j*(34) --93 + j*(59) --148 + j*(106) --1 + j*(295) -303 + j*(149) -215 + j*(-178) --49 + j*(-133) -8 + j*(54) -163 + j*(-39) -81 + j*(-192) --59 + j*(-179) --118 + j*(-100) --118 + j*(-17) -254 + j*(-10) -76 + j*(-153) --18 + j*(-66) -47 + j*(-84) --64 + j*(-223) --321 + j*(-112) --313 + j*(218) --22 + j*(334) -153 + j*(167) -99 + j*(27) -22 + j*(46) -63 + j*(111) -179 + j*(66) -187 + j*(-107) -5 + j*(-195) --132 + j*(-49) --30 + j*(89) -84 + j*(16) -40 + j*(-76) --21 + j*(-76) --74 + j*(-69) --136 + j*(7) --70 + j*(119) -35 + j*(62) --59 + j*(2) --95 + j*(186) -182 + j*(254) -316 + j*(-60) -25 + j*(-243) --161 + j*(4) -49 + j*(172) -197 + j*(2) -77 + j*(-119) -9 + j*(-37) -89 + j*(-21) -93 + j*(-126) --8 + j*(-157) --58 + j*(-104) --63 + j*(-88) --116 + j*(-65) --126 + j*(49) -14 + j*(114) -130 + j*(-16) -37 + j*(-168) --119 + j*(-136) --157 + j*(-20) --112 + j*(59) --28 + j*(83) -31 + j*(3) --67 + j*(-66) --148 + j*(71) -28 + j*(179) -158 + j*(-12) --24 + j*(-141) --117 + j*(20) -31 + j*(50) --12 + j*(-100) --171 + j*(-1) --35 + j*(156) -93 + j*(-4) --98 + j*(-98) --174 + j*(116) -35 + j*(187) -96 + j*(18) --18 + j*(-19) --39 + j*(40) --48 + j*(51) --66 + j*(136) -66 + j*(216) -198 + j*(115) -176 + j*(-5) -137 + j*(-35) -116 + j*(-69) -88 + j*(-67) -142 + j*(-100) -82 + j*(-290) --246 + j*(-293) --373 + j*(76) --87 + j*(290) -103 + j*(158) -93 + j*(109) -226 + j*(86) -247 + j*(-175) --47 + j*(-240) --90 + j*(38) -199 + j*(8) -119 + j*(-333) --255 + j*(-281) --264 + j*(42) --71 + j*(64) --111 + j*(-4) --120 + j*(132) -69 + j*(139) -86 + j*(-52) --85 + j*(-52) --62 + j*(112) -108 + j*(74) -86 + j*(-99) --75 + j*(-96) --78 + j*(42) -48 + j*(34) -23 + j*(-105) --137 + j*(-85) --141 + j*(82) --5 + j*(100) --5 + j*(16) --49 + j*(69) -77 + j*(88) -92 + j*(-113) --182 + j*(-150) --276 + j*(168) -23 + j*(330) -208 + j*(107) -64 + j*(-23) -19 + j*(103) -180 + j*(107) -218 + j*(-68) -98 + j*(-160) -4 + j*(-145) --81 + j*(-99) --108 + j*(50) -88 + j*(154) -288 + j*(-64) -101 + j*(-367) --256 + j*(-279) --276 + j*(37) --73 + j*(96) --68 + j*(-6) --135 + j*(78) -10 + j*(161) -100 + j*(9) --40 + j*(-54) --47 + j*(86) -120 + j*(31) -17 + j*(-182) --261 + j*(-69) --202 + j*(252) -85 + j*(308) -233 + j*(171) -313 + j*(39) -313 + j*(-197) -59 + j*(-351) --148 + j*(-180) --38 + j*(-49) --19 + j*(-190) --227 + j*(-170) --216 + j*(52) --65 + j*(30) --182 + j*(-33) --238 + j*(215) -83 + j*(325) -241 + j*(23) -12 + j*(-115) --50 + j*(55) -91 + j*(32) --6 + j*(-98) --127 + j*(57) -63 + j*(179) -190 + j*(-16) -9 + j*(-130) --76 + j*(42) -98 + j*(110) -183 + j*(-63) -37 + j*(-179) --99 + j*(-83) --46 + j*(57) -93 + j*(35) -106 + j*(-106) --13 + j*(-163) --94 + j*(-113) --136 + j*(-58) --165 + j*(54) --32 + j*(177) -162 + j*(64) -71 + j*(-158) --149 + j*(-78) --66 + j*(133) -136 + j*(49) -71 + j*(-140) --71 + j*(-119) --86 + j*(-66) --157 + j*(-65) --223 + j*(89) --69 + j*(231) -83 + j*(136) -29 + j*(52) -28 + j*(136) -187 + j*(112) -212 + j*(-88) -43 + j*(-182) --72 + j*(-89) --44 + j*(-6) --4 + j*(-25) --49 + j*(-52) --112 + j*(14) --66 + j*(126) -68 + j*(138) -146 + j*(37) -121 + j*(-84) --1 + j*(-151) --154 + j*(-57) --107 + j*(158) -141 + j*(159) -177 + j*(-77) --22 + j*(-104) -13 + j*(62) -192 + j*(-56) -21 + j*(-290) --262 + j*(-132) --165 + j*(151) -51 + j*(113) -37 + j*(-5) -8 + j*(18) -48 + j*(-3) -5 + j*(-36) -13 + j*(17) -94 + j*(-44) --9 + j*(-171) --174 + j*(-58) --77 + j*(116) -74 + j*(33) --8 + j*(-82) --98 + j*(-1) --31 + j*(72) -20 + j*(40) -21 + j*(30) -64 + j*(12) -51 + j*(-73) --57 + j*(-83) --91 + j*(29) -23 + j*(86) -109 + j*(-33) --9 + j*(-166) --200 + j*(-70) --149 + j*(159) -74 + j*(156) -83 + j*(-26) --53 + j*(5) -53 + j*(127) -204 + j*(-57) --27 + j*(-267) --308 + j*(-41) --140 + j*(284) -176 + j*(204) -175 + j*(-47) -9 + j*(-84) --35 + j*(17) -29 + j*(69) -103 + j*(41) -121 + j*(-43) -66 + j*(-91) -41 + j*(-82) -42 + j*(-129) --63 + j*(-180) --174 + j*(-76) --117 + j*(28) --91 + j*(-16) --206 + j*(47) --128 + j*(283) -193 + j*(266) -258 + j*(-54) --4 + j*(-167) --118 + j*(26) -6 + j*(127) -75 + j*(84) -110 + j*(81) -209 + j*(21) -190 + j*(-151) -24 + j*(-204) --61 + j*(-107) --36 + j*(-48) --18 + j*(-37) -16 + j*(-31) -38 + j*(-91) --39 + j*(-144) --117 + j*(-92) --119 + j*(-35) --132 + j*(4) --97 + j*(93) -38 + j*(78) -30 + j*(-82) --153 + j*(-69) --146 + j*(127) -32 + j*(129) -7 + j*(-2) --95 + j*(94) -70 + j*(228) -284 + j*(57) -206 + j*(-215) --42 + j*(-288) --244 + j*(-165) --298 + j*(76) --113 + j*(277) -151 + j*(194) -148 + j*(-52) --52 + j*(-83) --88 + j*(83) -62 + j*(131) -139 + j*(-5) -27 + j*(-122) --129 + j*(-40) --79 + j*(156) -146 + j*(141) -173 + j*(-105) --63 + j*(-176) --173 + j*(10) --83 + j*(117) --54 + j*(129) --1 + j*(231) -201 + j*(235) -281 + j*(44) -183 + j*(-27) -228 + j*(15) -324 + j*(-140) -168 + j*(-317) -9 + j*(-233) -95 + j*(-191) -66 + j*(-401) --260 + j*(-458) --479 + j*(-179) --404 + j*(89) --280 + j*(207) --132 + j*(310) -119 + j*(280) -226 + j*(27) -56 + j*(-135) --73 + j*(-43) --4 + j*(4) --29 + j*(-98) --199 + j*(-45) --175 + j*(177) -49 + j*(215) -124 + j*(40) -13 + j*(-30) --31 + j*(44) -29 + j*(79) -76 + j*(40) -74 + j*(-19) -21 + j*(-52) --27 + j*(-10) -15 + j*(32) -49 + j*(-23) --18 + j*(-55) --40 + j*(7) -6 + j*(-1) --54 + j*(-41) --117 + j*(76) -35 + j*(183) -183 + j*(40) -79 + j*(-119) --56 + j*(-58) --21 + j*(38) -50 + j*(14) -41 + j*(-52) --28 + j*(-80) --106 + j*(-21) --86 + j*(90) -12 + j*(117) -50 + j*(80) -88 + j*(90) -192 + j*(17) -143 + j*(-177) --98 + j*(-196) --193 + j*(33) --33 + j*(197) -168 + j*(150) -250 + j*(-32) -138 + j*(-204) --47 + j*(-156) -9 + j*(-8) -151 + j*(-147) --70 + j*(-351) --349 + j*(-124) --182 + j*(161) -18 + j*(32) --139 + j*(-53) --158 + j*(165) -86 + j*(170) -72 + j*(-34) --64 + j*(42) -110 + j*(148) -255 + j*(-100) -24 + j*(-322) --247 + j*(-218) --320 + j*(-6) --276 + j*(197) --72 + j*(337) -158 + j*(236) -158 + j*(52) -81 + j*(40) -131 + j*(45) -138 + j*(-57) -52 + j*(-81) -54 + j*(-54) -50 + j*(-128) --89 + j*(-151) --167 + j*(-4) --62 + j*(112) -55 + j*(58) -35 + j*(-46) --64 + j*(-44) --78 + j*(58) -19 + j*(84) -42 + j*(1) --32 + j*(1) --6 + j*(69) -49 + j*(25) --19 + j*(8) -16 + j*(121) -192 + j*(54) -127 + j*(-167) --102 + j*(-120) --66 + j*(75) -74 + j*(30) -8 + j*(-43) -1 + j*(54) -139 + j*(17) -100 + j*(-153) --66 + j*(-147) --98 + j*(-37) --68 + j*(16) --15 + j*(61) -84 + j*(8) -28 + j*(-129) --129 + j*(-59) --46 + j*(98) -94 + j*(-8) --35 + j*(-121) --118 + j*(24) -33 + j*(71) -48 + j*(-83) --100 + j*(-80) --98 + j*(34) --57 + j*(25) --103 + j*(65) --9 + j*(173) -144 + j*(78) -78 + j*(-78) --37 + j*(-34) -0 + j*(20) --2 + j*(-29) --74 + j*(18) --7 + j*(117) -107 + j*(59) -73 + j*(-45) -1 + j*(-21) -39 + j*(28) -100 + j*(-18) -72 + j*(-114) --42 + j*(-136) --112 + j*(-36) --37 + j*(57) -66 + j*(1) -25 + j*(-115) --92 + j*(-118) --153 + j*(-37) --148 + j*(53) --81 + j*(117) -6 + j*(95) --6 + j*(8) --119 + j*(34) --115 + j*(215) -116 + j*(305) -327 + j*(112) -244 + j*(-161) -6 + j*(-180) --41 + j*(-23) -54 + j*(-16) -8 + j*(-91) --58 + j*(-13) -45 + j*(30) -57 + j*(-109) --122 + j*(-103) --122 + j*(91) -43 + j*(95) -12 + j*(-2) --17 + j*(115) -218 + j*(117) -244 + j*(-215) --125 + j*(-296) --244 + j*(61) -66 + j*(191) -192 + j*(-68) --1 + j*(-185) --94 + j*(-71) --57 + j*(-23) --71 + j*(-9) --31 + j*(62) -89 + j*(21) -81 + j*(-135) --74 + j*(-192) --194 + j*(-103) --212 + j*(11) --192 + j*(98) --140 + j*(192) --10 + j*(256) -150 + j*(190) -185 + j*(32) -104 + j*(-49) -66 + j*(-52) -30 + j*(-100) --106 + j*(-81) --137 + j*(122) -101 + j*(227) -299 + j*(7) -167 + j*(-274) --129 + j*(-287) --291 + j*(-65) --211 + j*(175) -12 + j*(243) -161 + j*(110) -141 + j*(-30) -76 + j*(-87) -0 + j*(-122) --113 + j*(-66) --84 + j*(83) -66 + j*(64) -27 + j*(-73) --97 + j*(8) -37 + j*(119) -139 + j*(-71) --106 + j*(-170) --213 + j*(111) -76 + j*(228) -186 + j*(-36) --42 + j*(-121) --96 + j*(71) -56 + j*(107) -79 + j*(19) -66 + j*(16) -92 + j*(-28) -16 + j*(-65) -13 + j*(39) -163 + j*(-16) -59 + j*(-238) --233 + j*(-105) --89 + j*(243) -305 + j*(105) -205 + j*(-313) --194 + j*(-281) --226 + j*(44) --6 + j*(103) -47 + j*(-24) --11 + j*(-57) --18 + j*(-42) --17 + j*(-63) --56 + j*(-95) --145 + j*(-77) --183 + j*(60) --34 + j*(148) -72 + j*(-6) --105 + j*(-104) --199 + j*(105) -18 + j*(197) -80 + j*(-12) --137 + j*(-14) --93 + j*(242) -199 + j*(199) -197 + j*(-86) --37 + j*(-129) --113 + j*(28) --45 + j*(131) -69 + j*(158) -174 + j*(63) -106 + j*(-69) --1 + j*(5) -128 + j*(93) -242 + j*(-97) -55 + j*(-266) --127 + j*(-158) --124 + j*(-42) --134 + j*(18) --73 + j*(149) -127 + j*(127) -139 + j*(-74) --11 + j*(-93) --3 + j*(-16) -10 + j*(-75) --98 + j*(-40) --27 + j*(89) -96 + j*(-18) --55 + j*(-123) --149 + j*(67) -45 + j*(164) -137 + j*(19) -86 + j*(-37) -105 + j*(-89) --21 + j*(-194) --181 + j*(-13) -57 + j*(156) -234 + j*(-164) --155 + j*(-371) --403 + j*(13) --110 + j*(256) -44 + j*(81) --47 + j*(73) -78 + j*(133) -125 + j*(-73) --116 + j*(-96) --110 + j*(153) -117 + j*(132) -90 + j*(-28) -31 + j*(24) -131 + j*(-12) -42 + j*(-148) --80 + j*(-46) -35 + j*(4) --16 + j*(-148) --221 + j*(-10) --23 + j*(239) -247 + j*(18) -35 + j*(-240) --163 + j*(-67) --24 + j*(13) --80 + j*(-137) --294 + j*(2) --169 + j*(264) -54 + j*(219) -59 + j*(127) -112 + j*(136) -174 + j*(1) -14 + j*(-87) --62 + j*(85) -124 + j*(143) -178 + j*(-30) -48 + j*(-71) -57 + j*(12) -126 + j*(-59) -17 + j*(-147) --106 + j*(-33) --15 + j*(132) -194 + j*(95) -240 + j*(-132) -50 + j*(-254) --88 + j*(-122) -29 + j*(-28) -99 + j*(-187) --95 + j*(-300) --267 + j*(-153) --228 + j*(6) --156 + j*(41) --122 + j*(45) --116 + j*(18) --200 + j*(42) --203 + j*(222) -21 + j*(305) -157 + j*(124) -35 + j*(19) -1 + j*(133) -151 + j*(129) -161 + j*(-35) -23 + j*(-59) -8 + j*(44) -104 + j*(49) -136 + j*(-48) -61 + j*(-132) --68 + j*(-103) --92 + j*(47) -61 + j*(115) -170 + j*(-22) -78 + j*(-151) --27 + j*(-126) --45 + j*(-93) --95 + j*(-88) --137 + j*(16) --23 + j*(93) -66 + j*(-27) --81 + j*(-129) --231 + j*(39) --94 + j*(255) -139 + j*(207) -181 + j*(49) -168 + j*(5) -231 + j*(-105) -105 + j*(-317) --192 + j*(-274) --228 + j*(-6) --57 + j*(23) --119 + j*(-89) --247 + j*(63) --71 + j*(233) -102 + j*(82) --31 + j*(-52) --136 + j*(80) --28 + j*(187) -78 + j*(155) -148 + j*(89) -148 + j*(-62) --52 + j*(-130) --185 + j*(100) -29 + j*(301) -266 + j*(177) -280 + j*(9) -292 + j*(-85) -248 + j*(-291) --40 + j*(-396) --267 + j*(-170) --177 + j*(76) --1 + j*(95) -80 + j*(14) -73 + j*(-90) --40 + j*(-127) --90 + j*(-12) -42 + j*(26) -76 + j*(-139) --103 + j*(-202) --210 + j*(-71) --193 + j*(36) --164 + j*(129) --33 + j*(216) -126 + j*(130) -117 + j*(-5) -87 + j*(-40) -73 + j*(-141) --123 + j*(-200) --259 + j*(21) --77 + j*(185) -45 + j*(64) --32 + j*(29) -25 + j*(78) -39 + j*(-61) --186 + j*(-27) --119 + j*(289) -267 + j*(222) -222 + j*(-170) --119 + j*(-139) --74 + j*(124) -100 + j*(53) -10 + j*(-36) -6 + j*(71) -132 + j*(1) -15 + j*(-147) --148 + j*(-28) --78 + j*(127) -16 + j*(134) -77 + j*(156) -214 + j*(111) -246 + j*(-65) -144 + j*(-152) -95 + j*(-178) --23 + j*(-248) --216 + j*(-129) --152 + j*(127) -95 + j*(122) -135 + j*(-69) -17 + j*(-143) --75 + j*(-119) --157 + j*(-23) --88 + j*(161) -169 + j*(155) -256 + j*(-113) -64 + j*(-281) --111 + j*(-223) --162 + j*(-124) --154 + j*(-61) --140 + j*(-59) --221 + j*(-59) --289 + j*(105) --129 + j*(254) -20 + j*(151) --62 + j*(88) --39 + j*(217) -130 + j*(165) -64 + j*(25) --11 + j*(163) -244 + j*(229) -377 + j*(-88) -127 + j*(-293) --59 + j*(-196) --95 + j*(-131) --170 + j*(-47) --93 + j*(93) -25 + j*(1) --151 + j*(-75) --233 + j*(204) -87 + j*(337) -245 + j*(80) -103 + j*(-13) -141 + j*(52) -190 + j*(-105) --16 + j*(-148) --7 + j*(62) -220 + j*(-32) -76 + j*(-298) --201 + j*(-168) --111 + j*(37) --32 + j*(-49) --175 + j*(-12) --93 + j*(198) -136 + j*(139) -124 + j*(-34) -64 + j*(-37) -95 + j*(-90) --20 + j*(-189) --171 + j*(-74) --114 + j*(78) --15 + j*(88) -44 + j*(83) -137 + j*(1) -63 + j*(-166) --142 + j*(-103) --74 + j*(103) -123 + j*(6) --6 + j*(-195) --221 + j*(-57) --105 + j*(156) -79 + j*(72) -19 + j*(-69) --80 + j*(-19) --35 + j*(44) -6 + j*(-13) --87 + j*(-61) --192 + j*(52) --112 + j*(243) -129 + j*(253) -236 + j*(35) -91 + j*(-115) --44 + j*(-27) -28 + j*(87) -164 + j*(11) -116 + j*(-182) --134 + j*(-210) --259 + j*(60) --3 + j*(262) -236 + j*(19) --20 + j*(-234) --297 + j*(56) -16 + j*(375) -365 + j*(76) -103 + j*(-260) --189 + j*(-14) -66 + j*(234) -293 + j*(-16) -82 + j*(-218) --50 + j*(-61) -93 + j*(-19) -71 + j*(-188) --122 + j*(-160) --113 + j*(14) -15 + j*(16) -16 + j*(-71) --30 + j*(-85) --64 + j*(-98) --147 + j*(-69) --159 + j*(56) --42 + j*(100) --10 + j*(16) --82 + j*(27) --41 + j*(112) -51 + j*(78) -37 + j*(17) -42 + j*(22) -63 + j*(-54) --76 + j*(-110) --168 + j*(71) -37 + j*(191) -164 + j*(-25) --70 + j*(-147) --192 + j*(117) -93 + j*(267) -295 + j*(3) -106 + j*(-244) --141 + j*(-170) --177 + j*(23) --72 + j*(125) -36 + j*(92) -20 + j*(3) --78 + j*(56) -6 + j*(214) -238 + j*(158) -263 + j*(-87) -98 + j*(-170) -50 + j*(-124) -33 + j*(-194) --156 + j*(-219) --292 + j*(2) --151 + j*(224) -63 + j*(221) -158 + j*(116) -206 + j*(26) -218 + j*(-108) -115 + j*(-239) --49 + j*(-247) --142 + j*(-158) --155 + j*(-78) --161 + j*(-39) --186 + j*(23) --165 + j*(136) --27 + j*(216) -141 + j*(137) -158 + j*(-59) --6 + j*(-153) --134 + j*(-54) --101 + j*(64) --33 + j*(65) --40 + j*(52) --20 + j*(94) -48 + j*(69) -9 + j*(-5) --81 + j*(67) -15 + j*(206) -206 + j*(132) -190 + j*(-62) -49 + j*(-74) -56 + j*(9) -117 + j*(-29) -82 + j*(-70) -109 + j*(-51) -172 + j*(-185) --23 + j*(-366) --314 + j*(-216) --270 + j*(88) --56 + j*(100) --87 + j*(-6) --153 + j*(111) -8 + j*(194) -96 + j*(55) -1 + j*(24) -62 + j*(109) -177 + j*(-33) --5 + j*(-171) --139 + j*(36) -106 + j*(148) -213 + j*(-146) --103 + j*(-272) --249 + j*(13) --27 + j*(144) -54 + j*(-21) --76 + j*(-47) --66 + j*(56) --2 + j*(21) --71 + j*(-16) --115 + j*(82) --36 + j*(163) -71 + j*(156) -151 + j*(59) -82 + j*(-78) --102 + j*(-16) --26 + j*(233) -302 + j*(174) -305 + j*(-202) --49 + j*(-272) --136 + j*(16) -96 + j*(71) -115 + j*(-139) --86 + j*(-150) --104 + j*(27) -35 + j*(42) -37 + j*(-70) --75 + j*(-55) --54 + j*(78) -115 + j*(75) -156 + j*(-124) --50 + j*(-234) --222 + j*(-63) --117 + j*(148) -104 + j*(119) -156 + j*(-89) --21 + j*(-228) --242 + j*(-114) --213 + j*(168) -88 + j*(238) -245 + j*(-41) -39 + j*(-260) --187 + j*(-162) --201 + j*(-8) --169 + j*(58) --125 + j*(132) --17 + j*(139) -13 + j*(47) --62 + j*(23) --98 + j*(83) --105 + j*(158) --29 + j*(301) -257 + j*(325) -447 + j*(-21) -163 + j*(-355) --231 + j*(-200) --208 + j*(164) -71 + j*(241) -204 + j*(75) -139 + j*(-61) -31 + j*(-52) -40 + j*(45) -155 + j*(26) -152 + j*(-117) -21 + j*(-144) --9 + j*(-71) --6 + j*(-77) --78 + j*(-23) -15 + j*(126) -240 + j*(30) -194 + j*(-238) --36 + j*(-265) --91 + j*(-148) --93 + j*(-141) --160 + j*(-93) --126 + j*(-5) --101 + j*(-31) --165 + j*(47) -11 + j*(185) -234 + j*(-70) --75 + j*(-383) --466 + j*(-63) --175 + j*(363) -235 + j*(107) -8 + j*(-264) --322 + j*(-86) --228 + j*(157) --153 + j*(132) --203 + j*(249) -27 + j*(402) -252 + j*(170) -44 + j*(-29) --88 + j*(217) -237 + j*(332) -385 + j*(-18) -80 + j*(-173) --9 + j*(91) -257 + j*(102) -236 + j*(-187) --31 + j*(-152) -47 + j*(62) -228 + j*(-81) -47 + j*(-245) --74 + j*(-57) -150 + j*(-21) -128 + j*(-331) --258 + j*(-325) --310 + j*(66) -21 + j*(145) -88 + j*(-127) --151 + j*(-194) --251 + j*(-11) --170 + j*(112) --82 + j*(139) --10 + j*(121) -11 + j*(64) --31 + j*(62) --7 + j*(124) -93 + j*(112) -126 + j*(6) -42 + j*(-59) --32 + j*(-1) -19 + j*(89) -142 + j*(49) -147 + j*(-100) -18 + j*(-167) --82 + j*(-115) --127 + j*(-44) --140 + j*(68) --24 + j*(180) -145 + j*(122) -173 + j*(-27) -119 + j*(-105) -63 + j*(-177) --92 + j*(-196) --182 + j*(-29) --30 + j*(71) -28 + j*(-77) --143 + j*(-95) --134 + j*(83) -23 + j*(35) --97 + j*(-97) --238 + j*(85) --45 + j*(245) -86 + j*(83) --67 + j*(37) --52 + j*(232) -197 + j*(238) -286 + j*(17) -182 + j*(-133) -50 + j*(-175) --86 + j*(-118) --106 + j*(40) -28 + j*(112) -120 + j*(37) -129 + j*(-43) -112 + j*(-134) --9 + j*(-215) --161 + j*(-141) --180 + j*(-4) --148 + j*(71) --98 + j*(168) -72 + j*(206) -185 + j*(52) -101 + j*(-66) -54 + j*(-49) -39 + j*(-105) --122 + j*(-78) --98 + j*(180) -253 + j*(181) -315 + j*(-221) --54 + j*(-357) --211 + j*(-95) --59 + j*(-6) --71 + j*(-112) --192 + j*(-51) --170 + j*(62) --144 + j*(98) --115 + j*(206) -75 + j*(272) -245 + j*(103) -181 + j*(-96) -48 + j*(-134) --18 + j*(-117) --96 + j*(-97) --159 + j*(6) --98 + j*(127) -32 + j*(123) -52 + j*(21) --45 + j*(25) --13 + j*(169) -207 + j*(154) -260 + j*(-107) -22 + j*(-226) --115 + j*(-51) -6 + j*(68) -105 + j*(-15) -75 + j*(-115) --16 + j*(-165) --156 + j*(-121) --179 + j*(66) -6 + j*(146) -101 + j*(-12) --24 + j*(-93) --80 + j*(9) -5 + j*(45) -41 + j*(-20) -14 + j*(-86) --86 + j*(-133) --232 + j*(-35) --189 + j*(170) --17 + j*(186) --16 + j*(129) -40 + j*(239) -302 + j*(142) -232 + j*(-231) --175 + j*(-193) --135 + j*(192) -209 + j*(107) -62 + j*(-202) --229 + j*(6) -7 + j*(298) -291 + j*(92) -164 + j*(-139) -38 + j*(-79) -85 + j*(-69) -36 + j*(-137) --35 + j*(-97) --25 + j*(-71) --74 + j*(-62) --58 + j*(52) -118 + j*(33) -110 + j*(-211) --180 + j*(-263) --324 + j*(4) --163 + j*(216) -29 + j*(197) -110 + j*(105) -139 + j*(16) -114 + j*(-91) --4 + j*(-152) --122 + j*(-69) --78 + j*(74) -77 + j*(49) -64 + j*(-122) --115 + j*(-130) --146 + j*(22) --57 + j*(50) --74 + j*(18) --73 + j*(103) -56 + j*(91) -34 + j*(-60) --123 + j*(-23) --85 + j*(131) -33 + j*(101) --1 + j*(56) -42 + j*(124) -165 + j*(4) --16 + j*(-183) --284 + j*(33) --88 + j*(383) -301 + j*(281) -313 + j*(-45) -132 + j*(-107) -120 + j*(-59) -117 + j*(-146) --25 + j*(-164) --78 + j*(-21) -50 + j*(42) -121 + j*(-77) -15 + j*(-170) --95 + j*(-87) --25 + j*(22) -95 + j*(-66) --10 + j*(-231) --231 + j*(-156) --216 + j*(67) --58 + j*(75) --108 + j*(-13) --192 + j*(141) -27 + j*(284) -223 + j*(67) -39 + j*(-119) --94 + j*(57) -118 + j*(142) -185 + j*(-107) --74 + j*(-174) --129 + j*(74) -108 + j*(103) -122 + j*(-139) --121 + j*(-174) --208 + j*(45) --54 + j*(185) -111 + j*(119) -115 + j*(-40) --29 + j*(-81) --82 + j*(69) -83 + j*(148) -202 + j*(0) -124 + j*(-132) -52 + j*(-143) -6 + j*(-183) --119 + j*(-177) --158 + j*(-59) --113 + j*(-46) --206 + j*(-45) --221 + j*(156) -25 + j*(206) -66 + j*(-45) --206 + j*(-42) --188 + j*(257) -80 + j*(268) -86 + j*(122) -84 + j*(221) -343 + j*(170) -361 + j*(-197) -23 + j*(-321) --142 + j*(-121) --106 + j*(-8) --95 + j*(71) -39 + j*(152) -164 + j*(8) -15 + j*(-106) --46 + j*(63) -163 + j*(71) -142 + j*(-177) --112 + j*(-150) --83 + j*(72) -87 + j*(40) -53 + j*(-65) -25 + j*(-30) -74 + j*(-76) --7 + j*(-144) --54 + j*(-71) -3 + j*(-107) --147 + j*(-208) --345 + j*(4) --169 + j*(287) -110 + j*(211) -119 + j*(41) -110 + j*(19) -148 + j*(-118) --73 + j*(-258) --314 + j*(-25) --127 + j*(276) -167 + j*(165) -117 + j*(-55) --4 + j*(-7) -100 + j*(40) -143 + j*(-129) --39 + j*(-216) --150 + j*(-91) --101 + j*(-23) --125 + j*(-52) --200 + j*(29) --144 + j*(153) --40 + j*(166) -11 + j*(151) -85 + j*(118) -91 + j*(-7) --61 + j*(-33) --100 + j*(148) -93 + j*(218) -199 + j*(59) -112 + j*(-40) -63 + j*(-27) -28 + j*(-44) --54 + j*(28) -35 + j*(182) -256 + j*(131) -306 + j*(-94) -187 + j*(-243) -21 + j*(-292) --157 + j*(-193) --129 + j*(25) -83 + j*(13) -42 + j*(-211) --204 + j*(-165) --187 + j*(63) --46 + j*(74) --51 + j*(54) -43 + j*(98) -112 + j*(-78) --137 + j*(-135) --150 + j*(200) -284 + j*(163) -214 + j*(-362) --363 + j*(-276) --255 + j*(302) -293 + j*(146) -83 + j*(-375) --423 + j*(-147) --228 + j*(315) -134 + j*(178) -39 + j*(-47) --64 + j*(32) --3 + j*(41) --75 + j*(15) --71 + j*(171) -154 + j*(167) -175 + j*(-86) --69 + j*(-142) --149 + j*(66) -4 + j*(169) -115 + j*(78) -75 + j*(-21) --17 + j*(6) -23 + j*(125) -205 + j*(89) -219 + j*(-150) --26 + j*(-232) --145 + j*(-30) -8 + j*(84) -98 + j*(-42) --12 + j*(-126) --103 + j*(-57) --100 + j*(23) --71 + j*(86) -13 + j*(136) -128 + j*(88) -135 + j*(-43) -35 + j*(-82) -3 + j*(-13) -74 + j*(-7) -74 + j*(-98) --23 + j*(-114) --48 + j*(-29) -23 + j*(-13) -37 + j*(-82) --19 + j*(-112) --54 + j*(-98) --83 + j*(-95) --122 + j*(-71) --146 + j*(-47) --209 + j*(-8) --245 + j*(141) --91 + j*(293) -115 + j*(228) -140 + j*(78) -114 + j*(45) -153 + j*(-23) -64 + j*(-152) --105 + j*(-92) --72 + j*(58) -28 + j*(18) --56 + j*(-42) --107 + j*(85) -36 + j*(156) -123 + j*(37) -47 + j*(-40) -1 + j*(1) -21 + j*(21) -24 + j*(16) -45 + j*(29) -75 + j*(-9) -35 + j*(-57) --26 + j*(-11) -36 + j*(71) -168 + j*(4) -137 + j*(-182) --62 + j*(-215) --121 + j*(-64) --18 + j*(-70) --149 + j*(-198) --399 + j*(23) --184 + j*(413) -272 + j*(271) -185 + j*(-159) --191 + j*(-66) --62 + j*(284) -279 + j*(151) -170 + j*(-151) --56 + j*(-49) -82 + j*(110) -231 + j*(-54) -95 + j*(-223) --56 + j*(-167) --69 + j*(-92) --76 + j*(-71) --86 + j*(-23) --50 + j*(15) --8 + j*(13) -24 + j*(-11) -33 + j*(-72) --23 + j*(-122) --91 + j*(-112) --129 + j*(-92) --197 + j*(-66) --251 + j*(42) --188 + j*(165) --86 + j*(171) --81 + j*(136) --107 + j*(202) --6 + j*(310) -184 + j*(270) -243 + j*(90) -127 + j*(6) -94 + j*(98) -244 + j*(95) -273 + j*(-111) -74 + j*(-185) -13 + j*(-28) -173 + j*(-26) -148 + j*(-244) --113 + j*(-246) --159 + j*(-1) -40 + j*(54) -84 + j*(-108) --50 + j*(-150) --100 + j*(-60) --72 + j*(-21) --64 + j*(3) --14 + j*(33) -53 + j*(-29) -1 + j*(-134) --134 + j*(-132) --203 + j*(-6) --136 + j*(125) -16 + j*(111) -16 + j*(-48) --190 + j*(-33) --182 + j*(265) -206 + j*(314) -344 + j*(-115) --71 + j*(-330) --330 + j*(21) --79 + j*(273) -98 + j*(139) -45 + j*(103) -168 + j*(148) -262 + j*(-77) -10 + j*(-212) --114 + j*(34) -141 + j*(115) -204 + j*(-159) --43 + j*(-242) --132 + j*(-90) --115 + j*(-62) --211 + j*(23) --103 + j*(257) -225 + j*(193) -228 + j*(-151) --64 + j*(-209) --135 + j*(-3) --9 + j*(37) --16 + j*(-38) --65 + j*(2) --9 + j*(28) --17 + j*(-59) --173 + j*(-44) --218 + j*(197) -60 + j*(376) -379 + j*(150) -269 + j*(-243) --109 + j*(-243) --162 + j*(63) -66 + j*(113) -81 + j*(-51) --37 + j*(-18) -35 + j*(69) -100 + j*(-15) -40 + j*(-34) -110 + j*(-2) -157 + j*(-185) --97 + j*(-291) --256 + j*(-37) --44 + j*(111) -45 + j*(-82) --172 + j*(-120) --209 + j*(113) --8 + j*(174) -56 + j*(55) -19 + j*(27) -41 + j*(8) --13 + j*(-49) --89 + j*(33) -17 + j*(125) -119 + j*(4) -6 + j*(-98) --88 + j*(-2) --11 + j*(70) -25 + j*(18) --7 + j*(28) -58 + j*(59) -112 + j*(-53) --15 + j*(-151) --150 + j*(-53) --114 + j*(76) --48 + j*(92) --37 + j*(117) -45 + j*(177) -184 + j*(117) -210 + j*(-41) -116 + j*(-142) -1 + j*(-157) --101 + j*(-91) --107 + j*(54) -39 + j*(117) -136 + j*(-5) -49 + j*(-109) --28 + j*(-47) -35 + j*(-3) -76 + j*(-88) --8 + j*(-164) --124 + j*(-138) --185 + j*(-31) --127 + j*(90) --1 + j*(72) --35 + j*(-47) --191 + j*(39) --83 + j*(275) -226 + j*(209) -233 + j*(-107) --24 + j*(-156) --54 + j*(23) -73 + j*(-1) -4 + j*(-107) --91 + j*(-16) -14 + j*(49) -49 + j*(-82) --109 + j*(-105) --136 + j*(57) -6 + j*(71) --23 + j*(-66) --205 + j*(0) --170 + j*(249) -99 + j*(314) -259 + j*(119) -187 + j*(-54) -83 + j*(-64) -80 + j*(-42) -74 + j*(-91) --12 + j*(-110) --60 + j*(-23) -15 + j*(33) -69 + j*(-41) --9 + j*(-100) --71 + j*(-27) --15 + j*(25) -7 + j*(-19) --36 + j*(-1) -28 + j*(59) -127 + j*(-49) --5 + j*(-206) --233 + j*(-87) --170 + j*(190) -111 + j*(216) -231 + j*(-8) -119 + j*(-180) --25 + j*(-201) --130 + j*(-160) --214 + j*(-70) --226 + j*(76) --125 + j*(190) -18 + j*(189) -89 + j*(100) -66 + j*(33) -50 + j*(39) -93 + j*(19) -85 + j*(-71) --31 + j*(-95) --86 + j*(21) -30 + j*(101) -147 + j*(-8) -78 + j*(-171) --108 + j*(-180) --200 + j*(-35) --151 + j*(91) --68 + j*(125) --8 + j*(127) -56 + j*(101) -77 + j*(23) -11 + j*(-21) --42 + j*(26) --31 + j*(79) --11 + j*(127) -71 + j*(201) -253 + j*(163) -330 + j*(-45) -214 + j*(-199) -112 + j*(-206) -83 + j*(-250) --57 + j*(-326) --268 + j*(-235) --325 + j*(4) --178 + j*(190) -42 + j*(175) -108 + j*(-13) --57 + j*(-97) --132 + j*(84) -90 + j*(159) -181 + j*(-96) --88 + j*(-200) --194 + j*(58) -47 + j*(148) -115 + j*(-77) --90 + j*(-131) --146 + j*(30) --64 + j*(77) --58 + j*(88) -11 + j*(163) -161 + j*(100) -155 + j*(-69) -41 + j*(-119) --9 + j*(-103) --74 + j*(-113) --176 + j*(-38) --165 + j*(134) -11 + j*(231) -211 + j*(119) -199 + j*(-142) --76 + j*(-228) --226 + j*(30) -9 + j*(209) -200 + j*(-6) -21 + j*(-205) --164 + j*(-93) --141 + j*(21) --167 + j*(45) --193 + j*(214) -25 + j*(373) -298 + j*(247) -339 + j*(-19) -193 + j*(-187) -6 + j*(-186) --74 + j*(-49) -9 + j*(35) -66 + j*(-16) -44 + j*(-30) -100 + j*(-42) -60 + j*(-196) --193 + j*(-154) --158 + j*(175) -229 + j*(144) -200 + j*(-293) --264 + j*(-284) --288 + j*(158) -83 + j*(194) -88 + j*(-88) --126 + j*(-33) --25 + j*(153) -156 + j*(48) -86 + j*(-111) --18 + j*(-86) --4 + j*(-40) -15 + j*(-69) --14 + j*(-108) --82 + j*(-122) --151 + j*(-66) --136 + j*(14) --91 + j*(25) --88 + j*(16) --79 + j*(6) --142 + j*(-51) --326 + j*(49) --298 + j*(388) -96 + j*(531) -383 + j*(238) -268 + j*(-56) -84 + j*(-71) -29 + j*(-13) -1 + j*(42) -54 + j*(143) -218 + j*(122) -266 + j*(-61) -140 + j*(-158) -66 + j*(-114) -79 + j*(-106) -57 + j*(-148) -2 + j*(-156) --47 + j*(-148) --113 + j*(-105) --115 + j*(8) -15 + j*(54) -98 + j*(-83) --35 + j*(-215) --214 + j*(-125) --200 + j*(57) --76 + j*(100) --28 + j*(53) --25 + j*(40) --6 + j*(14) --44 + j*(-23) --100 + j*(23) --60 + j*(91) --9 + j*(66) --38 + j*(46) --46 + j*(100) -6 + j*(135) -68 + j*(144) -162 + j*(107) -194 + j*(-35) -66 + j*(-109) -26 + j*(-7) -151 + j*(-57) -23 + j*(-262) --274 + j*(-100) --108 + j*(252) -257 + j*(83) -76 + j*(-270) --252 + j*(-71) --45 + j*(216) -184 + j*(10) --11 + j*(-144) --75 + j*(35) -95 + j*(13) -1 + j*(-161) --164 + j*(-30) --23 + j*(100) -51 + j*(-47) --111 + j*(-62) --88 + j*(113) -86 + j*(73) -46 + j*(-92) --112 + j*(-87) --181 + j*(48) --118 + j*(214) -111 + j*(260) -245 + j*(37) -64 + j*(-98) -10 + j*(86) -279 + j*(38) -194 + j*(-350) --269 + j*(-301) --269 + j*(151) -103 + j*(166) -97 + j*(-110) --85 + j*(-75) --29 + j*(7) --47 + j*(-75) --155 + j*(13) --47 + j*(115) --23 + j*(8) --161 + j*(115) -73 + j*(341) -402 + j*(43) -104 + j*(-348) --291 + j*(-73) --41 + j*(291) -286 + j*(80) -141 + j*(-188) --30 + j*(-125) --25 + j*(-79) --93 + j*(-71) --95 + j*(68) -67 + j*(79) -82 + j*(-76) --42 + j*(-91) --57 + j*(-19) --46 + j*(-17) --73 + j*(24) --16 + j*(76) -40 + j*(37) -27 + j*(22) -93 + j*(28) -146 + j*(-124) --43 + j*(-261) --264 + j*(-112) --212 + j*(122) --37 + j*(161) -26 + j*(78) -6 + j*(52) -33 + j*(64) -81 + j*(0) --1 + j*(-100) --160 + j*(-18) --111 + j*(191) -105 + j*(204) -164 + j*(69) -171 + j*(43) -288 + j*(-88) -132 + j*(-406) --337 + j*(-333) --398 + j*(167) -19 + j*(324) -200 + j*(46) -62 + j*(-95) --21 + j*(-85) --133 + j*(-71) --204 + j*(156) -99 + j*(325) -346 + j*(9) -52 + j*(-248) --148 + j*(45) -208 + j*(187) -358 + j*(-264) --139 + j*(-507) --506 + j*(-58) --180 + j*(391) -290 + j*(215) -249 + j*(-226) --124 + j*(-294) --255 + j*(-22) --95 + j*(107) --29 + j*(27) --74 + j*(37) --13 + j*(66) --13 + j*(-32) --161 + j*(-1) --132 + j*(199) -66 + j*(206) -91 + j*(81) -59 + j*(102) -163 + j*(83) -148 + j*(-71) -2 + j*(-67) -16 + j*(41) -86 + j*(13) -69 + j*(-12) -115 + j*(-17) -103 + j*(-153) --99 + j*(-158) --127 + j*(71) -85 + j*(114) -129 + j*(-27) -112 + j*(-34) -218 + j*(-152) -32 + j*(-427) --383 + j*(-278) --339 + j*(162) -15 + j*(195) -56 + j*(-23) --36 + j*(-38) --22 + j*(-61) --161 + j*(-107) --261 + j*(129) -12 + j*(298) -224 + j*(59) -70 + j*(-136) --52 + j*(-70) --47 + j*(-59) --140 + j*(-52) --154 + j*(98) --23 + j*(129) --24 + j*(57) --47 + j*(139) -116 + j*(153) -151 + j*(-49) --37 + j*(-100) --79 + j*(33) --25 + j*(25) --133 + j*(35) --129 + j*(269) -173 + j*(357) -363 + j*(115) -275 + j*(-83) -205 + j*(-116) -185 + j*(-214) -9 + j*(-309) --196 + j*(-190) --194 + j*(33) --32 + j*(125) -95 + j*(32) -40 + j*(-100) --120 + j*(-52) --76 + j*(165) -205 + j*(163) -271 + j*(-156) --33 + j*(-278) --160 + j*(-15) -83 + j*(70) -123 + j*(-186) --147 + j*(-210) --156 + j*(40) -52 + j*(11) --41 + j*(-169) --214 + j*(-28) --52 + j*(142) -107 + j*(-16) --21 + j*(-165) --147 + j*(-124) --230 + j*(-78) --342 + j*(105) --146 + j*(390) -249 + j*(259) -194 + j*(-158) --195 + j*(-152) --223 + j*(187) -37 + j*(253) -122 + j*(97) -56 + j*(23) --13 + j*(51) -5 + j*(165) -209 + j*(189) -316 + j*(-83) -35 + j*(-265) --167 + j*(-19) -47 + j*(158) -181 + j*(-25) -46 + j*(-106) -53 + j*(-27) -105 + j*(-142) --91 + j*(-211) --183 + j*(-4) --4 + j*(66) --1 + j*(-104) --207 + j*(-59) --187 + j*(189) -39 + j*(249) -162 + j*(117) -140 + j*(-4) -64 + j*(-35) -35 + j*(21) -118 + j*(47) -178 + j*(-62) -99 + j*(-157) -27 + j*(-137) -33 + j*(-146) --40 + j*(-216) --193 + j*(-161) --205 + j*(27) --36 + j*(80) -11 + j*(-88) --214 + j*(-137) --328 + j*(147) --54 + j*(356) -190 + j*(168) -86 + j*(-4) -30 + j*(81) -143 + j*(59) -93 + j*(-39) -91 + j*(59) -321 + j*(-57) -171 + j*(-471) --364 + j*(-392) --382 + j*(114) --21 + j*(144) --91 + j*(-66) --223 + j*(142) -67 + j*(259) -170 + j*(-28) --49 + j*(-78) --8 + j*(59) -57 + j*(-97) --209 + j*(-124) --242 + j*(199) -52 + j*(252) -82 + j*(60) -1 + j*(119) -163 + j*(142) -177 + j*(-79) --37 + j*(-81) --11 + j*(94) -128 + j*(43) -76 + j*(-49) -56 + j*(-5) -112 + j*(-57) -29 + j*(-132) --37 + j*(-64) -15 + j*(-53) --33 + j*(-123) --136 + j*(-69) --132 + j*(37) --85 + j*(86) --25 + j*(117) -38 + j*(82) -11 + j*(58) -51 + j*(136) -216 + j*(64) -161 + j*(-162) --64 + j*(-133) --36 + j*(40) -72 + j*(-15) --13 + j*(-60) -1 + j*(43) -103 + j*(-13) -25 + j*(-83) -36 + j*(16) -181 + j*(-104) --18 + j*(-312) --258 + j*(-88) --38 + j*(113) -69 + j*(-120) --192 + j*(-119) --91 + j*(164) -205 + j*(-31) --57 + j*(-346) --381 + j*(-87) --197 + j*(186) --54 + j*(93) --95 + j*(115) -54 + j*(133) -33 + j*(-93) --244 + j*(-11) --107 + j*(305) -207 + j*(138) -18 + j*(-119) --147 + j*(105) -119 + j*(175) -96 + j*(-133) --253 + j*(-41) --149 + j*(344) -222 + j*(285) -220 + j*(11) -82 + j*(6) -124 + j*(48) -144 + j*(-33) -71 + j*(-71) -6 + j*(-41) --13 + j*(59) -137 + j*(151) -328 + j*(-30) -182 + j*(-309) --106 + j*(-240) --87 + j*(-27) -31 + j*(-71) --78 + j*(-133) --141 + j*(31) -40 + j*(122) -172 + j*(-39) -65 + j*(-214) --133 + j*(-192) --195 + j*(-4) --39 + j*(106) -78 + j*(-33) --74 + j*(-144) --187 + j*(40) -24 + j*(165) -167 + j*(-59) --47 + j*(-227) --223 + j*(-54) --111 + j*(86) --56 + j*(2) --182 + j*(34) --129 + j*(248) -155 + j*(257) -254 + j*(-10) -76 + j*(-153) --18 + j*(-66) -47 + j*(-84) --64 + j*(-223) --321 + j*(-112) --313 + j*(218) --22 + j*(334) -153 + j*(167) -99 + j*(27) -22 + j*(46) -63 + j*(111) -179 + j*(66) -187 + j*(-107) -5 + j*(-195) --132 + j*(-49) --30 + j*(89) -84 + j*(16) -40 + j*(-76) --21 + j*(-76) --74 + j*(-69) --136 + j*(7) --70 + j*(119) -35 + j*(62) --59 + j*(2) --95 + j*(186) -182 + j*(254) -316 + j*(-60) -25 + j*(-243) --161 + j*(4) -49 + j*(172) -197 + j*(2) -77 + j*(-119) -9 + j*(-37) -89 + j*(-21) -93 + j*(-126) --8 + j*(-157) --58 + j*(-104) --63 + j*(-88) --116 + j*(-65) --126 + j*(49) -14 + j*(114) -130 + j*(-16) -37 + j*(-168) --119 + j*(-136) --157 + j*(-20) --112 + j*(59) --28 + j*(83) -31 + j*(3) --67 + j*(-66) --148 + j*(71) -28 + j*(179) -158 + j*(-12) --24 + j*(-141) --117 + j*(20) -31 + j*(50) --12 + j*(-100) --171 + j*(-1) --35 + j*(156) -93 + j*(-4) --98 + j*(-98) --174 + j*(116) -35 + j*(187) -96 + j*(18) --18 + j*(-19) --39 + j*(40) --48 + j*(51) --66 + j*(136) -66 + j*(216) -198 + j*(115) -176 + j*(-5) -137 + j*(-35) -116 + j*(-69) -88 + j*(-67) -142 + j*(-100) -82 + j*(-290) --246 + j*(-293) --373 + j*(76) --87 + j*(290) -103 + j*(158) -93 + j*(109) -226 + j*(86) -247 + j*(-175) --47 + j*(-240) --90 + j*(38) -199 + j*(8) -119 + j*(-333) --255 + j*(-281) --264 + j*(42) --71 + j*(64) --111 + j*(-4) --120 + j*(132) -69 + j*(139) -86 + j*(-52) --85 + j*(-52) --62 + j*(112) -108 + j*(74) -86 + j*(-99) --75 + j*(-96) --78 + j*(42) -48 + j*(34) -23 + j*(-105) --137 + j*(-85) --141 + j*(82) --5 + j*(100) --5 + j*(16) --49 + j*(69) -77 + j*(88) -92 + j*(-113) --182 + j*(-150) --276 + j*(168) -23 + j*(330) -208 + j*(107) -64 + j*(-23) -19 + j*(103) -180 + j*(107) -218 + j*(-68) -98 + j*(-160) -4 + j*(-145) --81 + j*(-99) --108 + j*(50) -88 + j*(154) -288 + j*(-64) -101 + j*(-367) --256 + j*(-279) --276 + j*(37) --73 + j*(96) --68 + j*(-6) --135 + j*(78) -10 + j*(161) -100 + j*(9) --40 + j*(-54) --47 + j*(86) -120 + j*(31) -17 + j*(-182) --261 + j*(-69) --202 + j*(252) -85 + j*(308) -233 + j*(171) -313 + j*(39) -313 + j*(-197) -59 + j*(-351) --148 + j*(-180) --38 + j*(-49) --81 + j*(-46) --16 + j*(85) -103 + j*(-8) --16 + j*(-98) --54 + j*(54) -149 + j*(39) -102 + j*(-221) --192 + j*(-181) --167 + j*(105) -78 + j*(81) -42 + j*(-127) --145 + j*(-88) --132 + j*(79) -8 + j*(108) -81 + j*(4) -7 + j*(-110) --141 + j*(-67) --123 + j*(97) -32 + j*(84) --13 + j*(-54) --156 + j*(39) --35 + j*(213) -158 + j*(103) -86 + j*(-72) --36 + j*(-31) --8 + j*(33) -12 + j*(3) --18 + j*(3) --26 + j*(21) --40 + j*(49) --1 + j*(110) -91 + j*(77) -57 + j*(-6) -1 + j*(72) -150 + j*(144) -295 + j*(-41) -176 + j*(-265) --59 + j*(-291) --229 + j*(-135) --201 + j*(130) -114 + j*(213) -281 + j*(-125) --55 + j*(-348) --282 + j*(-45) --9 + j*(112) -31 + j*(-186) --354 + j*(-137) --294 + j*(325) -173 + j*(303) -168 + j*(-91) --138 + j*(-62) --81 + j*(177) -95 + j*(133) -79 + j*(59) -144 + j*(83) -242 + j*(-95) -37 + j*(-299) --247 + j*(-161) --223 + j*(132) -5 + j*(216) -146 + j*(88) -110 + j*(-48) -15 + j*(-57) -13 + j*(1) -62 + j*(-21) -42 + j*(-80) --10 + j*(-93) --57 + j*(-95) --132 + j*(-48) --117 + j*(71) --4 + j*(81) --21 + j*(-1) --98 + j*(76) -10 + j*(199) -175 + j*(142) -238 + j*(12) -245 + j*(-152) -62 + j*(-344) --260 + j*(-221) --199 + j*(131) -117 + j*(80) -23 + j*(-192) --208 + j*(-39) --1 + j*(132) -88 + j*(-134) --250 + j*(-153) --228 + j*(236) -160 + j*(183) -52 + j*(-163) --254 + j*(30) -9 + j*(329) -326 + j*(51) -100 + j*(-272) --187 + j*(-156) --197 + j*(35) --144 + j*(139) --6 + j*(221) -158 + j*(98) -41 + j*(-88) --153 + j*(50) --9 + j*(281) -256 + j*(204) -310 + j*(-22) -224 + j*(-184) -53 + j*(-279) --167 + j*(-194) --196 + j*(51) --12 + j*(165) -132 + j*(88) -176 + j*(-17) -170 + j*(-149) -28 + j*(-263) --156 + j*(-184) --144 + j*(-11) --22 + j*(-8) --47 + j*(-112) --171 + j*(-77) --164 + j*(60) --51 + j*(81) --47 + j*(-8) --152 + j*(21) --140 + j*(176) -28 + j*(229) -139 + j*(130) -151 + j*(42) -165 + j*(-37) -103 + j*(-161) --70 + j*(-179) --158 + j*(-38) --97 + j*(66) --30 + j*(76) -13 + j*(75) -59 + j*(37) -47 + j*(-21) -20 + j*(-23) -34 + j*(-53) --50 + j*(-124) --206 + j*(-18) --139 + j*(218) -118 + j*(235) -202 + j*(41) -112 + j*(-37) -115 + j*(-7) -166 + j*(-97) -58 + j*(-223) --95 + j*(-175) --90 + j*(-58) --28 + j*(-78) --98 + j*(-123) --185 + j*(-47) --167 + j*(49) --157 + j*(98) --117 + j*(235) -140 + j*(299) -325 + j*(19) -93 + j*(-212) --86 + j*(-13) -160 + j*(75) -199 + j*(-272) --233 + j*(-331) --342 + j*(107) -18 + j*(229) -87 + j*(-29) --98 + j*(6) -40 + j*(168) -213 + j*(-25) -25 + j*(-207) --131 + j*(-75) --62 + j*(12) --69 + j*(-28) --123 + j*(47) --41 + j*(129) -35 + j*(94) -56 + j*(64) -83 + j*(13) -10 + j*(-50) --74 + j*(51) -56 + j*(165) -204 + j*(49) -142 + j*(-91) -78 + j*(-69) -125 + j*(-101) -64 + j*(-228) --124 + j*(-233) --235 + j*(-74) --181 + j*(107) --5 + j*(154) -80 + j*(28) --16 + j*(-20) -17 + j*(107) -236 + j*(8) -134 + j*(-330) --291 + j*(-291) --337 + j*(137) -24 + j*(231) -107 + j*(-56) --137 + j*(-117) --220 + j*(99) --74 + j*(236) -87 + j*(215) -190 + j*(102) -170 + j*(-55) -44 + j*(-113) --37 + j*(-57) --55 + j*(-3) --64 + j*(71) -32 + j*(159) -192 + j*(98) -202 + j*(-74) -95 + j*(-137) -58 + j*(-116) -57 + j*(-165) --45 + j*(-228) --190 + j*(-177) --257 + j*(-37) --233 + j*(117) --110 + j*(246) -111 + j*(260) -280 + j*(59) -185 + j*(-203) --71 + j*(-223) --153 + j*(-43) --52 + j*(22) --49 + j*(-45) --122 + j*(-13) --112 + j*(59) --109 + j*(77) --118 + j*(186) -57 + j*(296) -267 + j*(158) -236 + j*(-60) -112 + j*(-116) -49 + j*(-120) --46 + j*(-100) --64 + j*(30) -73 + j*(61) -98 + j*(-70) --2 + j*(-81) -14 + j*(-40) --16 + j*(-98) --130 + j*(4) -43 + j*(180) -282 + j*(-47) -43 + j*(-334) --238 + j*(-124) --54 + j*(81) -45 + j*(-129) --231 + j*(-156) --253 + j*(165) -40 + j*(216) -103 + j*(1) --19 + j*(-45) --43 + j*(-1) --65 + j*(13) --57 + j*(88) -45 + j*(73) -1 + j*(-36) --126 + j*(59) --6 + j*(226) -196 + j*(142) -196 + j*(-37) -100 + j*(-117) --24 + j*(-124) --115 + j*(30) -78 + j*(194) -328 + j*(-31) -119 + j*(-364) --248 + j*(-228) --198 + j*(104) -54 + j*(115) -112 + j*(-59) -21 + j*(-175) --156 + j*(-185) --276 + j*(3) --127 + j*(174) --3 + j*(57) --167 + j*(33) --131 + j*(307) -233 + j*(283) -233 + j*(-86) --93 + j*(-55) -10 + j*(262) -358 + j*(125) -259 + j*(-226) --8 + j*(-181) -48 + j*(-40) -110 + j*(-176) --99 + j*(-247) --218 + j*(-33) --54 + j*(109) -65 + j*(-14) --57 + j*(-100) --139 + j*(45) -28 + j*(158) -182 + j*(0) -69 + j*(-180) --88 + j*(-124) --69 + j*(-43) --74 + j*(-78) --165 + j*(-21) --103 + j*(114) -45 + j*(63) --7 + j*(-81) --170 + j*(-40) --177 + j*(142) --13 + j*(234) -148 + j*(132) -103 + j*(-50) --79 + j*(-21) --26 + j*(179) -214 + j*(95) -111 + j*(-183) --202 + j*(-62) --65 + j*(286) -315 + j*(166) -247 + j*(-214) --81 + j*(-214) --130 + j*(21) -3 + j*(99) -97 + j*(65) -159 + j*(-36) -64 + j*(-176) --128 + j*(-100) --64 + j*(124) -179 + j*(76) -174 + j*(-169) --23 + j*(-226) --122 + j*(-134) --151 + j*(-48) --122 + j*(69) -34 + j*(99) -103 + j*(-63) --43 + j*(-161) --153 + j*(-62) --126 + j*(22) --119 + j*(59) --62 + j*(153) -116 + j*(122) -127 + j*(-105) --116 + j*(-155) --199 + j*(83) -21 + j*(189) -140 + j*(-9) --33 + j*(-146) --199 + j*(-18) --157 + j*(160) --21 + j*(222) -100 + j*(185) -158 + j*(81) -110 + j*(-5) -48 + j*(25) -108 + j*(71) -187 + j*(-6) -154 + j*(-117) -86 + j*(-159) -15 + j*(-206) --144 + j*(-207) --269 + j*(-13) --130 + j*(208) -117 + j*(156) -132 + j*(-68) --62 + j*(-125) --164 + j*(41) --47 + j*(194) -119 + j*(163) -163 + j*(57) -165 + j*(20) -226 + j*(-57) -159 + j*(-233) --67 + j*(-223) --69 + j*(-4) -162 + j*(-57) -66 + j*(-364) --327 + j*(-300) --351 + j*(98) --35 + j*(180) -35 + j*(-36) --113 + j*(-70) --138 + j*(25) --122 + j*(54) --122 + j*(134) -18 + j*(202) -151 + j*(71) -77 + j*(-88) --50 + j*(-88) --115 + j*(-35) --170 + j*(60) --103 + j*(218) -100 + j*(221) -163 + j*(52) -70 + j*(0) -94 + j*(52) -177 + j*(-44) -76 + j*(-206) --129 + j*(-180) --207 + j*(-13) --145 + j*(124) --36 + j*(175) -72 + j*(143) -110 + j*(42) -35 + j*(-27) --54 + j*(42) -8 + j*(174) -184 + j*(151) -238 + j*(-20) -127 + j*(-120) -41 + j*(-89) -18 + j*(-49) -14 + j*(13) -120 + j*(69) -255 + j*(-63) -156 + j*(-270) --48 + j*(-243) --50 + j*(-122) --13 + j*(-175) --153 + j*(-200) --223 + j*(-23) --74 + j*(87) -52 + j*(-10) -15 + j*(-144) --121 + j*(-197) --276 + j*(-108) --284 + j*(95) --121 + j*(185) --32 + j*(103) --72 + j*(75) --62 + j*(121) --23 + j*(132) -16 + j*(161) -151 + j*(142) -204 + j*(-68) --15 + j*(-202) --190 + j*(-33) --98 + j*(127) --8 + j*(94) --21 + j*(100) -47 + j*(135) -111 + j*(59) -66 + j*(-3) -42 + j*(13) -32 + j*(-7) --28 + j*(33) -42 + j*(144) -214 + j*(71) -183 + j*(-139) --11 + j*(-169) --77 + j*(-37) --13 + j*(28) -28 + j*(4) -6 + j*(-13) --9 + j*(39) -87 + j*(86) -190 + j*(-39) -71 + j*(-185) --72 + j*(-78) -59 + j*(27) -148 + j*(-169) --95 + j*(-299) --284 + j*(-90) --183 + j*(114) --41 + j*(128) -42 + j*(76) -41 + j*(-37) --104 + j*(-27) --61 + j*(190) -254 + j*(127) -204 + j*(-261) --199 + j*(-235) --174 + j*(119) -93 + j*(52) --48 + j*(-120) --139 + j*(107) -165 + j*(136) -159 + j*(-217) --197 + j*(-197) --162 + j*(107) -62 + j*(37) --49 + j*(-124) --175 + j*(-10) --124 + j*(65) --156 + j*(110) --60 + j*(294) -245 + j*(221) -237 + j*(-116) --35 + j*(-135) --19 + j*(35) -81 + j*(-70) --105 + j*(-158) --230 + j*(45) --98 + j*(192) -4 + j*(180) -74 + j*(200) -221 + j*(139) -243 + j*(-57) -95 + j*(-151) --8 + j*(-93) --18 + j*(-30) -0 + j*(6) -32 + j*(16) -68 + j*(11) -120 + j*(-41) -82 + j*(-187) --162 + j*(-208) --276 + j*(105) -57 + j*(322) -353 + j*(23) -128 + j*(-309) --186 + j*(-168) --115 + j*(102) -116 + j*(84) -170 + j*(-120) -5 + j*(-276) --236 + j*(-190) --244 + j*(74) --15 + j*(129) -18 + j*(-59) --169 + j*(-57) --166 + j*(146) -8 + j*(187) -89 + j*(97) -104 + j*(8) -26 + j*(-96) --151 + j*(-27) --93 + j*(222) -204 + j*(211) -271 + j*(-60) -118 + j*(-177) -35 + j*(-197) --118 + j*(-234) --296 + j*(-45) --152 + j*(199) -51 + j*(112) --34 + j*(23) --15 + j*(175) -233 + j*(110) -190 + j*(-203) --110 + j*(-227) --203 + j*(-18) --148 + j*(100) --77 + j*(214) -154 + j*(251) -313 + j*(-6) -112 + j*(-228) --91 + j*(-103) -2 + j*(36) -103 + j*(-71) --13 + j*(-194) --187 + j*(-126) --211 + j*(74) --35 + j*(177) -103 + j*(34) --38 + j*(-107) --194 + j*(48) --54 + j*(236) -139 + j*(153) -111 + j*(17) -49 + j*(28) -78 + j*(55) -118 + j*(41) -170 + j*(-4) -170 + j*(-122) -45 + j*(-183) --30 + j*(-103) -19 + j*(-76) --4 + j*(-136) --82 + j*(-109) --69 + j*(-55) --71 + j*(-72) --119 + j*(-47) --114 + j*(8) --107 + j*(29) --91 + j*(101) -47 + j*(107) -65 + j*(-80) --173 + j*(-102) --209 + j*(184) -93 + j*(252) -185 + j*(-21) --38 + j*(-115) --121 + j*(50) --29 + j*(117) --6 + j*(107) -30 + j*(156) -132 + j*(152) -189 + j*(82) -221 + j*(23) -244 + j*(-66) -218 + j*(-163) -179 + j*(-264) -26 + j*(-409) --295 + j*(-341) --363 + j*(37) --18 + j*(168) -91 + j*(-151) --255 + j*(-233) --349 + j*(125) --42 + j*(233) -11 + j*(0) --204 + j*(31) --136 + j*(288) -141 + j*(272) -200 + j*(45) -67 + j*(-45) --9 + j*(32) -59 + j*(119) -215 + j*(54) -209 + j*(-194) --94 + j*(-302) --320 + j*(-16) --112 + j*(284) -194 + j*(171) -148 + j*(-88) --57 + j*(-61) --19 + j*(124) -183 + j*(101) -230 + j*(-124) -29 + j*(-272) --207 + j*(-153) --192 + j*(122) -68 + j*(192) -184 + j*(-30) -1 + j*(-141) --74 + j*(33) -127 + j*(67) -157 + j*(-180) --114 + j*(-251) --228 + j*(-17) --82 + j*(104) --14 + j*(49) --8 + j*(66) -86 + j*(42) -71 + j*(-99) --79 + j*(-98) --80 + j*(25) --6 + j*(4) --71 + j*(-25) --71 + j*(88) -77 + j*(71) -49 + j*(-103) --151 + j*(-70) --147 + j*(149) -59 + j*(213) -199 + j*(84) -207 + j*(-97) -67 + j*(-251) --182 + j*(-228) --293 + j*(14) --147 + j*(204) -23 + j*(180) -74 + j*(98) -80 + j*(47) -62 + j*(-4) -2 + j*(-7) --12 + j*(57) -57 + j*(87) -107 + j*(38) -102 + j*(0) -119 + j*(-10) -156 + j*(-88) -71 + j*(-206) --96 + j*(-164) --83 + j*(-8) -54 + j*(-48) --49 + j*(-215) --287 + j*(-91) --204 + j*(205) -94 + j*(183) -115 + j*(-76) --100 + j*(-132) --210 + j*(28) --159 + j*(198) -22 + j*(296) -242 + j*(185) -238 + j*(-55) -69 + j*(-94) -85 + j*(-11) -148 + j*(-138) --55 + j*(-249) --222 + j*(-41) --63 + j*(134) -74 + j*(28) -4 + j*(-62) --53 + j*(-33) --95 + j*(4) --113 + j*(147) -127 + j*(271) -388 + j*(-3) -170 + j*(-368) --207 + j*(-255) --165 + j*(28) --20 + j*(-34) --176 + j*(-87) --212 + j*(161) -56 + j*(214) -88 + j*(-25) --130 + j*(20) --13 + j*(269) -270 + j*(145) -179 + j*(-109) -32 + j*(-13) -214 + j*(32) -240 + j*(-249) --54 + j*(-318) --115 + j*(-124) --49 + j*(-179) --281 + j*(-192) --308 + j*(177) -122 + j*(210) -110 + j*(-257) --413 + j*(-193) --341 + j*(371) -194 + j*(319) -129 + j*(-114) --196 + j*(16) -9 + j*(273) -226 + j*(30) --14 + j*(-144) --143 + j*(71) -37 + j*(160) -98 + j*(29) -11 + j*(-23) --62 + j*(30) --59 + j*(172) -170 + j*(260) -374 + j*(-22) -91 + j*(-315) --235 + j*(-52) -17 + j*(264) -308 + j*(32) -112 + j*(-209) --40 + j*(-46) -129 + j*(11) -146 + j*(-182) --29 + j*(-237) --134 + j*(-165) --228 + j*(-64) --201 + j*(183) -124 + j*(269) -307 + j*(-57) -36 + j*(-274) --158 + j*(-65) -25 + j*(76) -141 + j*(-103) --4 + j*(-233) --125 + j*(-177) --166 + j*(-139) --263 + j*(-87) --305 + j*(98) --144 + j*(253) -52 + j*(184) -46 + j*(33) --37 + j*(44) -24 + j*(87) -57 + j*(-37) --132 + j*(-75) --199 + j*(168) -64 + j*(276) -189 + j*(35) --25 + j*(-61) --81 + j*(156) -144 + j*(209) -223 + j*(22) -127 + j*(-48) -130 + j*(-33) -136 + j*(-127) -8 + j*(-185) --102 + j*(-104) --106 + j*(10) --30 + j*(91) -103 + j*(66) -124 + j*(-93) --32 + j*(-141) --78 + j*(-13) -25 + j*(-13) --52 + j*(-115) --190 + j*(29) --10 + j*(219) -214 + j*(38) -43 + j*(-186) --152 + j*(-14) -47 + j*(155) -214 + j*(-83) --40 + j*(-281) --275 + j*(-59) --132 + j*(180) -62 + j*(122) -66 + j*(18) -66 + j*(-15) -33 + j*(-124) --178 + j*(-131) --274 + j*(151) -3 + j*(363) -296 + j*(180) -255 + j*(-107) -62 + j*(-172) --33 + j*(-97) --42 + j*(-28) --8 + j*(23) -67 + j*(13) -92 + j*(-84) --1 + j*(-163) --136 + j*(-114) --154 + j*(33) --37 + j*(105) -46 + j*(37) -23 + j*(-28) --10 + j*(-42) --65 + j*(-58) --161 + j*(40) --48 + j*(238) -242 + j*(153) -208 + j*(-176) --96 + j*(-171) --71 + j*(79) -141 + j*(0) -22 + j*(-195) --145 + j*(-69) --23 + j*(32) -1 + j*(-106) --158 + j*(-91) --144 + j*(37) --114 + j*(6) --225 + j*(88) --99 + j*(313) -187 + j*(224) -156 + j*(-27) -6 + j*(-21) -26 + j*(18) --44 + j*(-21) --110 + j*(156) -166 + j*(279) -373 + j*(-39) -102 + j*(-322) --210 + j*(-171) --206 + j*(98) --38 + j*(230) -175 + j*(190) -238 + j*(-39) -24 + j*(-137) --42 + j*(72) -193 + j*(92) -178 + j*(-170) --78 + j*(-119) -30 + j*(127) -289 + j*(-23) -171 + j*(-293) --29 + j*(-264) --54 + j*(-238) --212 + j*(-272) --380 + j*(-33) --190 + j*(227) -57 + j*(135) -23 + j*(-16) --23 + j*(14) -38 + j*(-11) --19 + j*(-117) --170 + j*(-73) --187 + j*(109) --20 + j*(211) -161 + j*(103) -127 + j*(-109) --69 + j*(-141) --123 + j*(8) --30 + j*(41) --50 + j*(-23) --117 + j*(51) --20 + j*(134) -69 + j*(46) --4 + j*(-28) --60 + j*(30) --26 + j*(81) -18 + j*(88) -84 + j*(67) -106 + j*(-46) --32 + j*(-121) --155 + j*(11) --52 + j*(162) -104 + j*(91) -49 + j*(-57) --107 + j*(-10) --84 + j*(162) -78 + j*(184) -108 + j*(79) -66 + j*(119) -233 + j*(180) -402 + j*(-80) -151 + j*(-373) --197 + j*(-202) --103 + j*(110) -122 + j*(50) -57 + j*(-78) -13 + j*(30) -183 + j*(25) -190 + j*(-180) -16 + j*(-221) --12 + j*(-131) -28 + j*(-171) --58 + j*(-234) --159 + j*(-191) --208 + j*(-126) --233 + j*(-35) --175 + j*(46) --124 + j*(7) --218 + j*(2) --249 + j*(175) --74 + j*(280) -54 + j*(189) -38 + j*(134) -87 + j*(160) -177 + j*(76) -134 + j*(-44) -55 + j*(-45) -66 + j*(-36) -42 + j*(-107) --86 + j*(-110) --147 + j*(40) --18 + j*(158) -138 + j*(78) -116 + j*(-87) --26 + j*(-118) --91 + j*(-23) --45 + j*(52) -23 + j*(49) -59 + j*(-13) -6 + j*(-88) --102 + j*(-58) --103 + j*(64) -0 + j*(80) -0 + j*(1) --79 + j*(38) --22 + j*(141) -101 + j*(96) -76 + j*(-18) --18 + j*(6) -22 + j*(97) -136 + j*(53) -112 + j*(-92) --50 + j*(-98) --86 + j*(70) -83 + j*(131) -158 + j*(-28) -12 + j*(-99) --45 + j*(52) -128 + j*(119) -250 + j*(-48) -161 + j*(-238) --41 + j*(-281) --210 + j*(-143) --170 + j*(83) -44 + j*(117) -103 + j*(-55) --17 + j*(-90) -6 + j*(-11) -67 + j*(-115) --100 + j*(-185) --186 + j*(7) -6 + j*(85) -59 + j*(-106) --128 + j*(-150) --174 + j*(-2) --106 + j*(23) --146 + j*(30) --115 + j*(137) -16 + j*(115) --12 + j*(10) --88 + j*(73) -11 + j*(140) -76 + j*(25) --41 + j*(-23) --69 + j*(100) -61 + j*(120) -73 + j*(-14) --76 + j*(-17) --76 + j*(166) -146 + j*(190) -203 + j*(-59) --65 + j*(-141) --179 + j*(158) -127 + j*(331) -366 + j*(92) -271 + j*(-130) -192 + j*(-168) -129 + j*(-303) --170 + j*(-330) --313 + j*(18) -4 + j*(231) -230 + j*(-30) -35 + j*(-240) --133 + j*(-135) --115 + j*(-52) --153 + j*(-35) --172 + j*(101) --16 + j*(192) -129 + j*(86) -98 + j*(-69) --40 + j*(-105) --125 + j*(18) --9 + j*(138) -136 + j*(25) -25 + j*(-136) --140 + j*(-26) --40 + j*(128) -86 + j*(42) -8 + j*(-37) --24 + j*(43) -59 + j*(53) -67 + j*(-8) -61 + j*(-6) -91 + j*(-59) -16 + j*(-127) --57 + j*(-59) -2 + j*(-24) --6 + j*(-105) --116 + j*(-82) --112 + j*(23) --62 + j*(28) --76 + j*(44) --19 + j*(91) -38 + j*(19) --56 + j*(-11) --56 + j*(129) -135 + j*(124) -157 + j*(-80) -3 + j*(-127) --21 + j*(-65) --49 + j*(-135) --255 + j*(-85) --267 + j*(240) -88 + j*(366) -314 + j*(74) -134 + j*(-172) --48 + j*(-84) -16 + j*(-5) -13 + j*(-124) --199 + j*(-104) --243 + j*(177) -21 + j*(323) -231 + j*(174) -241 + j*(6) -211 + j*(-120) -67 + j*(-256) --177 + j*(-171) --163 + j*(88) -32 + j*(101) -6 + j*(3) --6 + j*(133) -254 + j*(110) -267 + j*(-250) --100 + j*(-334) --221 + j*(-70) --113 + j*(-4) --188 + j*(12) --129 + j*(237) -175 + j*(192) -129 + j*(-105) --121 + j*(4) -83 + j*(243) -358 + j*(-13) -136 + j*(-320) --134 + j*(-193) --85 + j*(-28) --25 + j*(-49) --39 + j*(-59) --42 + j*(-81) --126 + j*(-83) --144 + j*(44) --16 + j*(53) --59 + j*(-66) --182 + j*(48) --15 + j*(173) -83 + j*(-40) --190 + j*(-96) --234 + j*(235) -103 + j*(293) -141 + j*(22) --61 + j*(75) -105 + j*(276) -367 + j*(68) -211 + j*(-231) --35 + j*(-161) -0 + j*(-14) -74 + j*(-76) --12 + j*(-136) --82 + j*(-64) --36 + j*(-12) --21 + j*(-69) --129 + j*(-76) --170 + j*(76) --22 + j*(163) -64 + j*(42) --47 + j*(8) --32 + j*(148) -131 + j*(115) -85 + j*(-23) -4 + j*(89) -236 + j*(157) -371 + j*(-161) -77 + j*(-395) --167 + j*(-233) --142 + j*(-103) --190 + j*(-85) --221 + j*(99) --4 + j*(197) -113 + j*(18) --13 + j*(-54) --8 + j*(36) -69 + j*(-48) --64 + j*(-131) --150 + j*(8) --42 + j*(59) --83 + j*(-22) --187 + j*(132) -33 + j*(313) -291 + j*(114) -173 + j*(-157) --25 + j*(-118) --11 + j*(-26) --4 + j*(-68) --82 + j*(-47) --72 + j*(32) --42 + j*(31) --70 + j*(67) -2 + j*(145) -115 + j*(83) -69 + j*(-19) -2 + j*(51) -117 + j*(122) -245 + j*(2) -214 + j*(-159) -125 + j*(-253) --7 + j*(-340) --247 + j*(-320) --415 + j*(-74) --314 + j*(210) --62 + j*(283) -95 + j*(155) -68 + j*(13) --33 + j*(16) --16 + j*(117) -112 + j*(99) -112 + j*(-35) -4 + j*(-37) -42 + j*(50) -138 + j*(-35) -48 + j*(-168) --95 + j*(-132) --135 + j*(-46) --175 + j*(45) --99 + j*(234) -212 + j*(230) -308 + j*(-136) --42 + j*(-317) --255 + j*(-39) --71 + j*(141) -24 + j*(26) --61 + j*(32) -14 + j*(115) -88 + j*(12) --23 + j*(-21) -12 + j*(112) -178 + j*(14) -47 + j*(-193) --189 + j*(-53) --62 + j*(185) -148 + j*(84) -74 + j*(-69) --12 + j*(-4) -55 + j*(35) -66 + j*(-12) -81 + j*(13) -192 + j*(-59) -122 + j*(-283) --159 + j*(-285) --238 + j*(-45) --95 + j*(30) --93 + j*(-46) --166 + j*(18) --97 + j*(98) --63 + j*(34) --175 + j*(78) --115 + j*(289) -161 + j*(317) -301 + j*(96) -231 + j*(-69) -163 + j*(-127) -91 + j*(-209) --72 + j*(-214) --153 + j*(-78) --91 + j*(0) --83 + j*(-28) --144 + j*(37) --59 + j*(159) -102 + j*(96) -62 + j*(-69) --101 + j*(-29) --47 + j*(142) -145 + j*(75) -66 + j*(-145) --194 + j*(-59) --121 + j*(255) -226 + j*(237) -284 + j*(-82) -60 + j*(-177) -6 + j*(-68) -46 + j*(-112) --89 + j*(-147) --141 + j*(33) -42 + j*(86) -74 + j*(-95) --98 + j*(-101) --79 + j*(47) -28 + j*(-16) --104 + j*(-104) --210 + j*(83) --21 + j*(232) -139 + j*(103) -92 + j*(-8) -67 + j*(-16) -40 + j*(-74) --71 + j*(-34) -2 + j*(122) -231 + j*(6) -110 + j*(-317) --290 + j*(-269) --358 + j*(111) --109 + j*(267) -21 + j*(192) -65 + j*(185) -185 + j*(136) -192 + j*(-16) -103 + j*(-41) -150 + j*(-35) -134 + j*(-185) --76 + j*(-198) --94 + j*(1) -70 + j*(-44) --75 + j*(-212) --285 + j*(13) --35 + j*(257) -196 + j*(19) --34 + j*(-148) --113 + j*(96) -163 + j*(103) -129 + j*(-198) --148 + j*(-154) --99 + j*(44) --8 + j*(-47) --171 + j*(-51) --137 + j*(169) -82 + j*(134) -39 + j*(-27) --40 + j*(47) -66 + j*(49) -6 + j*(-69) --103 + j*(54) -69 + j*(132) -98 + j*(-70) --124 + j*(-29) --10 + j*(222) -260 + j*(67) -114 + j*(-181) --49 + j*(-58) -71 + j*(-25) --18 + j*(-165) --169 + j*(13) -81 + j*(142) -180 + j*(-171) --167 + j*(-261) --250 + j*(37) --76 + j*(62) --204 + j*(18) --202 + j*(334) -235 + j*(380) -347 + j*(-47) -23 + j*(-152) -3 + j*(66) -168 + j*(-11) -37 + j*(-153) --72 + j*(-21) -45 + j*(47) -83 + j*(-41) -49 + j*(-69) -35 + j*(-114) --78 + j*(-126) --99 + j*(24) -77 + j*(13) -19 + j*(-216) --276 + j*(-156) --284 + j*(150) --77 + j*(244) -25 + j*(216) -167 + j*(210) -296 + j*(-6) -105 + j*(-216) --93 + j*(-66) -57 + j*(64) -146 + j*(-127) --79 + j*(-224) --211 + j*(-19) --73 + j*(138) -80 + j*(81) -96 + j*(-46) -1 + j*(-110) --70 + j*(-42) -5 + j*(-4) -1 + j*(-139) --228 + j*(-139) --295 + j*(160) --11 + j*(317) -194 + j*(139) -155 + j*(-28) -108 + j*(-105) --11 + j*(-213) --255 + j*(-135) --271 + j*(165) --18 + j*(264) -84 + j*(119) -25 + j*(99) -105 + j*(161) -235 + j*(39) -151 + j*(-148) --40 + j*(-140) --90 + j*(16) -25 + j*(94) -120 + j*(14) -75 + j*(-83) -5 + j*(-74) -2 + j*(-60) --56 + j*(-86) --141 + j*(25) --11 + j*(178) -184 + j*(57) -73 + j*(-150) --120 + j*(-24) -37 + j*(170) -266 + j*(-8) -126 + j*(-279) --144 + j*(-231) --191 + j*(-41) --134 + j*(50) --66 + j*(119) -76 + j*(112) -122 + j*(-46) --18 + j*(-110) --66 + j*(10) -49 + j*(23) -34 + j*(-105) --104 + j*(-74) --68 + j*(72) -86 + j*(34) -71 + j*(-132) --91 + j*(-177) --204 + j*(-71) --194 + j*(69) --88 + j*(142) -6 + j*(93) --11 + j*(27) --46 + j*(41) --32 + j*(51) --63 + j*(48) --66 + j*(142) -88 + j*(167) -131 + j*(-28) --103 + j*(-74) --167 + j*(211) -144 + j*(334) -329 + j*(72) -173 + j*(-104) -86 + j*(-20) -187 + j*(-28) -176 + j*(-183) -21 + j*(-251) --116 + j*(-192) --187 + j*(-69) --146 + j*(75) --13 + j*(116) -58 + j*(46) -50 + j*(-4) -40 + j*(-40) --24 + j*(-63) --74 + j*(33) -59 + j*(116) -192 + j*(-36) -55 + j*(-223) --163 + j*(-145) --164 + j*(65) --1 + j*(142) -137 + j*(43) -119 + j*(-133) --65 + j*(-199) --193 + j*(-47) --95 + j*(98) -14 + j*(49) --11 + j*(-2) --1 + j*(20) -31 + j*(-43) --79 + j*(-95) --156 + j*(33) --37 + j*(119) -28 + j*(18) --74 + j*(-13) --95 + j*(91) --21 + j*(122) --11 + j*(119) -47 + j*(191) -222 + j*(151) -265 + j*(-71) -82 + j*(-185) --40 + j*(-66) -66 + j*(24) -174 + j*(-113) -35 + j*(-313) --267 + j*(-271) --388 + j*(52) --160 + j*(308) -133 + j*(223) -158 + j*(-12) -13 + j*(-76) --36 + j*(-8) --13 + j*(6) --27 + j*(-4) --44 + j*(18) --49 + j*(32) --75 + j*(81) --13 + j*(182) -148 + j*(168) -200 + j*(19) -131 + j*(-46) -139 + j*(-54) -121 + j*(-175) --78 + j*(-204) --154 + j*(7) -37 + j*(87) -86 + j*(-81) --64 + j*(-85) --6 + j*(43) -111 + j*(-93) --103 + j*(-233) --294 + j*(11) --91 + j*(235) -106 + j*(117) -64 + j*(27) -110 + j*(53) -191 + j*(-95) -31 + j*(-250) --144 + j*(-170) --157 + j*(-76) --209 + j*(-36) --236 + j*(128) --69 + j*(251) -84 + j*(177) -125 + j*(95) -177 + j*(-8) -71 + j*(-192) --204 + j*(-117) --164 + j*(200) -153 + j*(187) -148 + j*(-98) --88 + j*(-79) --40 + j*(113) -110 + j*(35) -11 + j*(-76) --71 + j*(46) -70 + j*(124) -175 + j*(-5) -114 + j*(-146) --22 + j*(-192) --167 + j*(-117) --182 + j*(71) --16 + j*(154) -81 + j*(30) --27 + j*(-45) --94 + j*(90) -71 + j*(202) -274 + j*(52) -215 + j*(-234) --93 + j*(-301) --268 + j*(-52) --110 + j*(161) -73 + j*(81) -32 + j*(-45) --45 + j*(-16) --29 + j*(23) --31 + j*(35) -9 + j*(85) -100 + j*(33) -43 + j*(-78) --61 + j*(1) -64 + j*(94) -168 + j*(-78) --13 + j*(-205) --144 + j*(-61) --56 + j*(13) --86 + j*(-42) --156 + j*(94) -42 + j*(208) -191 + j*(-6) --13 + j*(-153) --127 + j*(37) -59 + j*(109) -88 + j*(-75) --93 + j*(-64) --45 + j*(118) -148 + j*(40) -61 + j*(-171) --164 + j*(-104) --133 + j*(106) -27 + j*(103) -9 + j*(1) --65 + j*(74) -59 + j*(178) -222 + j*(57) -158 + j*(-132) -12 + j*(-125) -33 + j*(-59) -55 + j*(-160) --129 + j*(-214) --256 + j*(-8) --85 + j*(175) -112 + j*(47) -15 + j*(-156) --210 + j*(-97) --221 + j*(140) --15 + j*(230) -112 + j*(87) -8 + j*(-23) --72 + j*(98) -100 + j*(187) -235 + j*(-24) -18 + j*(-221) --236 + j*(-31) --109 + j*(274) -211 + j*(248) -299 + j*(-25) -122 + j*(-179) --27 + j*(-86) -56 + j*(40) -208 + j*(-78) -81 + j*(-318) --235 + j*(-260) --277 + j*(49) --59 + j*(149) -13 + j*(44) --18 + j*(52) -71 + j*(60) -81 + j*(-71) --65 + j*(-76) --45 + j*(76) -122 + j*(35) -91 + j*(-156) --100 + j*(-170) --175 + j*(-18) --83 + j*(103) -70 + j*(66) -72 + j*(-126) --162 + j*(-174) --268 + j*(81) --34 + j*(223) -95 + j*(27) --81 + j*(-58) --129 + j*(103) --10 + j*(121) --62 + j*(67) --89 + j*(242) -182 + j*(332) -387 + j*(71) -248 + j*(-204) --4 + j*(-214) --124 + j*(-41) --28 + j*(148) -207 + j*(115) -240 + j*(-131) -43 + j*(-199) -14 + j*(-80) -99 + j*(-156) --59 + j*(-278) --228 + j*(-122) --134 + j*(25) --71 + j*(-31) --134 + j*(-13) --91 + j*(50) --78 + j*(2) --161 + j*(66) --52 + j*(206) -125 + j*(95) -28 + j*(-72) --110 + j*(14) --52 + j*(128) -25 + j*(127) -94 + j*(114) -146 + j*(-5) --8 + j*(-91) --98 + j*(117) -173 + j*(220) -301 + j*(-74) -52 + j*(-197) -16 + j*(-13) -180 + j*(-112) --13 + j*(-313) --245 + j*(-104) --64 + j*(89) -49 + j*(-84) --145 + j*(-141) --194 + j*(45) --72 + j*(105) --32 + j*(76) -17 + j*(74) -37 + j*(-18) --81 + j*(-42) --104 + j*(80) --23 + j*(100) --51 + j*(107) -42 + j*(243) -305 + j*(128) -233 + j*(-210) --93 + j*(-184) --76 + j*(74) -112 + j*(35) -50 + j*(-95) --22 + j*(-21) -63 + j*(-1) -66 + j*(-93) -1 + j*(-117) --45 + j*(-119) --119 + j*(-73) --69 + j*(36) -47 + j*(-61) --136 + j*(-212) --364 + j*(19) --169 + j*(305) -76 + j*(196) -14 + j*(92) -61 + j*(190) -235 + j*(61) -98 + j*(-155) --96 + j*(-29) -35 + j*(119) -154 + j*(-23) -37 + j*(-140) --79 + j*(-98) --150 + j*(-16) --151 + j*(161) -73 + j*(278) -285 + j*(93) -202 + j*(-139) -32 + j*(-159) --49 + j*(-87) --57 + j*(21) -84 + j*(85) -197 + j*(-92) -2 + j*(-245) --152 + j*(-64) -23 + j*(43) -71 + j*(-156) --158 + j*(-175) --177 + j*(49) -2 + j*(60) --1 + j*(-68) --82 + j*(-66) --103 + j*(-56) --190 + j*(-33) --222 + j*(119) --102 + j*(221) --3 + j*(219) -112 + j*(226) -266 + j*(72) -149 + j*(-171) --91 + j*(-102) --21 + j*(69) -61 + j*(-51) --136 + j*(-63) --110 + j*(204) -182 + j*(163) -125 + j*(-103) --85 + j*(6) -95 + j*(177) -266 + j*(-32) -110 + j*(-194) -34 + j*(-147) -1 + j*(-245) --282 + j*(-225) --354 + j*(159) -15 + j*(309) -162 + j*(33) --21 + j*(-33) -23 + j*(92) -115 + j*(-56) --123 + j*(-117) --177 + j*(212) -219 + j*(306) -383 + j*(-83) -90 + j*(-290) --67 + j*(-128) -14 + j*(-94) --74 + j*(-182) --212 + j*(-44) --86 + j*(112) -40 + j*(11) --71 + j*(-66) --117 + j*(74) -45 + j*(103) -53 + j*(-76) --162 + j*(-62) --153 + j*(212) -172 + j*(257) -296 + j*(-73) -11 + j*(-260) --197 + j*(-38) --28 + j*(155) -134 + j*(14) -11 + j*(-101) --45 + j*(18) -98 + j*(8) -37 + j*(-184) --190 + j*(-105) --107 + j*(119) -73 + j*(1) --116 + j*(-134) --236 + j*(137) -83 + j*(258) -188 + j*(-74) --141 + j*(-133) --141 + j*(196) -178 + j*(144) -77 + j*(-153) --197 + j*(-9) --36 + j*(248) -184 + j*(119) -115 + j*(-14) -110 + j*(16) -146 + j*(-99) --31 + j*(-158) --87 + j*(29) -91 + j*(44) -52 + j*(-133) --122 + j*(-55) --30 + j*(98) -74 + j*(4) --31 + j*(-33) --4 + j*(100) -165 + j*(47) -131 + j*(-136) --23 + j*(-144) --62 + j*(-45) --7 + j*(18) -103 + j*(-16) -102 + j*(-202) --154 + j*(-264) --269 + j*(8) --14 + j*(118) -39 + j*(-144) --268 + j*(-148) --272 + j*(185) -19 + j*(200) --1 + j*(0) --125 + j*(96) -30 + j*(173) -55 + j*(-4) --146 + j*(56) --10 + j*(319) -322 + j*(182) -257 + j*(-162) --13 + j*(-180) --65 + j*(-35) --40 + j*(-1) --58 + j*(54) -21 + j*(128) -138 + j*(82) -168 + j*(-33) -116 + j*(-145) --39 + j*(-184) --156 + j*(-38) --47 + j*(105) -68 + j*(25) --13 + j*(-14) -35 + j*(111) -247 + j*(3) -142 + j*(-295) --182 + j*(-240) --173 + j*(28) -1 + j*(16) --51 + j*(-80) --89 + j*(-8) --27 + j*(-38) --166 + j*(-100) --269 + j*(147) -30 + j*(319) -247 + j*(24) --16 + j*(-187) --190 + j*(47) -23 + j*(173) -90 + j*(-25) --108 + j*(-33) --93 + j*(188) -130 + j*(202) -206 + j*(45) -183 + j*(-49) -161 + j*(-170) --33 + j*(-283) --267 + j*(-117) --189 + j*(159) -41 + j*(152) -41 + j*(3) --54 + j*(52) -41 + j*(136) -129 + j*(34) -35 + j*(-28) -20 + j*(85) -183 + j*(83) -219 + j*(-107) -69 + j*(-186) -3 + j*(-112) -37 + j*(-106) -4 + j*(-153) --51 + j*(-147) --91 + j*(-144) --175 + j*(-95) --158 + j*(46) --6 + j*(42) --35 + j*(-116) --227 + j*(-52) --151 + j*(165) -64 + j*(83) --52 + j*(-116) --252 + j*(39) --90 + j*(250) -103 + j*(104) --49 + j*(-39) --174 + j*(150) -37 + j*(317) -267 + j*(153) -196 + j*(-101) --31 + j*(-114) --81 + j*(76) -90 + j*(135) -138 + j*(-33) --36 + j*(-49) --8 + j*(163) -263 + j*(107) -215 + j*(-211) --100 + j*(-178) --57 + j*(99) -180 + j*(23) -81 + j*(-173) --51 + j*(-57) -98 + j*(-8) -91 + j*(-219) --158 + j*(-207) --163 + j*(16) --11 + j*(6) --74 + j*(-83) --141 + j*(24) --35 + j*(77) --21 + j*(10) --57 + j*(75) -102 + j*(112) -183 + j*(-119) --65 + j*(-275) --282 + j*(-79) --187 + j*(134) --65 + j*(109) --110 + j*(112) --45 + j*(265) -230 + j*(242) -305 + j*(-80) -11 + j*(-239) --171 + j*(6) -42 + j*(171) -181 + j*(-25) -2 + j*(-136) --69 + j*(27) -86 + j*(60) -97 + j*(-74) -13 + j*(-67) -77 + j*(-61) -39 + j*(-223) --218 + j*(-214) --292 + j*(66) --76 + j*(206) -69 + j*(94) -37 + j*(-4) --6 + j*(-4) -2 + j*(16) -38 + j*(-16) --6 + j*(-115) --191 + j*(-93) --235 + j*(159) -21 + j*(279) -175 + j*(70) -17 + j*(-56) --59 + j*(85) -85 + j*(141) -148 + j*(23) -102 + j*(-33) -99 + j*(-64) -39 + j*(-146) --107 + j*(-110) --124 + j*(42) --4 + j*(92) -40 + j*(16) --25 + j*(-8) --51 + j*(77) -54 + j*(139) -168 + j*(46) -113 + j*(-96) --28 + j*(-76) --30 + j*(47) -65 + j*(81) -136 + j*(57) -230 + j*(-17) -228 + j*(-216) -7 + j*(-314) --117 + j*(-148) -7 + j*(-106) --64 + j*(-285) --361 + j*(-161) --272 + j*(223) -129 + j*(195) -146 + j*(-167) --153 + j*(-218) --223 + j*(-16) --141 + j*(37) --156 + j*(42) --127 + j*(127) --32 + j*(117) --32 + j*(57) --54 + j*(74) --26 + j*(62) --93 + j*(35) --158 + j*(176) -22 + j*(332) -271 + j*(197) -228 + j*(-80) --19 + j*(-112) --82 + j*(104) -122 + j*(197) -270 + j*(11) -146 + j*(-187) --59 + j*(-143) --78 + j*(24) -31 + j*(86) -126 + j*(44) -180 + j*(-72) -92 + j*(-243) --170 + j*(-241) --284 + j*(40) --55 + j*(232) -149 + j*(73) -33 + j*(-94) --103 + j*(19) -11 + j*(149) -144 + j*(65) -103 + j*(-41) -56 + j*(-19) -107 + j*(-18) -112 + j*(-110) -12 + j*(-151) --49 + j*(-78) -7 + j*(-21) -65 + j*(-89) --4 + j*(-190) --156 + j*(-168) --218 + j*(-20) --136 + j*(106) --19 + j*(116) -57 + j*(67) -105 + j*(-18) -68 + j*(-156) --119 + j*(-213) --281 + j*(-46) --193 + j*(177) -11 + j*(179) -53 + j*(48) --5 + j*(34) -45 + j*(67) -104 + j*(-28) -14 + j*(-131) --103 + j*(-93) --124 + j*(-23) --140 + j*(9) --147 + j*(88) --59 + j*(136) --20 + j*(49) --163 + j*(47) --187 + j*(293) -126 + j*(425) -369 + j*(152) -197 + j*(-113) --4 + j*(-4) -114 + j*(127) -217 + j*(-8) -110 + j*(-86) -119 + j*(-16) -207 + j*(-158) --29 + j*(-351) --351 + j*(-115) --214 + j*(274) -127 + j*(270) -202 + j*(71) -164 + j*(25) -209 + j*(-23) -180 + j*(-123) -125 + j*(-127) -163 + j*(-175) -66 + j*(-309) --121 + j*(-241) --70 + j*(-93) -13 + j*(-209) --196 + j*(-296) --332 + j*(-61) --144 + j*(71) --88 + j*(-83) --279 + j*(-66) --269 + j*(167) --64 + j*(204) --10 + j*(82) --59 + j*(57) --69 + j*(72) --88 + j*(90) --69 + j*(161) -24 + j*(179) -76 + j*(122) -96 + j*(81) -103 + j*(7) -4 + j*(-44) --62 + j*(68) -54 + j*(134) -95 + j*(29) -12 + j*(61) -164 + j*(158) -338 + j*(-107) -28 + j*(-395) --340 + j*(-124) --163 + j*(250) -137 + j*(159) -92 + j*(-22) -24 + j*(29) -103 + j*(35) -98 + j*(-47) -66 + j*(-48) -89 + j*(-93) --3 + j*(-174) --129 + j*(-92) --98 + j*(28) --38 + j*(42) --7 + j*(63) -78 + j*(34) -50 + j*(-86) --81 + j*(-46) --16 + j*(85) -103 + j*(-8) --16 + j*(-98) --54 + j*(54) -149 + j*(39) -102 + j*(-221) --192 + j*(-181) --167 + j*(105) -78 + j*(81) -42 + j*(-127) --145 + j*(-88) --132 + j*(79) -8 + j*(108) -81 + j*(4) -7 + j*(-110) --141 + j*(-67) --123 + j*(97) -32 + j*(84) --13 + j*(-54) --156 + j*(39) --35 + j*(213) -158 + j*(103) -86 + j*(-72) --36 + j*(-31) --8 + j*(33) -12 + j*(3) --18 + j*(3) --26 + j*(21) --40 + j*(49) --1 + j*(110) -91 + j*(77) -57 + j*(-6) -1 + j*(72) -150 + j*(144) -295 + j*(-41) -176 + j*(-265) --59 + j*(-291) --229 + j*(-135) --201 + j*(130) -114 + j*(213) -281 + j*(-125) --55 + j*(-348) --282 + j*(-45) --9 + j*(112) -31 + j*(-186) --354 + j*(-137) --294 + j*(325) -173 + j*(303) -168 + j*(-91) --138 + j*(-62) --81 + j*(177) -95 + j*(133) -79 + j*(59) -144 + j*(83) -242 + j*(-95) -37 + j*(-299) --247 + j*(-161) --223 + j*(132) -5 + j*(216) -146 + j*(88) -110 + j*(-48) -15 + j*(-57) -13 + j*(1) -62 + j*(-21) -42 + j*(-80) --10 + j*(-93) --57 + j*(-95) --132 + j*(-48) --117 + j*(71) --4 + j*(81) --21 + j*(-1) --98 + j*(76) -10 + j*(199) -175 + j*(142) -238 + j*(12) -245 + j*(-152) -62 + j*(-344) --260 + j*(-221) --199 + j*(131) -117 + j*(80) -23 + j*(-192) --208 + j*(-39) --1 + j*(132) -88 + j*(-134) --250 + j*(-153) --228 + j*(236) -160 + j*(183) -52 + j*(-163) --254 + j*(30) -9 + j*(329) -326 + j*(51) -100 + j*(-272) --187 + j*(-156) --197 + j*(35) --144 + j*(139) --6 + j*(221) -158 + j*(98) -41 + j*(-88) --153 + j*(50) --9 + j*(281) -256 + j*(204) -310 + j*(-22) -224 + j*(-184) -53 + j*(-279) --167 + j*(-194) --196 + j*(51) --12 + j*(165) -132 + j*(88) -176 + j*(-17) -170 + j*(-149) -28 + j*(-263) --156 + j*(-184) --144 + j*(-11) --22 + j*(-8) --47 + j*(-112) --171 + j*(-77) --164 + j*(60) --51 + j*(81) --47 + j*(-8) --152 + j*(21) --140 + j*(176) -28 + j*(229) -139 + j*(130) -151 + j*(42) -165 + j*(-37) -103 + j*(-161) --70 + j*(-179) --158 + j*(-38) --97 + j*(66) --30 + j*(76) -13 + j*(75) -59 + j*(37) -47 + j*(-21) -20 + j*(-23) -34 + j*(-53) --50 + j*(-124) --206 + j*(-18) --139 + j*(218) -118 + j*(235) -202 + j*(41) -112 + j*(-37) -115 + j*(-7) -166 + j*(-97) -34 + j*(-267) --239 + j*(-119) --108 + j*(65) --68 + j*(-85) --296 + j*(1) --157 + j*(327) -224 + j*(201) -135 + j*(-182) --231 + j*(-141) --275 + j*(192) --20 + j*(354) -240 + j*(245) -291 + j*(-37) -54 + j*(-195) --135 + j*(-11) -25 + j*(170) -205 + j*(23) -100 + j*(-162) --71 + j*(-133) --131 + j*(-20) --115 + j*(113) -40 + j*(216) -250 + j*(104) -235 + j*(-154) -15 + j*(-248) --147 + j*(-132) --148 + j*(35) --17 + j*(121) -110 + j*(30) -44 + j*(-112) --106 + j*(-56) --55 + j*(97) -101 + j*(49) -62 + j*(-112) --109 + j*(-88) --120 + j*(91) -51 + j*(150) -152 + j*(11) -57 + j*(-103) --35 + j*(-41) -23 + j*(16) -52 + j*(-61) --41 + j*(-70) --28 + j*(37) -96 + j*(8) -76 + j*(-127) --33 + j*(-134) --47 + j*(-99) --90 + j*(-128) --177 + j*(-52) --112 + j*(59) --25 + j*(-8) --124 + j*(-69) --187 + j*(62) --61 + j*(129) --21 + j*(21) --146 + j*(18) --155 + j*(183) -16 + j*(247) -124 + j*(129) -52 + j*(31) --17 + j*(124) -143 + j*(221) -337 + j*(25) -185 + j*(-251) --93 + j*(-180) --52 + j*(13) -37 + j*(-83) --168 + j*(-117) --214 + j*(187) -127 + j*(282) -261 + j*(-25) -44 + j*(-146) --10 + j*(-31) -24 + j*(-95) --183 + j*(-95) --222 + j*(240) -168 + j*(390) -433 + j*(71) -298 + j*(-221) -113 + j*(-276) --38 + j*(-285) --211 + j*(-148) --129 + j*(102) -140 + j*(42) -71 + j*(-243) --246 + j*(-169) --197 + j*(172) -141 + j*(163) -176 + j*(-131) --39 + j*(-188) --71 + j*(-68) --6 + j*(-113) --122 + j*(-194) --250 + j*(-72) --182 + j*(49) --130 + j*(2) --233 + j*(1) --279 + j*(167) --152 + j*(306) -4 + j*(311) -115 + j*(258) -196 + j*(161) -183 + j*(35) -96 + j*(2) -91 + j*(52) -163 + j*(17) -135 + j*(-98) -13 + j*(-98) -6 + j*(10) -126 + j*(-1) -124 + j*(-168) --72 + j*(-218) --180 + j*(-43) --50 + j*(76) -38 + j*(-34) --102 + j*(-103) --193 + j*(77) --8 + j*(222) -180 + j*(76) -91 + j*(-114) --70 + j*(-62) --25 + j*(64) -83 + j*(8) -17 + j*(-104) --108 + j*(-43) --68 + j*(95) -66 + j*(85) -87 + j*(-28) -7 + j*(-65) --32 + j*(-13) -8 + j*(21) -50 + j*(-14) -21 + j*(-77) --58 + j*(-66) --64 + j*(24) -18 + j*(32) -10 + j*(-45) --84 + j*(0) --7 + j*(138) -182 + j*(66) -154 + j*(-149) --35 + j*(-161) --43 + j*(-35) -47 + j*(-86) --53 + j*(-212) --228 + j*(-121) --199 + j*(75) --38 + j*(105) --4 + j*(0) --91 + j*(-20) --118 + j*(69) --45 + j*(129) -31 + j*(110) -70 + j*(59) -72 + j*(-11) -1 + j*(-50) --55 + j*(21) -40 + j*(91) -129 + j*(-38) --18 + j*(-161) --184 + j*(-22) --86 + j*(154) -49 + j*(109) -23 + j*(70) -81 + j*(145) -249 + j*(54) -211 + j*(-182) --6 + j*(-238) --119 + j*(-112) --94 + j*(-16) --45 + j*(4) --40 + j*(-24) --111 + j*(-7) --115 + j*(140) -83 + j*(215) -242 + j*(36) -144 + j*(-174) --55 + j*(-186) --177 + j*(-56) --151 + j*(151) -97 + j*(248) -300 + j*(8) -105 + j*(-250) --141 + j*(-107) --28 + j*(91) -112 + j*(-6) -44 + j*(-77) -77 + j*(-43) -118 + j*(-206) --136 + j*(-317) --323 + j*(-78) --179 + j*(105) --104 + j*(43) --173 + j*(98) --71 + j*(229) -88 + j*(177) -116 + j*(83) -140 + j*(18) -84 + j*(-103) --86 + j*(-54) --16 + j*(139) -209 + j*(42) -120 + j*(-204) --91 + j*(-161) --88 + j*(-69) --161 + j*(-97) --286 + j*(111) --36 + j*(347) -242 + j*(135) -69 + j*(-81) --37 + j*(124) -262 + j*(174) -354 + j*(-204) -2 + j*(-390) --237 + j*(-170) --171 + j*(34) --58 + j*(66) --5 + j*(24) --40 + j*(-21) --98 + j*(57) -17 + j*(168) -192 + j*(62) -145 + j*(-131) -6 + j*(-157) --46 + j*(-134) --132 + j*(-122) --197 + j*(14) --73 + j*(123) -19 + j*(25) --85 + j*(-29) --125 + j*(93) --18 + j*(140) -16 + j*(88) -4 + j*(108) -71 + j*(125) -114 + j*(65) -103 + j*(39) -145 + j*(17) -142 + j*(-93) -8 + j*(-139) --78 + j*(-27) --11 + j*(73) -76 + j*(73) -147 + j*(40) -218 + j*(-68) -157 + j*(-252) --81 + j*(-305) --247 + j*(-103) --129 + j*(117) -89 + j*(69) -76 + j*(-133) --103 + j*(-138) --116 + j*(15) --3 + j*(2) --71 + j*(-87) --168 + j*(54) -42 + j*(187) -231 + j*(-71) --33 + j*(-334) --361 + j*(-124) --255 + j*(204) --13 + j*(185) --21 + j*(64) --66 + j*(123) -37 + j*(165) -95 + j*(77) -58 + j*(33) -67 + j*(37) -74 + j*(-26) --30 + j*(-59) --108 + j*(63) -1 + j*(209) -211 + j*(170) -277 + j*(-49) -127 + j*(-202) --37 + j*(-149) --49 + j*(-40) --4 + j*(-18) -2 + j*(-22) -18 + j*(-16) -25 + j*(-37) -17 + j*(-31) -79 + j*(-47) -69 + j*(-206) --183 + j*(-267) --346 + j*(2) --140 + j*(216) -21 + j*(79) --124 + j*(21) --123 + j*(237) -144 + j*(259) -203 + j*(23) -47 + j*(-21) -65 + j*(90) -180 + j*(37) -152 + j*(-79) -76 + j*(-94) -55 + j*(-66) -95 + j*(-49) -170 + j*(-146) -53 + j*(-356) --285 + j*(-315) --371 + j*(47) --97 + j*(212) -49 + j*(59) --17 + j*(-6) --7 + j*(9) --35 + j*(-49) --129 + j*(38) -21 + j*(176) -208 + j*(-23) -5 + j*(-260) --254 + j*(-107) --191 + j*(100) --117 + j*(107) --118 + j*(190) -64 + j*(272) -217 + j*(83) -73 + j*(-70) --32 + j*(52) -101 + j*(117) -176 + j*(-16) -87 + j*(-118) --18 + j*(-108) --82 + j*(-35) --58 + j*(65) -35 + j*(84) -73 + j*(41) -102 + j*(31) -163 + j*(-49) -85 + j*(-190) --89 + j*(-156) --95 + j*(-13) --11 + j*(-6) --22 + j*(-48) --49 + j*(-43) --93 + j*(-39) --145 + j*(78) -29 + j*(209) -235 + j*(17) -60 + j*(-231) --168 + j*(-93) --69 + j*(47) --81 + j*(-54) --246 + j*(132) -73 + j*(419) -487 + j*(60) -174 + j*(-421) --269 + j*(-190) --85 + j*(129) -81 + j*(-65) --154 + j*(-115) --136 + j*(141) -96 + j*(64) --59 + j*(-118) --215 + j*(124) -84 + j*(286) -255 + j*(-15) --16 + j*(-170) --146 + j*(68) -57 + j*(194) -195 + j*(58) -163 + j*(-68) -100 + j*(-120) -36 + j*(-140) --8 + j*(-136) --66 + j*(-155) --198 + j*(-103) --226 + j*(107) --17 + j*(230) -150 + j*(91) -87 + j*(-49) -8 + j*(-22) -44 + j*(16) -93 + j*(-31) -83 + j*(-126) --42 + j*(-206) --228 + j*(-101) --180 + j*(163) -112 + j*(176) -170 + j*(-102) --66 + j*(-179) --119 + j*(-8) -2 + j*(-32) --122 + j*(-159) --315 + j*(13) --185 + j*(263) -39 + j*(226) -61 + j*(107) -42 + j*(103) -80 + j*(82) -66 + j*(42) -73 + j*(47) -92 + j*(-11) --8 + j*(-42) --36 + j*(92) -136 + j*(116) -161 + j*(-85) --52 + j*(-107) --78 + j*(107) -115 + j*(158) -198 + j*(37) -206 + j*(-30) -233 + j*(-147) -105 + j*(-296) --91 + j*(-243) --107 + j*(-116) --93 + j*(-111) --156 + j*(-58) --100 + j*(51) --8 + j*(5) --76 + j*(-36) --76 + j*(80) -89 + j*(67) -88 + j*(-130) --109 + j*(-154) --163 + j*(4) --71 + j*(72) --11 + j*(50) -28 + j*(6) -4 + j*(-98) --163 + j*(-115) --266 + j*(84) --107 + j*(284) -148 + j*(235) -229 + j*(-1) -65 + j*(-182) --173 + j*(-113) --206 + j*(139) -15 + j*(269) -215 + j*(127) -177 + j*(-83) -16 + j*(-129) --66 + j*(-47) --53 + j*(12) --54 + j*(39) --33 + j*(121) -116 + j*(142) -199 + j*(-38) -25 + j*(-173) --127 + j*(-29) --23 + j*(112) -71 + j*(55) -71 + j*(41) -174 + j*(1) -127 + j*(-229) --209 + j*(-211) --235 + j*(178) -154 + j*(242) -226 + j*(-96) --25 + j*(-138) --1 + j*(19) -86 + j*(-87) --87 + j*(-129) --107 + j*(76) -92 + j*(91) -117 + j*(-59) -75 + j*(-100) -46 + j*(-206) --205 + j*(-226) --292 + j*(119) -88 + j*(243) -202 + j*(-139) --165 + j*(-208) --170 + j*(136) -146 + j*(70) -25 + j*(-223) --239 + j*(-89) --125 + j*(107) --38 + j*(11) --151 + j*(28) --81 + j*(168) -54 + j*(91) --25 + j*(-14) --119 + j*(71) --67 + j*(187) -62 + j*(231) -211 + j*(141) -182 + j*(-53) -4 + j*(-33) -92 + j*(132) -301 + j*(-38) -110 + j*(-316) --187 + j*(-183) --132 + j*(46) --33 + j*(34) --54 + j*(67) -66 + j*(127) -159 + j*(-26) -22 + j*(-117) --34 + j*(-18) -18 + j*(-16) --23 + j*(-11) -64 + j*(69) -196 + j*(-114) --57 + j*(-320) --330 + j*(-72) --152 + j*(192) --2 + j*(98) --83 + j*(132) -121 + j*(293) -404 + j*(18) -167 + j*(-352) --204 + j*(-215) --169 + j*(91) -43 + j*(148) -187 + j*(39) -197 + j*(-179) --52 + j*(-305) --244 + j*(-71) --23 + j*(115) -124 + j*(-132) --166 + j*(-276) --333 + j*(7) --122 + j*(169) --35 + j*(35) --150 + j*(45) --89 + j*(186) -71 + j*(132) -36 + j*(-23) --124 + j*(-6) --153 + j*(177) -23 + j*(295) -215 + j*(187) -194 + j*(6) -92 + j*(1) -140 + j*(35) -164 + j*(-89) -0 + j*(-136) --56 + j*(47) -154 + j*(107) -251 + j*(-138) -10 + j*(-301) --205 + j*(-109) --66 + j*(111) -130 + j*(-16) --21 + j*(-204) --230 + j*(-14) --6 + j*(218) -248 + j*(-33) --30 + j*(-313) --336 + j*(-28) --74 + j*(287) -214 + j*(66) -23 + j*(-171) --169 + j*(6) --18 + j*(186) -165 + j*(110) -215 + j*(-51) -141 + j*(-221) --84 + j*(-267) --209 + j*(-71) --64 + j*(42) --12 + j*(-101) --207 + j*(-122) --271 + j*(94) --121 + j*(217) --10 + j*(194) -59 + j*(175) -134 + j*(99) -99 + j*(0) -27 + j*(18) -67 + j*(83) -180 + j*(54) -252 + j*(-110) -118 + j*(-344) --245 + j*(-345) --413 + j*(30) --139 + j*(291) -91 + j*(139) --4 + j*(32) -15 + j*(153) -206 + j*(59) -92 + j*(-194) --200 + j*(-92) --145 + j*(218) -156 + j*(247) -284 + j*(16) -176 + j*(-186) --37 + j*(-201) --136 + j*(-23) -21 + j*(102) -150 + j*(-71) --67 + j*(-228) --292 + j*(19) --73 + j*(336) -310 + j*(216) -332 + j*(-157) -56 + j*(-287) --94 + j*(-136) --10 + j*(-37) -43 + j*(-132) --78 + j*(-206) --198 + j*(-115) --190 + j*(-6) --173 + j*(41) --153 + j*(139) -8 + j*(206) -163 + j*(44) -36 + j*(-164) --196 + j*(-98) --203 + j*(114) --78 + j*(181) --26 + j*(182) -62 + j*(232) -237 + j*(156) -251 + j*(-74) -62 + j*(-168) --41 + j*(-62) -3 + j*(-13) --21 + j*(-46) --76 + j*(36) -42 + j*(139) -205 + j*(18) -135 + j*(-199) --91 + j*(-214) --186 + j*(-43) --100 + j*(76) --15 + j*(37) --72 + j*(-13) --146 + j*(102) --11 + j*(252) -202 + j*(170) -194 + j*(-18) -103 + j*(-23) -181 + j*(-23) -166 + j*(-228) --115 + j*(-272) --225 + j*(10) -1 + j*(140) -100 + j*(-16) --1 + j*(-50) -47 + j*(25) -138 + j*(-90) -16 + j*(-223) --127 + j*(-161) --138 + j*(-84) --164 + j*(-64) --204 + j*(10) --188 + j*(89) --175 + j*(176) --53 + j*(317) -230 + j*(272) -305 + j*(-43) -55 + j*(-187) --64 + j*(-13) -90 + j*(30) -88 + j*(-156) --129 + j*(-174) --196 + j*(16) --98 + j*(94) --83 + j*(88) --60 + j*(185) -122 + j*(215) -223 + j*(18) -56 + j*(-102) --25 + j*(59) -197 + j*(101) -256 + j*(-204) --93 + j*(-337) --296 + j*(-22) --63 + j*(194) -100 + j*(45) --1 + j*(-23) -26 + j*(77) -159 + j*(-20) -41 + j*(-190) --141 + j*(-94) --85 + j*(64) -17 + j*(31) --13 + j*(-13) --18 + j*(30) -35 + j*(13) -6 + j*(-37) --47 + j*(8) -11 + j*(77) -110 + j*(32) -112 + j*(-88) -20 + j*(-143) --46 + j*(-119) --78 + j*(-110) --158 + j*(-88) --196 + j*(45) --78 + j*(132) -3 + j*(45) --91 + j*(6) --100 + j*(129) -20 + j*(136) --5 + j*(57) --52 + j*(176) -173 + j*(255) -332 + j*(-16) -96 + j*(-234) --121 + j*(-66) --5 + j*(100) -100 + j*(18) -38 + j*(-21) -70 + j*(42) -169 + j*(-37) -86 + j*(-180) --71 + j*(-134) --54 + j*(-3) -48 + j*(-19) -24 + j*(-111) --67 + j*(-94) --61 + j*(-22) --18 + j*(-33) --43 + j*(-50) --28 + j*(-21) -10 + j*(-98) --150 + j*(-191) --346 + j*(9) --187 + j*(305) -134 + j*(229) -122 + j*(-38) --75 + j*(-45) --81 + j*(108) -35 + j*(128) -87 + j*(60) -73 + j*(-12) --1 + j*(-37) --43 + j*(38) -37 + j*(85) -69 + j*(6) --5 + j*(9) -47 + j*(98) -168 + j*(11) -84 + j*(-131) --36 + j*(-69) -14 + j*(-11) -0 + j*(-80) --106 + j*(-10) --7 + j*(136) -168 + j*(38) -94 + j*(-140) --55 + j*(-88) -1 + j*(16) -88 + j*(-73) --23 + j*(-194) --198 + j*(-105) --177 + j*(92) --8 + j*(129) -30 + j*(16) --53 + j*(25) -8 + j*(119) -132 + j*(45) -78 + j*(-69) -28 + j*(-37) -82 + j*(-84) --40 + j*(-209) --239 + j*(-71) --139 + j*(154) -50 + j*(103) -24 + j*(-12) --9 + j*(5) --3 + j*(-36) --116 + j*(-28) --100 + j*(141) -89 + j*(119) -43 + j*(-52) --103 + j*(43) -37 + j*(163) -112 + j*(13) --36 + j*(25) -91 + j*(203) -330 + j*(-5) -105 + j*(-291) --171 + j*(-92) -3 + j*(132) -169 + j*(-21) -66 + j*(-124) -59 + j*(-92) -61 + j*(-216) --166 + j*(-260) --288 + j*(-28) --144 + j*(124) --42 + j*(82) --34 + j*(65) -1 + j*(53) --16 + j*(18) --38 + j*(60) -28 + j*(83) -56 + j*(20) -27 + j*(11) -66 + j*(15) -75 + j*(-78) --39 + j*(-118) --107 + j*(-30) --64 + j*(39) --19 + j*(25) --37 + j*(-17) --118 + j*(4) --134 + j*(147) -31 + j*(228) -143 + j*(97) -49 + j*(32) -76 + j*(151) -277 + j*(72) -225 + j*(-197) --33 + j*(-203) --60 + j*(-19) -44 + j*(-20) --1 + j*(-74) --28 + j*(-5) -49 + j*(11) -67 + j*(-62) -25 + j*(-95) --18 + j*(-107) --86 + j*(-66) --52 + j*(37) -77 + j*(2) -51 + j*(-151) --102 + j*(-160) --155 + j*(-52) --123 + j*(10) --77 + j*(35) --37 + j*(-19) --151 + j*(-78) --279 + j*(107) --80 + j*(320) -166 + j*(162) -40 + j*(-37) --87 + j*(115) -116 + j*(214) -234 + j*(-7) -59 + j*(-147) --79 + j*(-52) --74 + j*(62) -0 + j*(154) -177 + j*(139) -238 + j*(-76) -45 + j*(-194) --65 + j*(-65) -10 + j*(-18) --23 + j*(-69) --79 + j*(30) -66 + j*(104) -166 + j*(-57) -38 + j*(-192) --109 + j*(-149) --170 + j*(-40) --140 + j*(96) -20 + j*(132) -81 + j*(-31) --105 + j*(-83) --165 + j*(148) -92 + j*(245) -236 + j*(13) -61 + j*(-146) --80 + j*(-19) -27 + j*(107) -159 + j*(11) -81 + j*(-136) --73 + j*(-70) -13 + j*(98) -228 + j*(-10) -141 + j*(-288) --147 + j*(-269) --175 + j*(-65) --96 + j*(-78) --225 + j*(-78) --224 + j*(160) -59 + j*(181) -83 + j*(-113) --226 + j*(-141) --305 + j*(163) --93 + j*(317) -67 + j*(287) -216 + j*(245) -365 + j*(32) -216 + j*(-264) --116 + j*(-228) --151 + j*(48) -54 + j*(88) -63 + j*(-82) --107 + j*(-66) --95 + j*(116) -88 + j*(127) -116 + j*(-40) --36 + j*(-79) --89 + j*(66) -40 + j*(155) -170 + j*(84) -196 + j*(-43) -141 + j*(-147) -37 + j*(-197) --66 + j*(-172) --134 + j*(-96) --136 + j*(9) --40 + j*(70) -35 + j*(-16) --76 + j*(-89) --170 + j*(64) -11 + j*(190) -152 + j*(13) --12 + j*(-109) --90 + j*(52) -77 + j*(80) -54 + j*(-91) --123 + j*(-16) --5 + j*(180) -223 + j*(46) -123 + j*(-204) --119 + j*(-177) --174 + j*(16) --52 + j*(139) -118 + j*(87) -125 + j*(-110) --74 + j*(-159) --132 + j*(8) --10 + j*(21) --101 + j*(-79) --238 + j*(122) -15 + j*(330) -260 + j*(115) -121 + j*(-69) -85 + j*(38) -250 + j*(-74) -77 + j*(-341) --238 + j*(-199) --146 + j*(61) -8 + j*(-41) --161 + j*(-130) --271 + j*(75) --132 + j*(226) --8 + j*(225) -101 + j*(228) -247 + j*(119) -230 + j*(-91) -74 + j*(-165) --19 + j*(-128) --75 + j*(-95) --127 + j*(-25) --117 + j*(65) --79 + j*(142) -49 + j*(235) -298 + j*(139) -308 + j*(-222) --73 + j*(-368) --323 + j*(-56) --135 + j*(231) -115 + j*(166) -129 + j*(3) -47 + j*(-31) -39 + j*(25) -129 + j*(23) -165 + j*(-124) -3 + j*(-222) --131 + j*(-92) --35 + j*(14) -15 + j*(-88) --119 + j*(-105) --146 + j*(41) --48 + j*(86) --21 + j*(86) -78 + j*(122) -211 + j*(-35) -49 + j*(-244) --173 + j*(-111) --52 + j*(62) -48 + j*(-91) --158 + j*(-151) --210 + j*(82) -1 + j*(119) --11 + j*(-60) --188 + j*(6) --103 + j*(201) -93 + j*(146) -90 + j*(-23) --31 + j*(-64) --115 + j*(-6) --129 + j*(91) --73 + j*(156) --34 + j*(175) -8 + j*(250) -199 + j*(287) -373 + j*(81) -259 + j*(-160) -71 + j*(-150) -55 + j*(-83) -28 + j*(-115) --59 + j*(-50) -13 + j*(64) -136 + j*(-8) -74 + j*(-134) --45 + j*(-95) --34 + j*(8) -62 + j*(33) -138 + j*(-57) -73 + j*(-204) --126 + j*(-192) --165 + j*(19) -34 + j*(80) -88 + j*(-112) --105 + j*(-161) --154 + j*(27) -13 + j*(75) -53 + j*(-72) --76 + j*(-108) --110 + j*(0) --18 + j*(25) -4 + j*(-70) --103 + j*(-115) --195 + j*(-31) --182 + j*(82) --122 + j*(148) --19 + j*(197) -145 + j*(121) -130 + j*(-141) --204 + j*(-209) --380 + j*(159) --49 + j*(431) -254 + j*(199) -109 + j*(-46) --40 + j*(69) -76 + j*(146) -103 + j*(42) -23 + j*(88) -150 + j*(185) -306 + j*(30) -202 + j*(-156) -64 + j*(-117) -97 + j*(-59) -127 + j*(-127) -59 + j*(-185) --7 + j*(-177) --52 + j*(-165) --100 + j*(-148) --152 + j*(-111) --204 + j*(-42) --206 + j*(82) --100 + j*(183) -35 + j*(167) -95 + j*(85) -105 + j*(21) -103 + j*(-40) -58 + j*(-119) --71 + j*(-144) --182 + j*(-22) --114 + j*(151) -64 + j*(158) -118 + j*(35) -75 + j*(-1) -117 + j*(-11) -117 + j*(-136) --44 + j*(-187) --122 + j*(-53) --40 + j*(-3) --56 + j*(-62) --124 + j*(5) --46 + j*(85) -11 + j*(18) --49 + j*(7) --18 + j*(71) -37 + j*(21) --21 + j*(4) -23 + j*(83) -139 + j*(-21) -6 + j*(-177) --162 + j*(-49) --58 + j*(91) -13 + j*(4) --66 + j*(15) -26 + j*(85) -84 + j*(-81) --144 + j*(-136) --197 + j*(111) -9 + j*(126) --88 + j*(-19) --234 + j*(235) -132 + j*(465) -454 + j*(116) -223 + j*(-209) -18 + j*(-98) -71 + j*(-66) --54 + j*(-120) --129 + j*(120) -187 + j*(238) -367 + j*(-93) -122 + j*(-313) --61 + j*(-222) --101 + j*(-175) --223 + j*(-97) --185 + j*(135) -59 + j*(154) -94 + j*(-38) --36 + j*(-45) --3 + j*(41) -57 + j*(-8) -19 + j*(-36) -42 + j*(-23) -47 + j*(-97) --47 + j*(-107) --39 + j*(-42) --11 + j*(-113) --172 + j*(-134) --220 + j*(83) -5 + j*(147) -57 + j*(-65) --144 + j*(-103) --192 + j*(58) --134 + j*(111) --146 + j*(188) -15 + j*(324) -254 + j*(173) -148 + j*(-80) --52 + j*(23) -94 + j*(183) -257 + j*(17) -134 + j*(-141) -34 + j*(-82) -66 + j*(-64) -51 + j*(-109) -25 + j*(-139) --74 + j*(-213) --311 + j*(-86) --231 + j*(309) -259 + j*(319) -364 + j*(-181) --62 + j*(-348) --226 + j*(-56) --77 + j*(29) --122 + j*(-21) --134 + j*(138) -69 + j*(139) -33 + j*(-44) --113 + j*(81) -110 + j*(214) -250 + j*(-69) --32 + j*(-199) --103 + j*(50) -117 + j*(23) --11 + j*(-203) --255 + j*(-18) --77 + j*(229) -121 + j*(95) -27 + j*(-4) -33 + j*(86) -142 + j*(11) -57 + j*(-103) --25 + j*(-51) --18 + j*(-39) --105 + j*(-1) --42 + j*(191) -243 + j*(138) -227 + j*(-188) --71 + j*(-205) --73 + j*(17) -75 + j*(-42) --54 + j*(-156) --165 + j*(5) --11 + j*(103) -47 + j*(-25) --75 + j*(-35) --68 + j*(111) -99 + j*(136) -199 + j*(-17) -103 + j*(-174) --64 + j*(-142) --41 + j*(-4) -87 + j*(-76) --41 + j*(-238) --248 + j*(-98) --129 + j*(101) -1 + j*(-13) --146 + j*(-62) --127 + j*(126) -78 + j*(33) --100 + j*(-194) --372 + j*(47) --139 + j*(343) -95 + j*(155) --95 + j*(54) --81 + j*(323) -264 + j*(278) -234 + j*(-66) --50 + j*(-19) -48 + j*(223) -284 + j*(112) -224 + j*(-91) -134 + j*(-91) -138 + j*(-142) --8 + j*(-211) --136 + j*(-45) -19 + j*(98) -153 + j*(-49) -11 + j*(-176) --105 + j*(-61) --22 + j*(21) -2 + j*(-51) --99 + j*(-24) --56 + j*(127) -128 + j*(113) -160 + j*(-46) -81 + j*(-84) -115 + j*(-97) -65 + j*(-268) --238 + j*(-262) --328 + j*(115) -54 + j*(303) -318 + j*(-23) -104 + j*(-321) --145 + j*(-260) --211 + j*(-163) --313 + j*(-78) --312 + j*(160) --65 + j*(249) -25 + j*(66) --114 + j*(55) --45 + j*(205) -119 + j*(95) --11 + j*(-44) --98 + j*(122) -107 + j*(158) -88 + j*(-76) --170 + j*(13) --18 + j*(310) -313 + j*(129) -136 + j*(-189) --126 + j*(-7) -83 + j*(190) -230 + j*(-31) -31 + j*(-122) -38 + j*(31) -165 + j*(-95) --62 + j*(-211) --161 + j*(81) -185 + j*(142) -208 + j*(-250) --206 + j*(-253) --192 + j*(141) -153 + j*(92) -63 + j*(-202) --186 + j*(-95) --95 + j*(91) -0 + j*(26) --43 + j*(40) -65 + j*(83) -115 + j*(-91) --76 + j*(-152) --131 + j*(6) --35 + j*(12) --111 + j*(-40) --175 + j*(98) --62 + j*(197) -20 + j*(194) -148 + j*(226) -348 + j*(36) -168 + j*(-298) --222 + j*(-152) --85 + j*(243) -297 + j*(108) -188 + j*(-240) --70 + j*(-167) -7 + j*(-41) -28 + j*(-183) --185 + j*(-180) --223 + j*(41) --71 + j*(119) -10 + j*(57) -11 + j*(-16) --75 + j*(-59) --168 + j*(67) --23 + j*(224) -180 + j*(88) -67 + j*(-110) --99 + j*(-6) -11 + j*(132) -138 + j*(37) -91 + j*(-74) -19 + j*(-91) --42 + j*(-75) --66 + j*(5) -25 + j*(30) -19 + j*(-80) --114 + j*(-31) --13 + j*(120) -162 + j*(-45) --66 + j*(-266) --356 + j*(-14) --152 + j*(330) -183 + j*(220) -167 + j*(-35) -26 + j*(-68) --13 + j*(-28) --38 + j*(4) --9 + j*(59) -47 + j*(23) --9 + j*(-20) --32 + j*(76) -98 + j*(88) -107 + j*(-59) --37 + j*(-49) -12 + j*(94) -174 + j*(8) -88 + j*(-179) --100 + j*(-131) --91 + j*(10) --30 + j*(9) --70 + j*(28) --10 + j*(131) -158 + j*(77) -141 + j*(-124) --57 + j*(-151) --112 + j*(18) -19 + j*(88) -95 + j*(-1) -59 + j*(-68) -23 + j*(-81) --15 + j*(-88) --47 + j*(-52) --13 + j*(-25) -2 + j*(-80) --78 + j*(-100) --107 + j*(-23) --51 + j*(-14) --87 + j*(-75) --187 + j*(-18) --170 + j*(98) --112 + j*(129) --97 + j*(177) -15 + j*(250) -170 + j*(165) -148 + j*(12) -64 + j*(20) -124 + j*(47) -161 + j*(-74) -35 + j*(-153) --64 + j*(-81) --49 + j*(-13) --33 + j*(-3) --28 + j*(11) --21 + j*(12) --44 + j*(30) --15 + j*(107) -117 + j*(91) -134 + j*(-70) --36 + j*(-107) --75 + j*(66) -117 + j*(116) -204 + j*(-89) -24 + j*(-230) --148 + j*(-127) --139 + j*(30) --41 + j*(98) -69 + j*(69) -103 + j*(-61) --25 + j*(-137) --119 + j*(-23) --18 + j*(52) -8 + j*(-64) --153 + j*(-33) --83 + j*(189) -197 + j*(93) -86 + j*(-235) --293 + j*(-129) --226 + j*(281) -158 + j*(278) -195 + j*(-12) -13 + j*(-35) -42 + j*(86) -158 + j*(42) -163 + j*(-66) -129 + j*(-132) -66 + j*(-199) --32 + j*(-218) --116 + j*(-207) --245 + j*(-177) --373 + j*(11) --266 + j*(280) -18 + j*(331) -182 + j*(159) -158 + j*(-23) -15 + j*(-107) --128 + j*(-4) --47 + j*(170) -136 + j*(105) -69 + j*(-54) --55 + j*(49) -98 + j*(155) -208 + j*(-11) -83 + j*(-102) -73 + j*(-41) -92 + j*(-145) --116 + j*(-157) --128 + j*(124) -205 + j*(135) -236 + j*(-214) --62 + j*(-278) --117 + j*(-98) --63 + j*(-123) --197 + j*(-114) --185 + j*(81) --5 + j*(66) --50 + j*(-69) --143 + j*(8) --59 + j*(42) --122 + j*(-60) --296 + j*(93) --145 + j*(368) -175 + j*(320) -255 + j*(62) -122 + j*(-95) --64 + j*(-74) --113 + j*(142) -149 + j*(253) -330 + j*(-47) -31 + j*(-283) --222 + j*(-14) -6 + j*(216) -192 + j*(39) -72 + j*(-78) -43 + j*(-16) -64 + j*(-79) --71 + j*(-67) --28 + j*(125) -212 + j*(54) -131 + j*(-217) --133 + j*(-146) --68 + j*(70) -76 + j*(-16) --59 + j*(-91) --95 + j*(104) -144 + j*(139) -205 + j*(-93) -36 + j*(-150) -50 + j*(-59) -124 + j*(-183) --73 + j*(-305) --228 + j*(-122) --81 + j*(-23) --100 + j*(-214) --424 + j*(-128) --380 + j*(317) -73 + j*(366) -153 + j*(8) --98 + j*(-6) --1 + j*(191) -185 + j*(2) --50 + j*(-177) --202 + j*(67) -40 + j*(162) -50 + j*(-89) --235 + j*(-28) --160 + j*(301) -161 + j*(273) -180 + j*(40) -69 + j*(28) -107 + j*(59) -119 + j*(-6) -87 + j*(-18) -110 + j*(-49) -35 + j*(-127) --82 + j*(-34) -22 + j*(100) -173 + j*(-21) -50 + j*(-208) --171 + j*(-125) --165 + j*(105) -37 + j*(181) -170 + j*(35) -77 + j*(-113) --60 + j*(-45) -16 + j*(80) -151 + j*(-3) -94 + j*(-148) --14 + j*(-153) --68 + j*(-142) --179 + j*(-107) --211 + j*(71) --58 + j*(149) --26 + j*(57) --117 + j*(155) -84 + j*(344) -407 + j*(170) -378 + j*(-184) -158 + j*(-296) -35 + j*(-284) --87 + j*(-274) --168 + j*(-157) --114 + j*(-103) --168 + j*(-168) --328 + j*(-48) --250 + j*(185) --42 + j*(190) --8 + j*(85) --21 + j*(76) --8 + j*(45) --76 + j*(54) --27 + j*(190) -190 + j*(132) -170 + j*(-142) --105 + j*(-183) --204 + j*(33) --92 + j*(165) -28 + j*(173) -127 + j*(103) -102 + j*(-33) --23 + j*(-9) -51 + j*(109) -190 + j*(-38) --11 + j*(-218) --225 + j*(-1) --25 + j*(212) -148 + j*(43) --7 + j*(-45) -1 + j*(132) -233 + j*(62) -165 + j*(-228) --132 + j*(-211) --180 + j*(21) --56 + j*(96) --8 + j*(82) -44 + j*(94) -104 + j*(25) -35 + j*(-51) --43 + j*(27) -45 + j*(134) -209 + j*(76) -254 + j*(-117) -107 + j*(-292) --150 + j*(-268) --263 + j*(-11) --60 + j*(197) -191 + j*(55) -93 + j*(-218) --197 + j*(-148) --148 + j*(162) -184 + j*(128) -178 + j*(-226) --180 + j*(-267) --271 + j*(51) --34 + j*(158) -41 + j*(13) --38 + j*(0) -1 + j*(40) -6 + j*(-18) --59 + j*(40) -88 + j*(136) -261 + j*(-80) -59 + j*(-350) --248 + j*(-250) --266 + j*(-21) --182 + j*(36) --177 + j*(53) --161 + j*(85) --193 + j*(107) --207 + j*(268) -27 + j*(402) -247 + j*(209) -129 + j*(17) -56 + j*(136) -258 + j*(120) -229 + j*(-168) --78 + j*(-160) --64 + j*(113) -170 + j*(59) -77 + j*(-148) --108 + j*(-31) -15 + j*(130) -151 + j*(8) -51 + j*(-105) --40 + j*(-45) --42 + j*(8) --46 + j*(79) -69 + j*(174) -252 + j*(73) -219 + j*(-144) -48 + j*(-170) -27 + j*(-79) -76 + j*(-110) -14 + j*(-173) --57 + j*(-125) --37 + j*(-83) --28 + j*(-112) --76 + j*(-127) --127 + j*(-107) --182 + j*(-55) --190 + j*(67) --52 + j*(153) -88 + j*(37) --12 + j*(-134) --209 + j*(-48) --156 + j*(166) -36 + j*(158) -42 + j*(40) -16 + j*(83) -163 + j*(47) -121 + j*(-222) --246 + j*(-230) --334 + j*(179) -50 + j*(338) -243 + j*(25) -16 + j*(-159) --142 + j*(-8) --72 + j*(122) -25 + j*(144) -138 + j*(94) -143 + j*(-86) --79 + j*(-124) --121 + j*(132) -185 + j*(173) -239 + j*(-182) --132 + j*(-284) --294 + j*(43) --78 + j*(240) -91 + j*(185) -195 + j*(122) -308 + j*(-75) -124 + j*(-369) --279 + j*(-296) --353 + j*(95) --79 + j*(262) -76 + j*(132) -30 + j*(67) -55 + j*(129) -194 + j*(81) -192 + j*(-132) --52 + j*(-206) --191 + j*(40) -42 + j*(218) -232 + j*(6) -36 + j*(-152) --55 + j*(59) -214 + j*(88) -226 + j*(-250) --139 + j*(-286) --190 + j*(41) -70 + j*(71) -55 + j*(-124) --89 + j*(-54) -37 + j*(49) -132 + j*(-125) --43 + j*(-244) --177 + j*(-129) --149 + j*(-38) --137 + j*(-24) --142 + j*(4) --150 + j*(25) --171 + j*(105) --52 + j*(214) -131 + j*(100) -37 + j*(-120) --204 + j*(-43) --158 + j*(200) -51 + j*(194) -59 + j*(61) -1 + j*(87) -82 + j*(112) -108 + j*(1) --3 + j*(-28) --23 + j*(77) -76 + j*(83) -66 + j*(-2) --14 + j*(46) -72 + j*(158) -244 + j*(79) -236 + j*(-113) -114 + j*(-178) -60 + j*(-178) --21 + j*(-221) --165 + j*(-146) --140 + j*(19) --21 + j*(2) --102 + j*(-72) --185 + j*(98) -42 + j*(233) -225 + j*(3) -28 + j*(-192) --140 + j*(-33) --7 + j*(78) -38 + j*(-54) --113 + j*(-42) --71 + j*(146) -151 + j*(107) -143 + j*(-125) --66 + j*(-162) --119 + j*(-9) --29 + j*(5) --102 + j*(-79) --268 + j*(76) --108 + j*(378) -293 + j*(308) -334 + j*(-91) -11 + j*(-167) -0 + j*(102) -304 + j*(29) -221 + j*(-356) --197 + j*(-358) --294 + j*(-16) --108 + j*(108) --43 + j*(82) -37 + j*(127) -197 + j*(-4) -68 + j*(-255) --235 + j*(-165) --197 + j*(137) -63 + j*(132) -61 + j*(-66) --91 + j*(-42) --37 + j*(91) -100 + j*(26) -60 + j*(-134) --96 + j*(-156) --182 + j*(-64) --192 + j*(13) --215 + j*(84) --202 + j*(231) --19 + j*(366) -247 + j*(267) -278 + j*(-31) -21 + j*(-142) --112 + j*(76) -100 + j*(225) -283 + j*(19) -115 + j*(-186) --77 + j*(-58) -45 + j*(105) -199 + j*(-28) -84 + j*(-192) --70 + j*(-128) --62 + j*(-35) --59 + j*(-8) --18 + j*(86) -176 + j*(46) -160 + j*(-254) --221 + j*(-291) --323 + j*(122) -72 + j*(262) -206 + j*(-103) --147 + j*(-211) --238 + j*(141) -100 + j*(235) -200 + j*(-59) --37 + j*(-152) --114 + j*(34) -33 + j*(107) -126 + j*(5) -100 + j*(-115) --15 + j*(-191) --179 + j*(-140) --224 + j*(51) --86 + j*(173) -54 + j*(123) -80 + j*(24) -42 + j*(-43) --30 + j*(-70) --118 + j*(-21) --136 + j*(110) --18 + j*(228) -181 + j*(202) -283 + j*(4) -170 + j*(-181) -2 + j*(-163) --1 + j*(-71) -43 + j*(-122) --56 + j*(-192) --161 + j*(-115) --156 + j*(-45) --197 + j*(-29) --255 + j*(115) --100 + j*(283) -112 + j*(202) -103 + j*(40) -40 + j*(46) -104 + j*(28) -45 + j*(-110) --158 + j*(-43) --114 + j*(212) -162 + j*(218) -224 + j*(-30) -39 + j*(-115) --30 + j*(13) -65 + j*(57) -101 + j*(-19) -54 + j*(-53) -42 + j*(-27) -81 + j*(-44) -65 + j*(-117) --36 + j*(-137) --88 + j*(-47) --27 + j*(-2) --19 + j*(-59) --105 + j*(-21) --44 + j*(110) -124 + j*(50) -86 + j*(-128) --64 + j*(-110) --41 + j*(-31) --33 + j*(-107) --197 + j*(-87) --207 + j*(129) --13 + j*(190) -45 + j*(83) -28 + j*(101) -155 + j*(90) -182 + j*(-108) --11 + j*(-187) --96 + j*(-67) --54 + j*(-40) --118 + j*(-52) --151 + j*(76) --30 + j*(140) -28 + j*(68) --1 + j*(66) -59 + j*(91) -106 + j*(13) -63 + j*(-46) -30 + j*(-65) --52 + j*(-95) --160 + j*(30) --26 + j*(209) -195 + j*(98) -116 + j*(-109) --30 + j*(-35) -85 + j*(37) -122 + j*(-138) --80 + j*(-183) --139 + j*(-16) --52 + j*(21) --83 + j*(8) --54 + j*(124) -121 + j*(78) -69 + j*(-126) --141 + j*(-68) --84 + j*(131) -74 + j*(79) -15 + j*(-7) -12 + j*(95) -184 + j*(45) -122 + j*(-194) --146 + j*(-146) --102 + j*(121) -168 + j*(62) -98 + j*(-232) --227 + j*(-185) --233 + j*(142) -51 + j*(192) -104 + j*(-26) --62 + j*(-37) --11 + j*(115) -159 + j*(13) -35 + j*(-194) --204 + j*(-81) --124 + j*(170) -105 + j*(130) -91 + j*(-57) --46 + j*(-47) --34 + j*(46) -18 + j*(25) --19 + j*(13) --1 + j*(90) -125 + j*(73) -142 + j*(-82) --7 + j*(-134) --57 + j*(-12) -56 + j*(1) -25 + j*(-146) --174 + j*(-100) --139 + j*(134) -93 + j*(115) -64 + j*(-90) --108 + j*(-28) --1 + j*(120) -132 + j*(-34) --59 + j*(-165) --207 + j*(35) --47 + j*(202) -100 + j*(136) -141 + j*(77) -220 + j*(-18) -155 + j*(-210) --57 + j*(-214) --86 + j*(-76) --43 + j*(-117) --204 + j*(-126) --249 + j*(128) -28 + j*(229) -165 + j*(-16) --25 + j*(-170) --192 + j*(-66) --209 + j*(88) --129 + j*(233) -81 + j*(271) -209 + j*(80) -72 + j*(-46) -18 + j*(77) -187 + j*(63) -157 + j*(-168) --95 + j*(-155) --91 + j*(73) -98 + j*(53) -54 + j*(-110) --90 + j*(-47) --23 + j*(76) -80 + j*(1) -1 + j*(-93) --100 + j*(-33) --98 + j*(78) --21 + j*(166) -151 + j*(190) -321 + j*(1) -203 + j*(-288) --123 + j*(-281) --194 + j*(-1) -13 + j*(88) -78 + j*(-65) --23 + j*(-102) --22 + j*(-69) --57 + j*(-141) --228 + j*(-72) --181 + j*(177) -86 + j*(182) -119 + j*(-33) -4 + j*(-56) -50 + j*(-43) --4 + j*(-202) --270 + j*(-153) --286 + j*(146) --64 + j*(211) --37 + j*(127) --25 + j*(225) -196 + j*(214) -241 + j*(-38) -58 + j*(-103) -51 + j*(-18) -80 + j*(-117) --96 + j*(-141) --125 + j*(45) -23 + j*(34) --79 + j*(-83) --216 + j*(120) -38 + j*(322) -293 + j*(91) -132 + j*(-173) --103 + j*(-79) --69 + j*(127) -124 + j*(176) -286 + j*(19) -222 + j*(-245) --86 + j*(-308) --252 + j*(-31) --45 + j*(192) -200 + j*(66) -170 + j*(-175) --29 + j*(-252) --189 + j*(-151) --204 + j*(22) --84 + j*(115) -18 + j*(67) -18 + j*(1) --2 + j*(-13) --11 + j*(-31) --57 + j*(-40) --103 + j*(17) --69 + j*(106) -46 + j*(123) -122 + j*(16) -49 + j*(-89) --46 + j*(-57) --28 + j*(-10) --50 + j*(-45) --136 + j*(37) --18 + j*(188) -182 + j*(63) -70 + j*(-157) --140 + j*(-64) --78 + j*(111) -35 + j*(95) -66 + j*(81) -185 + j*(32) -162 + j*(-202) --117 + j*(-233) --161 + j*(8) -6 + j*(-26) --165 + j*(-170) --362 + j*(101) --98 + j*(355) -115 + j*(180) --6 + j*(114) -75 + j*(283) -329 + j*(164) -286 + j*(-95) -141 + j*(-126) -104 + j*(-136) --6 + j*(-132) -7 + j*(22) -205 + j*(-46) -93 + j*(-307) --196 + j*(-183) --59 + j*(74) -151 + j*(-113) --83 + j*(-315) --296 + j*(-106) --171 + j*(77) --71 + j*(35) --72 + j*(4) --87 + j*(-40) --209 + j*(-25) --231 + j*(175) --37 + j*(239) --9 + j*(131) --40 + j*(248) -265 + j*(286) -378 + j*(-141) --78 + j*(-327) --289 + j*(93) -57 + j*(281) -181 + j*(31) -14 + j*(23) -139 + j*(173) -344 + j*(-11) -225 + j*(-270) -10 + j*(-289) --103 + j*(-218) --167 + j*(-113) --125 + j*(-10) --69 + j*(-30) --124 + j*(-33) --103 + j*(62) -4 + j*(15) --92 + j*(-112) --288 + j*(6) --251 + j*(276) -4 + j*(411) -286 + j*(305) -386 + j*(-4) -161 + j*(-228) --64 + j*(-95) -54 + j*(63) -171 + j*(-109) --41 + j*(-246) --227 + j*(-56) --119 + j*(155) -76 + j*(156) -170 + j*(5) -58 + j*(-159) --158 + j*(-61) --49 + j*(208) -276 + j*(100) -196 + j*(-252) --112 + j*(-204) --63 + j*(-6) -14 + j*(-114) --177 + j*(-100) --102 + j*(158) -188 + j*(33) -34 + j*(-267) --239 + j*(-119) --108 + j*(65) --68 + j*(-85) --296 + j*(1) --157 + j*(327) -224 + j*(201) -135 + j*(-182) --231 + j*(-141) --275 + j*(192) --20 + j*(354) -240 + j*(245) -291 + j*(-37) -54 + j*(-195) --135 + j*(-11) -25 + j*(170) -205 + j*(23) -100 + j*(-162) --71 + j*(-133) --131 + j*(-20) --115 + j*(113) -40 + j*(216) -250 + j*(104) -235 + j*(-154) -15 + j*(-248) --147 + j*(-132) --148 + j*(35) --17 + j*(121) -110 + j*(30) -44 + j*(-112) --106 + j*(-56) --55 + j*(97) -101 + j*(49) -62 + j*(-112) --109 + j*(-88) --120 + j*(91) -51 + j*(150) -152 + j*(11) -57 + j*(-103) --35 + j*(-41) -23 + j*(16) -52 + j*(-61) --41 + j*(-70) --28 + j*(37) -96 + j*(8) -76 + j*(-127) --33 + j*(-134) --47 + j*(-99) --90 + j*(-128) --177 + j*(-52) --112 + j*(59) --25 + j*(-8) --124 + j*(-69) --187 + j*(62) --61 + j*(129) --21 + j*(21) --146 + j*(18) --155 + j*(183) -16 + j*(247) -124 + j*(129) -52 + j*(31) --17 + j*(124) -143 + j*(221) -337 + j*(25) -185 + j*(-251) --93 + j*(-180) --52 + j*(13) -37 + j*(-83) --168 + j*(-117) --214 + j*(187) -127 + j*(282) -261 + j*(-25) -44 + j*(-146) --10 + j*(-31) -24 + j*(-95) --183 + j*(-95) --222 + j*(240) -168 + j*(390) -433 + j*(71) -298 + j*(-221) -113 + j*(-276) --38 + j*(-285) --211 + j*(-148) --129 + j*(102) -140 + j*(42) -71 + j*(-243) --246 + j*(-169) --197 + j*(172) -141 + j*(163) -176 + j*(-131) --39 + j*(-188) --71 + j*(-68) --6 + j*(-113) --122 + j*(-194) --250 + j*(-72) --182 + j*(49) --130 + j*(2) --233 + j*(1) --279 + j*(167) --152 + j*(306) -4 + j*(311) -115 + j*(258) -196 + j*(161) -183 + j*(35) -96 + j*(2) -91 + j*(52) -163 + j*(17) -135 + j*(-98) -13 + j*(-98) -6 + j*(10) -126 + j*(-1) -124 + j*(-168) --72 + j*(-218) --180 + j*(-43) --50 + j*(76) -38 + j*(-34) --102 + j*(-103) --193 + j*(77) --8 + j*(222) -180 + j*(76) -91 + j*(-114) --70 + j*(-62) --25 + j*(64) -83 + j*(8) -17 + j*(-104) --108 + j*(-43) --68 + j*(95) -66 + j*(85) -87 + j*(-28) -7 + j*(-65) --32 + j*(-13) -8 + j*(21) -50 + j*(-14) -21 + j*(-77) --58 + j*(-66) --64 + j*(24) -18 + j*(32) -10 + j*(-45) --84 + j*(0) --7 + j*(138) -182 + j*(66) -154 + j*(-149) --35 + j*(-161) --43 + j*(-35) -289 + j*(-105) -48 + j*(-267) --117 + j*(-80) -29 + j*(9) -35 + j*(-146) --147 + j*(-115) --127 + j*(57) --21 + j*(53) --33 + j*(38) -35 + j*(74) -91 + j*(-54) --83 + j*(-115) --143 + j*(86) -59 + j*(139) -90 + j*(-30) --27 + j*(-8) -72 + j*(67) -134 + j*(-110) --86 + j*(-178) --147 + j*(43) -63 + j*(65) -36 + j*(-163) --241 + j*(-127) --261 + j*(175) --10 + j*(271) -105 + j*(127) -33 + j*(82) -76 + j*(185) -282 + j*(139) -342 + j*(-134) -117 + j*(-313) --91 + j*(-217) --93 + j*(-85) --62 + j*(-66) --66 + j*(-48) --45 + j*(-54) --103 + j*(-93) --198 + j*(10) --96 + j*(158) -62 + j*(83) --5 + j*(-36) --83 + j*(56) -40 + j*(118) -115 + j*(-21) --5 + j*(-117) --124 + j*(-46) --124 + j*(76) --24 + j*(152) -101 + j*(85) -59 + j*(-54) --82 + j*(-16) --40 + j*(128) -96 + j*(98) -89 + j*(8) -78 + j*(14) -117 + j*(-49) -11 + j*(-134) --95 + j*(-16) -24 + j*(91) -124 + j*(-26) -34 + j*(-121) --38 + j*(-86) --65 + j*(-70) --132 + j*(-6) --73 + j*(136) -105 + j*(129) -165 + j*(-20) -114 + j*(-127) -27 + j*(-206) --149 + j*(-214) --279 + j*(-35) --199 + j*(165) --30 + j*(222) -127 + j*(180) -237 + j*(3) -117 + j*(-216) --130 + j*(-172) --134 + j*(24) --23 + j*(24) --66 + j*(-16) --55 + j*(66) -30 + j*(5) --110 + j*(-68) --191 + j*(171) -123 + j*(295) -298 + j*(-30) -11 + j*(-223) --153 + j*(-2) -4 + j*(105) -43 + j*(1) --23 + j*(31) -62 + j*(81) -114 + j*(-18) -42 + j*(-70) -21 + j*(-55) --17 + j*(-88) --118 + j*(-25) --51 + j*(135) -152 + j*(98) -173 + j*(-116) --1 + j*(-206) --134 + j*(-121) --135 + j*(-4) --72 + j*(30) --74 + j*(0) --143 + j*(57) --77 + j*(211) -144 + j*(200) -202 + j*(-10) -59 + j*(-81) -58 + j*(10) -178 + j*(-93) -22 + j*(-322) --337 + j*(-206) --330 + j*(221) -78 + j*(327) -239 + j*(-14) --35 + j*(-155) --123 + j*(98) -151 + j*(136) -168 + j*(-165) --141 + j*(-185) --166 + j*(93) -47 + j*(113) -43 + j*(-6) -30 + j*(49) -165 + j*(-33) -17 + j*(-255) --269 + j*(-81) --86 + j*(231) -225 + j*(40) -30 + j*(-259) --252 + j*(-91) --139 + j*(146) -13 + j*(98) -14 + j*(58) -77 + j*(35) -42 + j*(-102) --147 + j*(-42) --55 + j*(191) -230 + j*(76) -115 + j*(-262) --256 + j*(-185) --249 + j*(168) -25 + j*(216) -93 + j*(48) -23 + j*(21) -58 + j*(40) -56 + j*(-28) --37 + j*(-1) -32 + j*(119) -198 + j*(11) -76 + j*(-219) --213 + j*(-105) --132 + j*(235) -230 + j*(217) -286 + j*(-113) -52 + j*(-210) --11 + j*(-78) -75 + j*(-99) --7 + j*(-212) --186 + j*(-150) --212 + j*(49) --55 + j*(184) -151 + j*(121) -186 + j*(-97) -4 + j*(-198) --103 + j*(-67) -1 + j*(5) -44 + j*(-101) --55 + j*(-142) --87 + j*(-94) --101 + j*(-129) --243 + j*(-112) --301 + j*(93) --132 + j*(234) -18 + j*(151) --12 + j*(62) --49 + j*(107) -35 + j*(147) -117 + j*(44) -16 + j*(-88) --175 + j*(0) --128 + j*(248) -146 + j*(272) -226 + j*(30) -36 + j*(-52) --14 + j*(125) -177 + j*(180) -288 + j*(15) -226 + j*(-129) -146 + j*(-189) -43 + j*(-238) --108 + j*(-192) --154 + j*(-26) --35 + j*(66) -40 + j*(-11) --47 + j*(-35) --35 + j*(124) -231 + j*(130) -330 + j*(-210) -6 + j*(-432) --267 + j*(-223) --188 + j*(-30) --155 + j*(-62) --239 + j*(41) --90 + j*(183) -37 + j*(34) --144 + j*(-7) --110 + j*(267) -263 + j*(215) -240 + j*(-197) --127 + j*(-203) --124 + j*(60) -16 + j*(-4) --152 + j*(-30) --110 + j*(262) -289 + j*(213) -280 + j*(-238) --146 + j*(-282) --222 + j*(64) -23 + j*(141) -82 + j*(-6) -25 + j*(-49) -6 + j*(-81) --108 + j*(-105) --194 + j*(47) --64 + j*(187) -83 + j*(114) -59 + j*(8) -0 + j*(14) --1 + j*(57) -37 + j*(90) -122 + j*(75) -168 + j*(-39) -73 + j*(-146) --55 + j*(-95) --36 + j*(14) -54 + j*(-6) -14 + j*(-96) --99 + j*(-51) --68 + j*(88) -85 + j*(91) -134 + j*(-51) -41 + j*(-154) --95 + j*(-151) --206 + j*(-25) --144 + j*(183) -107 + j*(202) -188 + j*(-37) --20 + j*(-119) --62 + j*(71) -147 + j*(68) -124 + j*(-173) --122 + j*(-161) --127 + j*(53) -21 + j*(59) -6 + j*(-20) --13 + j*(25) -59 + j*(1) -4 + j*(-86) --95 + j*(-6) -8 + j*(105) -144 + j*(-4) -68 + j*(-172) --110 + j*(-169) --196 + j*(-29) --133 + j*(106) --3 + j*(113) -34 + j*(15) --41 + j*(-21) --91 + j*(33) --90 + j*(110) --18 + j*(216) -197 + j*(218) -314 + j*(-42) -87 + j*(-242) --115 + j*(-71) -33 + j*(80) -140 + j*(-82) --29 + j*(-170) --99 + j*(-30) --1 + j*(-6) --40 + j*(-76) --98 + j*(8) -1 + j*(52) -15 + j*(-54) --93 + j*(-42) --65 + j*(50) --20 + j*(-1) --129 + j*(8) --103 + j*(194) -134 + j*(193) -154 + j*(-35) --39 + j*(-37) -11 + j*(146) -216 + j*(68) -156 + j*(-149) --17 + j*(-116) -37 + j*(-21) -90 + j*(-150) --112 + j*(-232) --263 + j*(-30) --138 + j*(153) -8 + j*(112) --6 + j*(47) --35 + j*(86) -14 + j*(156) -151 + j*(177) -316 + j*(31) -255 + j*(-251) --49 + j*(-311) --167 + j*(-69) -13 + j*(4) -6 + j*(-192) --267 + j*(-154) --273 + j*(182) -54 + j*(267) -185 + j*(0) --18 + j*(-135) --144 + j*(32) -2 + j*(172) -166 + j*(59) -109 + j*(-117) --37 + j*(-109) --45 + j*(-27) --28 + j*(-60) --139 + j*(-47) --143 + j*(141) -78 + j*(190) -168 + j*(-18) -1 + j*(-113) --71 + j*(6) -6 + j*(42) -5 + j*(3) --3 + j*(49) -91 + j*(45) -108 + j*(-82) --16 + j*(-148) --133 + j*(-73) --136 + j*(76) -23 + j*(173) -211 + j*(23) -102 + j*(-249) --216 + j*(-225) --303 + j*(62) --138 + j*(218) --2 + j*(214) -100 + j*(173) -144 + j*(47) -25 + j*(-8) -6 + j*(151) -246 + j*(177) -357 + j*(-109) -131 + j*(-318) --112 + j*(-233) --158 + j*(-30) --19 + j*(103) -180 + j*(0) -107 + j*(-271) --215 + j*(-262) --282 + j*(39) --81 + j*(137) --29 + j*(65) -1 + j*(115) -158 + j*(27) -47 + j*(-217) --241 + j*(-107) --150 + j*(170) -54 + j*(88) --59 + j*(-16) --83 + j*(154) -124 + j*(134) -70 + j*(-66) --105 + j*(45) -65 + j*(219) -265 + j*(42) -152 + j*(-168) --22 + j*(-149) --83 + j*(-40) --25 + j*(85) -170 + j*(56) -179 + j*(-217) --138 + j*(-293) --273 + j*(-1) --75 + j*(133) --13 + j*(32) --70 + j*(78) -46 + j*(151) -146 + j*(57) -153 + j*(-16) -195 + j*(-137) -28 + j*(-334) --276 + j*(-197) --188 + j*(105) -34 + j*(-1) --150 + j*(-147) --267 + j*(112) -5 + j*(197) -16 + j*(-44) --216 + j*(57) --28 + j*(312) -238 + j*(98) -31 + j*(-144) --156 + j*(45) --7 + j*(180) -56 + j*(98) -30 + j*(136) -173 + j*(168) -258 + j*(-6) -145 + j*(-132) -42 + j*(-111) -1 + j*(-65) -16 + j*(-4) -90 + j*(-25) -50 + j*(-115) --30 + j*(-59) -59 + j*(-30) -15 + j*(-192) --250 + j*(-86) --112 + j*(277) -327 + j*(137) -206 + j*(-332) --237 + j*(-243) --171 + j*(117) -79 + j*(52) --7 + j*(-91) --53 + j*(17) -75 + j*(-9) -6 + j*(-153) --129 + j*(-91) --99 + j*(-10) --106 + j*(-25) --136 + j*(52) --40 + j*(88) --48 + j*(1) --161 + j*(84) --45 + j*(264) -179 + j*(209) -245 + j*(39) -233 + j*(-105) -105 + j*(-275) --171 + j*(-233) --192 + j*(54) -74 + j*(65) -41 + j*(-211) --262 + j*(-182) --293 + j*(94) --141 + j*(161) --134 + j*(158) --73 + j*(276) -132 + j*(254) -175 + j*(54) -16 + j*(-18) --84 + j*(126) -39 + j*(310) -330 + j*(296) -501 + j*(-6) -334 + j*(-305) -71 + j*(-325) --45 + j*(-229) --115 + j*(-142) --98 + j*(11) -86 + j*(33) -119 + j*(-179) --106 + j*(-235) --180 + j*(-46) --73 + j*(-6) --128 + j*(-57) --189 + j*(103) -11 + j*(227) -194 + j*(70) -141 + j*(-124) --1 + j*(-195) --173 + j*(-159) --265 + j*(54) --91 + j*(255) -147 + j*(177) -175 + j*(-4) -122 + j*(-93) -39 + j*(-185) --155 + j*(-162) --191 + j*(64) -11 + j*(116) -21 + j*(-49) --126 + j*(13) --3 + j*(163) -136 + j*(6) --46 + j*(-89) --78 + j*(132) -209 + j*(125) -206 + j*(-209) --115 + j*(-246) --169 + j*(-5) --25 + j*(13) --78 + j*(-70) --147 + j*(35) --38 + j*(98) --1 + j*(-1) --103 + j*(-11) --120 + j*(90) --57 + j*(137) --13 + j*(147) -47 + j*(153) -107 + j*(101) -100 + j*(24) -37 + j*(-1) --18 + j*(52) -26 + j*(156) -185 + j*(162) -270 + j*(-8) -148 + j*(-137) -51 + j*(-60) -148 + j*(-20) -189 + j*(-180) -4 + j*(-284) --164 + j*(-153) --118 + j*(13) -3 + j*(23) -24 + j*(-56) --43 + j*(-78) --88 + j*(-6) --18 + j*(78) -110 + j*(32) -114 + j*(-117) --15 + j*(-175) --87 + j*(-96) --46 + j*(-64) --71 + j*(-127) --206 + j*(-91) --226 + j*(105) --23 + j*(203) -134 + j*(45) -30 + j*(-124) --115 + j*(-62) --65 + j*(28) --31 + j*(-54) --179 + j*(-63) --210 + j*(136) --16 + j*(198) -36 + j*(40) --106 + j*(38) --68 + j*(192) -78 + j*(156) -47 + j*(64) -39 + j*(136) -185 + j*(86) -110 + j*(-131) --153 + j*(-52) --91 + j*(232) -165 + j*(208) -156 + j*(53) -134 + j*(125) -352 + j*(78) -346 + j*(-262) --13 + j*(-349) --147 + j*(-60) -64 + j*(48) -127 + j*(-127) --36 + j*(-159) --47 + j*(2) -148 + j*(4) -195 + j*(-245) --71 + j*(-416) --358 + j*(-235) --324 + j*(68) --119 + j*(122) --91 + j*(37) --129 + j*(89) --40 + j*(146) -21 + j*(93) -28 + j*(99) -151 + j*(76) -176 + j*(-152) --89 + j*(-262) --268 + j*(-39) --136 + j*(136) --42 + j*(90) --69 + j*(110) -40 + j*(185) -185 + j*(63) -122 + j*(-134) --73 + j*(-173) --218 + j*(-44) --208 + j*(163) --20 + j*(275) -141 + j*(173) -112 + j*(64) -101 + j*(95) -206 + j*(52) -184 + j*(-124) --6 + j*(-166) --108 + j*(-8) --1 + j*(148) -205 + j*(106) -245 + j*(-127) -27 + j*(-231) --72 + j*(-45) -124 + j*(-6) -107 + j*(-274) --233 + j*(-255) --246 + j*(96) -51 + j*(117) -33 + j*(-96) --96 + j*(-16) -52 + j*(31) -20 + j*(-190) --269 + j*(-102) --158 + j*(219) -146 + j*(103) -16 + j*(-148) --162 + j*(-1) --6 + j*(86) --26 + j*(-93) --250 + j*(21) --105 + j*(300) -186 + j*(184) -116 + j*(-55) --38 + j*(-11) --4 + j*(71) -16 + j*(56) -22 + j*(95) -110 + j*(95) -133 + j*(8) -105 + j*(-18) -121 + j*(-63) -32 + j*(-133) --62 + j*(-13) -107 + j*(81) -227 + j*(-165) --63 + j*(-356) --326 + j*(-103) --173 + j*(166) -21 + j*(103) --13 + j*(16) --28 + j*(69) -35 + j*(64) -17 + j*(31) -24 + j*(100) -172 + j*(95) -235 + j*(-98) -76 + j*(-238) --76 + j*(-169) --74 + j*(-90) --94 + j*(-104) --181 + j*(-21) --91 + j*(144) -133 + j*(70) -83 + j*(-201) --218 + j*(-201) --285 + j*(86) --70 + j*(182) --14 + j*(47) --133 + j*(74) --64 + j*(236) -134 + j*(196) -145 + j*(21) -33 + j*(-3) -31 + j*(71) -93 + j*(63) -103 + j*(27) -136 + j*(8) -159 + j*(-101) -6 + j*(-204) --166 + j*(-51) --32 + j*(163) -197 + j*(45) -89 + j*(-181) --113 + j*(-66) -34 + j*(115) -224 + j*(-70) -40 + j*(-300) --203 + j*(-174) --153 + j*(20) --46 + j*(-1) --86 + j*(-54) --144 + j*(-4) --142 + j*(78) --77 + j*(152) -35 + j*(143) -64 + j*(58) -30 + j*(57) -103 + j*(73) -147 + j*(-69) --13 + j*(-156) --113 + j*(-19) --8 + j*(49) -1 + j*(-51) --122 + j*(-18) --88 + j*(131) -46 + j*(125) -52 + j*(45) -18 + j*(74) -99 + j*(122) -229 + j*(40) -226 + j*(-179) --26 + j*(-305) --270 + j*(-82) --103 + j*(228) -225 + j*(115) -159 + j*(-190) --81 + j*(-153) --35 + j*(-6) -34 + j*(-107) --125 + j*(-144) --168 + j*(22) --47 + j*(45) --95 + j*(-20) --159 + j*(114) -14 + j*(233) -197 + j*(102) -174 + j*(-106) --4 + j*(-222) --247 + j*(-124) --266 + j*(206) -88 + j*(342) -296 + j*(18) -17 + j*(-190) --146 + j*(75) -149 + j*(204) -288 + j*(-123) --25 + j*(-312) --264 + j*(-69) --137 + j*(181) -74 + j*(180) -169 + j*(55) -150 + j*(-76) -47 + j*(-137) --26 + j*(-86) -4 + j*(-62) --24 + j*(-129) --163 + j*(-97) --177 + j*(95) -24 + j*(166) -134 + j*(-13) --17 + j*(-141) --153 + j*(-25) --85 + j*(95) --29 + j*(76) --37 + j*(125) -110 + j*(194) -278 + j*(7) -135 + j*(-240) --113 + j*(-179) --115 + j*(-4) --42 + j*(2) --67 + j*(11) --9 + j*(69) -59 + j*(-32) --93 + j*(-112) --205 + j*(74) --33 + j*(229) -126 + j*(125) -100 + j*(23) -87 + j*(9) -70 + j*(-52) --30 + j*(-29) -18 + j*(99) -185 + j*(21) -101 + j*(-180) --99 + j*(-108) --31 + j*(54) -78 + j*(-33) --46 + j*(-89) --52 + j*(81) -185 + j*(49) -157 + j*(-255) --177 + j*(-282) --271 + j*(8) --87 + j*(125) --6 + j*(40) --25 + j*(14) --21 + j*(-10) --103 + j*(-24) --145 + j*(128) -56 + j*(224) -201 + j*(26) -47 + j*(-132) --82 + j*(-22) --1 + j*(52) -16 + j*(-13) --42 + j*(16) -16 + j*(66) -49 + j*(-5) --40 + j*(-9) --18 + j*(112) -144 + j*(107) -204 + j*(-70) -72 + j*(-212) --123 + j*(-176) --181 + j*(23) --6 + j*(134) -121 + j*(-31) --50 + j*(-162) --195 + j*(7) --65 + j*(153) -37 + j*(91) -40 + j*(92) -170 + j*(61) -163 + j*(-193) --170 + j*(-240) --288 + j*(107) --1 + j*(282) -185 + j*(114) -162 + j*(-13) -153 + j*(-107) --3 + j*(-224) --206 + j*(-63) --57 + j*(169) -165 + j*(22) -11 + j*(-170) --147 + j*(-13) -1 + j*(107) -85 + j*(-23) --13 + j*(-83) --57 + j*(-38) --77 + j*(-19) --95 + j*(47) --35 + j*(86) --41 + j*(71) --32 + j*(205) -263 + j*(254) -446 + j*(-144) -64 + j*(-469) --317 + j*(-196) --170 + j*(134) -43 + j*(57) --21 + j*(-52) --77 + j*(8) --59 + j*(57) --23 + j*(123) -140 + j*(134) -221 + j*(-90) --5 + j*(-235) --171 + j*(-45) --26 + j*(109) -98 + j*(6) -53 + j*(-85) -20 + j*(-107) --38 + j*(-162) --164 + j*(-141) --222 + j*(-29) --217 + j*(60) --197 + j*(170) --65 + j*(260) -76 + j*(199) -81 + j*(114) -95 + j*(112) -139 + j*(42) -67 + j*(-21) -35 + j*(58) -151 + j*(43) -117 + j*(-108) --39 + j*(-65) -33 + j*(71) -153 + j*(-46) -3 + j*(-164) --120 + j*(-2) -28 + j*(127) -170 + j*(25) -165 + j*(-112) -88 + j*(-227) --107 + j*(-260) --238 + j*(-64) --82 + j*(87) -16 + j*(-58) --175 + j*(-95) --187 + j*(146) -65 + j*(148) -33 + j*(-88) --204 + j*(-8) --112 + j*(245) -112 + j*(188) -80 + j*(72) -94 + j*(163) -308 + j*(91) -301 + j*(-218) -12 + j*(-330) --177 + j*(-164) --170 + j*(13) --62 + j*(122) -107 + j*(92) -132 + j*(-90) --40 + j*(-125) --41 + j*(42) -165 + j*(-6) -113 + j*(-285) --213 + j*(-308) --335 + j*(-26) --180 + j*(148) --30 + j*(113) -8 + j*(11) --77 + j*(-79) --247 + j*(-12) --247 + j*(233) --6 + j*(336) -141 + j*(191) -93 + j*(113) -146 + j*(161) -292 + j*(35) -192 + j*(-216) --88 + j*(-197) --121 + j*(41) -64 + j*(60) -31 + j*(-109) --173 + j*(-31) --81 + j*(224) -200 + j*(147) -132 + j*(-132) --136 + j*(-41) --18 + j*(240) -288 + j*(127) -226 + j*(-165) -8 + j*(-162) --4 + j*(-52) -6 + j*(-53) --10 + j*(20) -144 + j*(53) -215 + j*(-162) -6 + j*(-276) --84 + j*(-134) -16 + j*(-155) --129 + j*(-308) --391 + j*(-144) --329 + j*(155) --134 + j*(208) --63 + j*(195) -69 + j*(210) -174 + j*(31) --1 + j*(-110) --136 + j*(81) -98 + j*(218) -280 + j*(-43) -37 + j*(-285) --244 + j*(-103) --130 + j*(182) -132 + j*(116) -78 + j*(-113) --134 + j*(-38) --12 + j*(190) -277 + j*(32) -137 + j*(-336) --269 + j*(-279) --306 + j*(73) --84 + j*(141) --79 + j*(33) --160 + j*(114) --60 + j*(229) -64 + j*(197) -116 + j*(135) -141 + j*(62) -92 + j*(-4) -40 + j*(38) -105 + j*(69) -138 + j*(-11) -86 + j*(-39) -103 + j*(-30) -90 + j*(-114) --45 + j*(-99) --21 + j*(61) -155 + j*(28) -143 + j*(-152) -14 + j*(-182) --38 + j*(-177) --177 + j*(-168) --257 + j*(71) -22 + j*(226) -203 + j*(-59) --80 + j*(-229) --218 + j*(40) -30 + j*(115) -11 + j*(-123) --260 + j*(-18) --127 + j*(306) -204 + j*(222) -184 + j*(-29) -74 + j*(-21) -145 + j*(-28) -97 + j*(-173) --65 + j*(-141) --32 + j*(-24) -42 + j*(-103) --76 + j*(-190) --200 + j*(-114) --247 + j*(-19) --295 + j*(141) --132 + j*(388) -254 + j*(333) -330 + j*(-62) -25 + j*(-201) --71 + j*(1) -73 + j*(-6) --41 + j*(-155) --235 + j*(30) --35 + j*(269) -218 + j*(110) -127 + j*(-100) -16 + j*(-71) -24 + j*(-86) --116 + j*(-117) --199 + j*(104) -41 + j*(250) -223 + j*(57) -123 + j*(-101) -54 + j*(-88) -33 + j*(-143) --110 + j*(-144) --150 + j*(2) --69 + j*(37) --112 + j*(37) --70 + j*(188) -166 + j*(158) -164 + j*(-104) --70 + j*(-116) --74 + j*(55) -14 + j*(47) --10 + j*(61) -119 + j*(114) -215 + j*(-118) --82 + j*(-257) --247 + j*(54) -39 + j*(202) -122 + j*(-38) --81 + j*(-23) -25 + j*(167) -210 + j*(18) -73 + j*(-124) -33 + j*(-14) -141 + j*(-105) --53 + j*(-239) --199 + j*(8) -69 + j*(123) -135 + j*(-160) --154 + j*(-180) --127 + j*(86) -100 + j*(2) --37 + j*(-207) --245 + j*(-57) --139 + j*(126) --26 + j*(81) --37 + j*(59) -4 + j*(56) --21 + j*(-15) --119 + j*(55) --18 + j*(194) -148 + j*(102) -82 + j*(-47) --7 + j*(17) -97 + j*(55) -132 + j*(-103) --51 + j*(-179) --177 + j*(-28) --92 + j*(119) -30 + j*(105) -57 + j*(37) -43 + j*(4) -25 + j*(-22) --23 + j*(-17) --28 + j*(54) -62 + j*(68) -92 + j*(-38) --19 + j*(-83) --71 + j*(21) -14 + j*(81) -79 + j*(25) -70 + j*(-34) -31 + j*(-78) --53 + j*(-79) --98 + j*(21) --20 + j*(96) -56 + j*(66) -81 + j*(31) -117 + j*(-33) -43 + j*(-134) --94 + j*(-61) --4 + j*(74) -112 + j*(-68) --100 + j*(-173) --209 + j*(107) -116 + j*(230) -250 + j*(-109) --65 + j*(-243) --179 + j*(18) -12 + j*(88) -21 + j*(-33) --46 + j*(14) -36 + j*(38) -23 + j*(-49) --44 + j*(4) -50 + j*(33) -29 + j*(-98) --134 + j*(-14) -22 + j*(192) -293 + j*(-10) -109 + j*(-337) --204 + j*(-235) --176 + j*(-43) --158 + j*(-93) --324 + j*(-2) --251 + j*(276) -33 + j*(293) -100 + j*(108) -23 + j*(74) -47 + j*(98) -50 + j*(59) -31 + j*(103) -155 + j*(132) -241 + j*(-50) -63 + j*(-202) --117 + j*(-78) --51 + j*(88) -74 + j*(75) -110 + j*(15) -144 + j*(-58) -79 + j*(-200) --139 + j*(-191) --190 + j*(33) --8 + j*(96) -7 + j*(-53) --159 + j*(1) --78 + j*(213) -152 + j*(168) -161 + j*(-13) -86 + j*(-45) -86 + j*(-71) --5 + j*(-117) --72 + j*(0) -64 + j*(57) -101 + j*(-98) --54 + j*(-114) --33 + j*(19) -74 + j*(-61) --57 + j*(-158) --146 + j*(-16) --35 + j*(30) --71 + j*(-45) --130 + j*(91) -86 + j*(144) -123 + j*(-132) --199 + j*(-146) --197 + j*(214) -173 + j*(206) -166 + j*(-143) --147 + j*(-138) --156 + j*(122) -28 + j*(158) -74 + j*(79) -92 + j*(67) -139 + j*(16) -139 + j*(-55) -127 + j*(-139) -9 + j*(-258) --230 + j*(-187) --246 + j*(93) --12 + j*(165) -50 + j*(8) --50 + j*(1) -4 + j*(67) -45 + j*(-31) --97 + j*(-49) --100 + j*(129) -100 + j*(128) -93 + j*(-74) --117 + j*(-50) --92 + j*(185) -175 + j*(204) -278 + j*(-47) -117 + j*(-231) --79 + j*(-203) --175 + j*(-86) --193 + j*(62) --84 + j*(206) -129 + j*(198) -231 + j*(-6) -102 + j*(-179) --88 + j*(-148) --156 + j*(2) --88 + j*(147) -98 + j*(192) -267 + j*(23) -168 + j*(-235) --110 + j*(-236) --180 + j*(1) --2 + j*(80) -46 + j*(-66) --109 + j*(-97) --160 + j*(77) -1 + j*(176) -139 + j*(74) -117 + j*(-64) -33 + j*(-117) --59 + j*(-117) --161 + j*(-37) --133 + j*(150) -104 + j*(219) -291 + j*(-16) -139 + j*(-310) --199 + j*(-314) --378 + j*(-46) --284 + j*(239) --25 + j*(341) -194 + j*(214) -214 + j*(10) -110 + j*(-87) -23 + j*(-93) --47 + j*(-53) --41 + j*(39) -58 + j*(28) -17 + j*(-89) --136 + j*(-11) --37 + j*(188) -182 + j*(91) -91 + j*(-105) --46 + j*(6) -108 + j*(94) -180 + j*(-86) -37 + j*(-130) -85 + j*(-60) -135 + j*(-260) --185 + j*(-387) --421 + j*(-73) --231 + j*(197) --42 + j*(148) --9 + j*(95) -47 + j*(28) --54 + j*(-99) --247 + j*(40) --104 + j*(290) -146 + j*(186) -71 + j*(12) -3 + j*(115) -165 + j*(115) -146 + j*(-84) --47 + j*(-49) -16 + j*(131) -212 + j*(54) -180 + j*(-160) --13 + j*(-214) --140 + j*(-92) --93 + j*(52) -25 + j*(36) --27 + j*(-58) --121 + j*(58) -49 + j*(178) -180 + j*(-21) --45 + j*(-127) --101 + j*(151) -255 + j*(185) -320 + j*(-228) --79 + j*(-355) --247 + j*(-40) --45 + j*(126) -95 + j*(31) -101 + j*(-80) -32 + j*(-185) --139 + j*(-178) --192 + j*(-7) --73 + j*(47) --81 + j*(-33) --180 + j*(51) --69 + j*(201) -110 + j*(124) -83 + j*(-42) --50 + j*(-42) --71 + j*(80) -69 + j*(144) -213 + j*(-8) -88 + j*(-250) --221 + j*(-203) --274 + j*(106) --42 + j*(234) -100 + j*(119) -87 + j*(26) -66 + j*(-14) -21 + j*(-45) --20 + j*(-9) -13 + j*(8) -4 + j*(-40) --59 + j*(-20) --49 + j*(38) --25 + j*(42) --22 + j*(71) -52 + j*(76) -53 + j*(-28) --86 + j*(-1) --26 + j*(194) -226 + j*(132) -187 + j*(-146) --77 + j*(-126) --53 + j*(110) -164 + j*(88) -166 + j*(-105) -30 + j*(-148) --29 + j*(-98) --57 + j*(-61) --66 + j*(14) -28 + j*(76) -149 + j*(-6) -115 + j*(-182) --88 + j*(-221) --185 + j*(-33) --21 + j*(79) -82 + j*(-96) --125 + j*(-214) --287 + j*(-10) --146 + j*(173) --12 + j*(116) --25 + j*(76) -11 + j*(93) -31 + j*(28) --45 + j*(43) -14 + j*(156) -173 + j*(86) -139 + j*(-89) -6 + j*(-100) --23 + j*(-38) --27 + j*(-8) -13 + j*(44) -117 + j*(-16) -51 + j*(-180) --146 + j*(-136) --134 + j*(37) --23 + j*(21) --78 + j*(-34) --112 + j*(47) --48 + j*(56) --108 + j*(28) --144 + j*(182) -54 + j*(279) -195 + j*(128) -129 + j*(27) -136 + j*(62) -218 + j*(-19) -161 + j*(-156) -49 + j*(-178) --12 + j*(-179) --121 + j*(-172) --220 + j*(-45) --171 + j*(123) --26 + j*(193) -110 + j*(132) -129 + j*(3) -39 + j*(-29) -65 + j*(55) -211 + j*(-35) -109 + j*(-274) --185 + j*(-220) --183 + j*(54) -26 + j*(59) --7 + j*(-98) --143 + j*(-27) --61 + j*(94) -26 + j*(10) --83 + j*(-47) --158 + j*(103) --2 + j*(258) -251 + j*(173) -300 + j*(-131) -28 + j*(-305) --199 + j*(-117) --73 + j*(78) -47 + j*(-50) --134 + j*(-120) --199 + j*(110) -38 + j*(192) -126 + j*(-15) --35 + j*(-98) --124 + j*(2) --126 + j*(100) --49 + j*(239) -209 + j*(235) -294 + j*(-68) -13 + j*(-176) --31 + j*(79) -262 + j*(23) -144 + j*(-357) --298 + j*(-252) --250 + j*(172) -72 + j*(168) -68 + j*(1) -73 + j*(57) -232 + j*(-107) --36 + j*(-400) --446 + j*(-110) --196 + j*(342) -204 + j*(129) --45 + j*(-166) --267 + j*(185) -194 + j*(424) -521 + j*(-70) -105 + j*(-478) --304 + j*(-208) --165 + j*(102) -0 + j*(15) --111 + j*(-33) --99 + j*(129) -104 + j*(97) -68 + j*(-135) --190 + j*(-107) --194 + j*(148) -14 + j*(179) -18 + j*(48) --71 + j*(122) -74 + j*(238) -245 + j*(97) -179 + j*(-89) -52 + j*(-107) --18 + j*(-81) --87 + j*(2) --12 + j*(144) -167 + j*(89) -122 + j*(-79) --1 + j*(-8) -138 + j*(82) -232 + j*(-118) -33 + j*(-228) --41 + j*(-73) -85 + j*(-91) --19 + j*(-235) --194 + j*(-97) --62 + j*(70) -66 + j*(-56) --55 + j*(-144) --111 + j*(-49) --57 + j*(-36) --92 + j*(-65) --105 + j*(-19) --88 + j*(-44) --190 + j*(-34) --196 + j*(132) --33 + j*(165) --22 + j*(61) --68 + j*(141) -124 + j*(167) -168 + j*(-108) --149 + j*(-180) --244 + j*(127) --2 + j*(221) -33 + j*(65) --71 + j*(139) -95 + j*(257) -263 + j*(78) -151 + j*(-98) -33 + j*(-74) -5 + j*(-63) --97 + j*(-25) --93 + j*(167) -140 + j*(245) -302 + j*(45) -200 + j*(-151) -46 + j*(-136) -48 + j*(-49) -122 + j*(-85) -79 + j*(-211) --98 + j*(-222) --182 + j*(-57) --70 + j*(57) -24 + j*(-21) --59 + j*(-98) --161 + j*(4) --69 + j*(160) -134 + j*(116) -154 + j*(-108) --57 + j*(-182) --161 + j*(-10) --42 + j*(93) -23 + j*(33) -18 + j*(42) -133 + j*(21) -133 + j*(-211) --172 + j*(-284) --332 + j*(1) --152 + j*(195) --28 + j*(141) --17 + j*(161) -130 + j*(177) -220 + j*(-8) -100 + j*(-139) -10 + j*(-124) --48 + j*(-148) --190 + j*(-85) --171 + j*(121) -27 + j*(141) -56 + j*(-9) --40 + j*(-22) --37 + j*(16) --66 + j*(1) --113 + j*(91) -0 + j*(174) -98 + j*(89) -57 + j*(23) -44 + j*(35) -30 + j*(5) --23 + j*(73) -120 + j*(161) -271 + j*(-38) -64 + j*(-243) --151 + j*(-73) --24 + j*(100) -72 + j*(12) -13 + j*(2) -74 + j*(50) -113 + j*(-50) -20 + j*(-53) -93 + j*(24) -184 + j*(-129) --1 + j*(-242) --82 + j*(-81) -67 + j*(-92) --29 + j*(-284) --260 + j*(-185) --206 + j*(-7) --161 + j*(-64) --305 + j*(-4) --243 + j*(209) --74 + j*(191) --119 + j*(148) --81 + j*(298) -144 + j*(272) -154 + j*(89) -76 + j*(119) -211 + j*(135) -238 + j*(-69) -45 + j*(-116) -28 + j*(28) -146 + j*(1) -110 + j*(-107) -45 + j*(-105) -16 + j*(-117) --69 + j*(-81) --28 + j*(48) -132 + j*(-17) -42 + j*(-207) --167 + j*(-116) --84 + j*(81) -78 + j*(-4) --19 + j*(-136) --136 + j*(-39) --55 + j*(69) -43 + j*(12) -22 + j*(-86) --69 + j*(-117) --155 + j*(-61) --162 + j*(35) --115 + j*(83) --90 + j*(102) --52 + j*(128) --16 + j*(120) --25 + j*(138) -55 + j*(226) -257 + j*(161) -288 + j*(-102) -76 + j*(-227) --66 + j*(-138) --85 + j*(-68) --132 + j*(-14) --106 + j*(112) -21 + j*(136) -40 + j*(70) -32 + j*(154) -274 + j*(192) -470 + j*(-161) -147 + j*(-558) --358 + j*(-407) --404 + j*(30) --165 + j*(161) --110 + j*(119) --52 + j*(228) -209 + j*(174) -204 + j*(-175) --187 + j*(-217) --269 + j*(175) -78 + j*(296) -209 + j*(49) -89 + j*(-22) -134 + j*(-6) -108 + j*(-174) --145 + j*(-147) --117 + j*(135) -160 + j*(94) -94 + j*(-165) --141 + j*(-80) --43 + j*(127) -132 + j*(31) -54 + j*(-102) --30 + j*(-47) -19 + j*(-6) -48 + j*(-57) -17 + j*(-117) --84 + j*(-141) --181 + j*(-30) --98 + j*(112) -36 + j*(63) -11 + j*(-26) --16 + j*(-16) --29 + j*(-71) --196 + j*(-40) --182 + j*(252) -190 + j*(307) -325 + j*(-54) -77 + j*(-206) -13 + j*(-109) -13 + j*(-216) --254 + j*(-208) --281 + j*(120) -9 + j*(128) --92 + j*(-108) --335 + j*(128) --39 + j*(413) -235 + j*(158) -40 + j*(-4) -47 + j*(185) -272 + j*(43) -58 + j*(-199) --151 + j*(68) -185 + j*(223) -320 + j*(-168) --80 + j*(-320) --244 + j*(13) --34 + j*(158) -46 + j*(89) -90 + j*(115) -222 + j*(21) -141 + j*(-165) --11 + j*(-110) -69 + j*(-47) -57 + j*(-207) --177 + j*(-183) --182 + j*(69) -19 + j*(83) -4 + j*(-45) --62 + j*(29) -73 + j*(46) -56 + j*(-146) --194 + j*(-108) --160 + j*(185) -148 + j*(170) -151 + j*(-126) --126 + j*(-132) --126 + j*(131) -123 + j*(138) -142 + j*(-78) --23 + j*(-88) -12 + j*(37) -146 + j*(-54) -37 + j*(-241) --188 + j*(-173) --185 + j*(35) --38 + j*(55) --45 + j*(-38) --124 + j*(16) --33 + j*(112) -83 + j*(-2) --41 + j*(-153) --229 + j*(-45) --171 + j*(152) --30 + j*(144) --42 + j*(91) --32 + j*(158) -83 + j*(134) -56 + j*(16) --47 + j*(80) -69 + j*(199) -236 + j*(71) -161 + j*(-123) --4 + j*(-136) --93 + j*(-64) --148 + j*(62) --47 + j*(245) -218 + j*(224) -298 + j*(-30) -145 + j*(-163) -47 + j*(-138) --21 + j*(-137) --120 + j*(-38) --23 + j*(128) -176 + j*(43) -117 + j*(-156) --56 + j*(-127) --53 + j*(-14) --11 + j*(-1) -14 + j*(35) -124 + j*(-1) -84 + j*(-180) --141 + j*(-144) --107 + j*(107) -157 + j*(79) -155 + j*(-175) --37 + j*(-204) --59 + j*(-121) --61 + j*(-178) --214 + j*(-185) --306 + j*(-16) --241 + j*(144) --115 + j*(222) -52 + j*(216) -165 + j*(67) -101 + j*(-112) --72 + j*(-145) --185 + j*(-23) --122 + j*(134) -55 + j*(108) -33 + j*(-105) --250 + j*(-77) --265 + j*(286) -128 + j*(386) -296 + j*(48) -64 + j*(-122) --53 + j*(13) -15 + j*(66) -23 + j*(66) -108 + j*(94) -180 + j*(-81) --65 + j*(-205) --232 + j*(86) -78 + j*(267) -239 + j*(-42) --71 + j*(-153) --117 + j*(177) -238 + j*(168) -198 + j*(-204) --176 + j*(-141) --97 + j*(228) -262 + j*(150) -208 + j*(-185) --86 + j*(-157) --82 + j*(98) -142 + j*(136) -242 + j*(-37) -164 + j*(-181) -35 + j*(-193) -2 + j*(-112) -82 + j*(-119) -57 + j*(-270) --162 + j*(-302) --274 + j*(-95) --132 + j*(29) --64 + j*(-79) --197 + j*(-99) --213 + j*(50) --98 + j*(53) --172 + j*(-28) --287 + j*(146) --75 + j*(344) -168 + j*(168) -29 + j*(-42) --130 + j*(121) -88 + j*(276) -290 + j*(46) -116 + j*(-192) --108 + j*(-100) --81 + j*(66) -20 + j*(63) -8 + j*(11) --29 + j*(52) -40 + j*(115) -158 + j*(41) -110 + j*(-136) --104 + j*(-132) --139 + j*(93) -78 + j*(148) -141 + j*(-59) --54 + j*(-121) --123 + j*(51) -1 + j*(128) -66 + j*(78) -93 + j*(68) -163 + j*(-1) -104 + j*(-146) --76 + j*(-124) --93 + j*(61) -79 + j*(119) -188 + j*(-23) -113 + j*(-179) --43 + j*(-187) --100 + j*(-78) --45 + j*(-51) --98 + j*(-113) --233 + j*(1) --123 + j*(232) -156 + j*(174) -148 + j*(-90) --66 + j*(-91) --35 + j*(91) -155 + j*(33) -121 + j*(-197) --119 + j*(-256) --310 + j*(-78) --269 + j*(197) -3 + j*(300) -182 + j*(91) -19 + j*(-75) --105 + j*(106) -130 + j*(225) -284 + j*(-35) -54 + j*(-224) --133 + j*(-47) --6 + j*(124) -160 + j*(51) -171 + j*(-109) -57 + j*(-223) --130 + j*(-194) --180 + j*(4) --11 + j*(92) -74 + j*(-50) --52 + j*(-118) --97 + j*(-11) --3 + j*(7) -8 + j*(-91) --86 + j*(-139) --194 + j*(-109) --279 + j*(10) --231 + j*(179) --83 + j*(216) --47 + j*(160) --45 + j*(217) -106 + j*(235) -167 + j*(57) --2 + j*(1) --26 + j*(185) -186 + j*(215) -257 + j*(21) -141 + j*(-59) -119 + j*(-13) -165 + j*(-59) -110 + j*(-144) -8 + j*(-139) --33 + j*(-65) -11 + j*(-12) -63 + j*(-57) --11 + j*(-122) --100 + j*(-14) -40 + j*(100) -182 + j*(-69) --8 + j*(-233) --179 + j*(-41) -19 + j*(117) -161 + j*(-88) --35 + j*(-218) --136 + j*(-60) --17 + j*(-28) --75 + j*(-149) --241 + j*(-43) --153 + j*(168) -45 + j*(142) -80 + j*(20) -69 + j*(-28) -76 + j*(-134) --96 + j*(-247) --325 + j*(-105) --283 + j*(164) --85 + j*(204) --66 + j*(121) --98 + j*(215) -92 + j*(301) -265 + j*(112) -143 + j*(-83) -3 + j*(-4) -103 + j*(76) -180 + j*(-63) -59 + j*(-177) --62 + j*(-136) --111 + j*(-74) --144 + j*(11) --81 + j*(103) -1 + j*(78) --28 + j*(57) -13 + j*(127) -128 + j*(42) --3 + j*(-99) --172 + j*(89) -55 + j*(308) -307 + j*(102) -168 + j*(-109) -77 + j*(-8) -207 + j*(-42) -105 + j*(-216) --57 + j*(-90) -122 + j*(7) -168 + j*(-257) --159 + j*(-298) --193 + j*(23) -97 + j*(0) -6 + j*(-298) --320 + j*(-202) --291 + j*(93) --113 + j*(110) --132 + j*(59) --149 + j*(163) --18 + j*(245) -150 + j*(180) -192 + j*(-21) --12 + j*(-139) --167 + j*(93) -133 + j*(296) -422 + j*(-64) -78 + j*(-441) --328 + j*(-182) --164 + j*(155) -32 + j*(40) --94 + j*(-28) --88 + j*(132) -64 + j*(98) -8 + j*(21) -30 + j*(139) -245 + j*(49) -146 + j*(-260) --206 + j*(-195) --180 + j*(150) -134 + j*(155) -177 + j*(-130) --66 + j*(-232) --235 + j*(-58) --152 + j*(147) -47 + j*(132) -57 + j*(-49) --119 + j*(-60) --140 + j*(104) --33 + j*(127) --69 + j*(110) --46 + j*(278) -240 + j*(312) -383 + j*(20) -192 + j*(-167) -70 + j*(-82) -132 + j*(-64) -102 + j*(-156) -2 + j*(-146) --12 + j*(-86) -6 + j*(-78) -10 + j*(-89) -1 + j*(-121) --66 + j*(-136) --112 + j*(-70) --74 + j*(-28) --65 + j*(-53) --93 + j*(-38) --75 + j*(-33) --134 + j*(-76) --257 + j*(40) --152 + j*(264) -122 + j*(228) -159 + j*(-25) --31 + j*(-98) --112 + j*(28) --53 + j*(109) -6 + j*(115) -55 + j*(113) -119 + j*(81) -160 + j*(-12) -98 + j*(-134) --69 + j*(-132) --108 + j*(42) -71 + j*(84) -102 + j*(-123) --149 + j*(-164) --233 + j*(99) --30 + j*(226) -82 + j*(144) -124 + j*(140) -285 + j*(53) -253 + j*(-241) --65 + j*(-312) --187 + j*(-81) --78 + j*(-13) --146 + j*(-58) --225 + j*(144) -30 + j*(315) -274 + j*(113) -185 + j*(-124) -39 + j*(-122) -31 + j*(-100) --21 + j*(-143) --119 + j*(-92) --108 + j*(5) --59 + j*(8) --90 + j*(-4) --119 + j*(73) --38 + j*(153) -69 + j*(119) -79 + j*(35) -44 + j*(34) -98 + j*(56) -162 + j*(-49) -58 + j*(-182) --121 + j*(-129) --134 + j*(50) -6 + j*(117) -101 + j*(33) -76 + j*(-61) -10 + j*(-74) --4 + j*(-46) -1 + j*(-69) --63 + j*(-79) --99 + j*(14) -19 + j*(67) -86 + j*(-82) --101 + j*(-184) --262 + j*(23) --74 + j*(246) -199 + j*(108) -130 + j*(-200) --197 + j*(-220) --322 + j*(87) --86 + j*(292) -134 + j*(148) -47 + j*(-25) --66 + j*(71) -64 + j*(151) -130 + j*(-6) --42 + j*(-47) --55 + j*(150) -165 + j*(156) -183 + j*(-57) -16 + j*(-71) -38 + j*(48) -134 + j*(-11) -57 + j*(-99) --16 + j*(-20) -64 + j*(59) -183 + j*(12) -243 + j*(-139) -146 + j*(-344) --136 + j*(-390) --310 + j*(-160) --190 + j*(20) --101 + j*(-61) --244 + j*(-89) --314 + j*(119) --135 + j*(274) -37 + j*(193) -9 + j*(93) --30 + j*(167) -136 + j*(244) -330 + j*(52) -206 + j*(-245) --100 + j*(-232) --156 + j*(-1) --20 + j*(57) --2 + j*(-8) --21 + j*(8) -9 + j*(-23) --84 + j*(-71) --172 + j*(70) --40 + j*(197) -71 + j*(134) -69 + j*(122) -204 + j*(131) -289 + j*(-105) -48 + j*(-267) --117 + j*(-80) -29 + j*(9) -35 + j*(-146) --147 + j*(-115) --127 + j*(57) --21 + j*(53) --33 + j*(38) -35 + j*(74) -91 + j*(-54) --83 + j*(-115) --143 + j*(86) -59 + j*(139) -90 + j*(-30) --27 + j*(-8) -72 + j*(67) -134 + j*(-110) --86 + j*(-178) --147 + j*(43) -63 + j*(65) -36 + j*(-163) --241 + j*(-127) --261 + j*(175) --10 + j*(271) -105 + j*(127) -33 + j*(82) -76 + j*(185) -282 + j*(139) -342 + j*(-134) -117 + j*(-313) --91 + j*(-217) --93 + j*(-85) --62 + j*(-66) --66 + j*(-48) --45 + j*(-54) --103 + j*(-93) --198 + j*(10) --96 + j*(158) -62 + j*(83) --5 + j*(-36) --83 + j*(56) -40 + j*(118) -115 + j*(-21) --5 + j*(-117) --124 + j*(-46) --124 + j*(76) --24 + j*(152) -101 + j*(85) -59 + j*(-54) --82 + j*(-16) --40 + j*(128) -96 + j*(98) -89 + j*(8) -78 + j*(14) -117 + j*(-49) -11 + j*(-134) --95 + j*(-16) -24 + j*(91) -124 + j*(-26) -34 + j*(-121) --38 + j*(-86) --65 + j*(-70) --132 + j*(-6) --73 + j*(136) -105 + j*(129) -165 + j*(-20) -114 + j*(-127) -27 + j*(-206) --149 + j*(-214) --279 + j*(-35) --199 + j*(165) --30 + j*(222) -127 + j*(180) -237 + j*(3) -117 + j*(-216) --130 + j*(-172) --134 + j*(24) --23 + j*(24) --66 + j*(-16) --55 + j*(66) -30 + j*(5) --110 + j*(-68) --191 + j*(171) -123 + j*(295) -298 + j*(-30) -11 + j*(-223) --153 + j*(-2) -4 + j*(105) -43 + j*(1) --23 + j*(31) -62 + j*(81) -114 + j*(-18) -42 + j*(-70) -21 + j*(-55) --17 + j*(-88) --118 + j*(-25) --51 + j*(135) -152 + j*(98) -173 + j*(-116) --1 + j*(-206) --134 + j*(-121) --135 + j*(-4) --72 + j*(30) --74 + j*(0) --143 + j*(57) --77 + j*(211) -144 + j*(200) -202 + j*(-10) -59 + j*(-81) -58 + j*(10) -178 + j*(-93) -22 + j*(-322) --337 + j*(-206) --330 + j*(221) -78 + j*(327) -239 + j*(-14) --35 + j*(-155) --123 + j*(98) -151 + j*(136) -168 + j*(-165) --141 + j*(-185) --166 + j*(93) -47 + j*(113) -43 + j*(-6) -30 + j*(49) -165 + j*(-33) -17 + j*(-255) --269 + j*(-81) --86 + j*(231) -225 + j*(40) -30 + j*(-259) --252 + j*(-91) --139 + j*(146) -13 + j*(98) -14 + j*(58) -77 + j*(35) -42 + j*(-102) --147 + j*(-42) --55 + j*(191) -230 + j*(76) -115 + j*(-262) --256 + j*(-185) --249 + j*(168) --23 + j*(28) -142 + j*(89) -243 + j*(-152) --11 + j*(-301) --160 + j*(-95) --9 + j*(-13) --18 + j*(-156) --180 + j*(-100) --137 + j*(49) --59 + j*(32) --93 + j*(57) -9 + j*(139) -139 + j*(30) -85 + j*(-95) -49 + j*(-113) --1 + j*(-236) --292 + j*(-232) --390 + j*(163) -18 + j*(347) -232 + j*(-16) --69 + j*(-199) --178 + j*(31) --9 + j*(29) --153 + j*(-123) --350 + j*(132) --78 + j*(395) -177 + j*(175) --3 + j*(17) --54 + j*(233) -233 + j*(250) -274 + j*(-47) -47 + j*(-99) -62 + j*(39) -161 + j*(-92) --80 + j*(-226) --301 + j*(77) --18 + j*(404) -385 + j*(230) -369 + j*(-156) -106 + j*(-264) --22 + j*(-159) --18 + j*(-98) --25 + j*(-91) --62 + j*(-67) --71 + j*(3) -14 + j*(64) -128 + j*(-19) -71 + j*(-185) --119 + j*(-175) --159 + j*(-13) --60 + j*(39) --55 + j*(-1) --75 + j*(60) -33 + j*(105) -115 + j*(1) -66 + j*(-100) -3 + j*(-122) --59 + j*(-150) --186 + j*(-126) --264 + j*(36) --168 + j*(209) -22 + j*(231) -126 + j*(107) -83 + j*(4) -36 + j*(27) -107 + j*(28) -112 + j*(-110) --60 + j*(-147) --120 + j*(21) -26 + j*(76) -58 + j*(-45) --23 + j*(-40) -44 + j*(-8) -48 + j*(-170) --195 + j*(-199) --287 + j*(54) --105 + j*(174) --40 + j*(91) --74 + j*(122) -21 + j*(158) -40 + j*(59) --60 + j*(115) -76 + j*(275) -334 + j*(137) -289 + j*(-160) -68 + j*(-228) --31 + j*(-156) --88 + j*(-124) --161 + j*(-33) --124 + j*(107) -8 + j*(153) -107 + j*(76) -85 + j*(-28) --11 + j*(-13) -36 + j*(100) -209 + j*(28) -150 + j*(-202) --91 + j*(-184) --93 + j*(16) -47 + j*(-1) --6 + j*(-98) --74 + j*(-21) -4 + j*(15) -9 + j*(-45) --18 + j*(-18) -45 + j*(-42) --28 + j*(-154) --188 + j*(-57) --95 + j*(119) -54 + j*(37) --26 + j*(-59) --64 + j*(36) -48 + j*(21) -4 + j*(-108) --123 + j*(-68) --115 + j*(13) --122 + j*(18) --150 + j*(101) --64 + j*(182) -11 + j*(168) -74 + j*(197) -255 + j*(128) -258 + j*(-156) --20 + j*(-245) --132 + j*(-64) --83 + j*(-25) --188 + j*(30) --97 + j*(302) -292 + j*(246) -298 + j*(-159) --21 + j*(-179) -32 + j*(19) -153 + j*(-161) --119 + j*(-269) --227 + j*(11) -1 + j*(71) --40 + j*(-97) --175 + j*(52) -53 + j*(170) -153 + j*(-105) --145 + j*(-195) --250 + j*(85) --49 + j*(207) -48 + j*(129) -69 + j*(92) -109 + j*(19) -41 + j*(-40) -16 + j*(28) -91 + j*(10) -21 + j*(-59) --27 + j*(63) -158 + j*(100) -209 + j*(-114) -35 + j*(-167) -47 + j*(-66) -111 + j*(-199) --112 + j*(-295) --257 + j*(-64) --81 + j*(86) -22 + j*(-27) --33 + j*(-78) --40 + j*(-95) --135 + j*(-163) --308 + j*(-43) --243 + j*(182) --76 + j*(193) --74 + j*(161) --16 + j*(262) -194 + j*(226) -250 + j*(6) -122 + j*(-113) -16 + j*(-117) --87 + j*(-83) --140 + j*(62) --11 + j*(180) -116 + j*(110) -89 + j*(40) -112 + j*(82) -233 + j*(13) -198 + j*(-182) --1 + j*(-221) --87 + j*(-75) -7 + j*(4) -69 + j*(-75) --1 + j*(-138) --55 + j*(-95) --35 + j*(-101) --127 + j*(-163) --291 + j*(-27) --199 + j*(238) -83 + j*(233) -132 + j*(16) --4 + j*(-6) -42 + j*(98) -173 + j*(21) -136 + j*(-142) -4 + j*(-189) --103 + j*(-150) --156 + j*(-56) --114 + j*(25) --72 + j*(-2) --146 + j*(-1) --158 + j*(125) --50 + j*(185) -4 + j*(173) -88 + j*(221) -277 + j*(117) -223 + j*(-158) --43 + j*(-142) -3 + j*(74) -201 + j*(-54) -4 + j*(-277) --254 + j*(-63) --64 + j*(196) -165 + j*(43) -50 + j*(-132) --64 + j*(-62) --34 + j*(-21) --73 + j*(-23) --63 + j*(88) -105 + j*(88) -138 + j*(-120) --75 + j*(-207) --221 + j*(-44) --150 + j*(121) --31 + j*(136) -4 + j*(95) --1 + j*(103) -50 + j*(145) -151 + j*(125) -222 + j*(25) -218 + j*(-111) -110 + j*(-235) --87 + j*(-225) --169 + j*(-39) --33 + j*(73) -58 + j*(-28) --32 + j*(-81) --56 + j*(-4) -0 + j*(-13) --52 + j*(-40) --47 + j*(54) -88 + j*(6) --13 + j*(-171) --248 + j*(-30) --103 + j*(257) -195 + j*(141) -110 + j*(-98) --19 + j*(-1) -159 + j*(16) -120 + j*(-291) --305 + j*(-276) --378 + j*(201) -63 + j*(371) -286 + j*(28) -67 + j*(-182) --76 + j*(-67) --17 + j*(-21) --61 + j*(-85) --170 + j*(4) --101 + j*(160) -56 + j*(147) -92 + j*(47) -78 + j*(16) -103 + j*(-33) -47 + j*(-131) --84 + j*(-116) --113 + j*(-16) --83 + j*(1) --139 + j*(10) --166 + j*(136) --43 + j*(240) -93 + j*(202) -138 + j*(125) -150 + j*(73) -153 + j*(25) -153 + j*(-23) -118 + j*(-97) --18 + j*(-105) --68 + j*(83) -180 + j*(184) -353 + j*(-104) -77 + j*(-334) --151 + j*(-103) -63 + j*(66) -168 + j*(-168) --89 + j*(-233) --119 + j*(25) -132 + j*(16) -107 + j*(-228) --86 + j*(-214) --54 + j*(-138) --92 + j*(-265) --349 + j*(-207) --356 + j*(107) --93 + j*(160) --73 + j*(-28) --248 + j*(10) --212 + j*(209) --37 + j*(228) -18 + j*(128) --33 + j*(85) --90 + j*(137) --46 + j*(281) -199 + j*(336) -417 + j*(77) -261 + j*(-259) --77 + j*(-247) --156 + j*(1) --24 + j*(88) -17 + j*(42) -16 + j*(64) -92 + j*(48) -74 + j*(-57) --51 + j*(-31) --7 + j*(107) -146 + j*(42) -68 + j*(-126) --114 + j*(-33) --16 + j*(158) -170 + j*(69) -87 + j*(-78) --1 + j*(31) -176 + j*(82) -247 + j*(-149) -19 + j*(-266) --98 + j*(-95) -27 + j*(-35) -33 + j*(-168) --127 + j*(-173) --180 + j*(-40) --136 + j*(45) --74 + j*(109) -67 + j*(114) -138 + j*(-57) --23 + j*(-173) --140 + j*(-45) --43 + j*(23) --66 + j*(-90) --259 + j*(13) --144 + j*(330) -278 + j*(287) -363 + j*(-161) --17 + j*(-372) --299 + j*(-127) --216 + j*(142) --33 + j*(185) -62 + j*(124) -99 + j*(53) -91 + j*(-22) -33 + j*(-68) --33 + j*(-50) --51 + j*(11) -7 + j*(47) -59 + j*(-15) --10 + j*(-90) --110 + j*(-23) --59 + j*(87) -34 + j*(46) --17 + j*(-21) --74 + j*(53) -9 + j*(121) -81 + j*(61) -57 + j*(22) -82 + j*(31) -119 + j*(-49) -18 + j*(-129) --86 + j*(-42) --18 + j*(55) -60 + j*(-11) --16 + j*(-70) --66 + j*(14) -22 + j*(47) -23 + j*(-51) --113 + j*(-11) --48 + j*(196) -238 + j*(147) -247 + j*(-192) --85 + j*(-257) --155 + j*(30) -103 + j*(41) -40 + j*(-253) --333 + j*(-172) --313 + j*(243) -45 + j*(299) -109 + j*(74) --7 + j*(95) -122 + j*(183) -224 + j*(11) -69 + j*(-73) -57 + j*(95) -303 + j*(52) -310 + j*(-268) -7 + j*(-387) --173 + j*(-211) --130 + j*(-76) --92 + j*(-74) --115 + j*(-60) --124 + j*(-13) --91 + j*(41) --10 + j*(51) -42 + j*(-41) --47 + j*(-139) --182 + j*(-78) --173 + j*(54) --92 + j*(66) --122 + j*(40) --153 + j*(150) --4 + j*(240) -147 + j*(111) -57 + j*(-50) --78 + j*(25) -3 + j*(144) -118 + j*(59) -32 + j*(-44) --53 + j*(49) -57 + j*(134) -166 + j*(28) -100 + j*(-100) --23 + j*(-94) --69 + j*(-5) --24 + j*(75) -73 + j*(71) -105 + j*(-28) -19 + j*(-87) --48 + j*(-28) --14 + j*(33) -34 + j*(14) -28 + j*(-35) --40 + j*(-55) --118 + j*(28) --57 + j*(181) -138 + j*(190) -226 + j*(35) -182 + j*(-69) -153 + j*(-136) -42 + j*(-231) --151 + j*(-138) --90 + j*(93) -134 + j*(37) -58 + j*(-165) --120 + j*(-41) -66 + j*(122) -249 + j*(-115) -25 + j*(-331) --183 + j*(-188) --133 + j*(-76) --165 + j*(-93) --202 + j*(42) --27 + j*(93) --12 + j*(-100) --242 + j*(-66) --185 + j*(194) -54 + j*(130) --50 + j*(-53) --193 + j*(125) -37 + j*(274) -191 + j*(54) -31 + j*(-66) --7 + j*(38) -71 + j*(-16) --44 + j*(-88) --101 + j*(44) -20 + j*(53) --57 + j*(-65) --210 + j*(97) --16 + j*(304) -215 + j*(141) -97 + j*(-46) --6 + j*(60) -120 + j*(99) -136 + j*(-38) -18 + j*(-38) -42 + j*(48) -107 + j*(1) -57 + j*(-47) -26 + j*(5) -81 + j*(33) -141 + j*(0) -173 + j*(-95) -95 + j*(-210) --70 + j*(-194) --105 + j*(-44) -3 + j*(1) -30 + j*(-78) --32 + j*(-98) --53 + j*(-66) --62 + j*(-49) --61 + j*(-18) --31 + j*(-13) --39 + j*(-23) --13 + j*(19) -91 + j*(-51) --1 + j*(-260) --320 + j*(-216) --397 + j*(143) --115 + j*(337) -115 + j*(214) -139 + j*(40) -49 + j*(-75) --118 + j*(-44) --129 + j*(173) -124 + j*(238) -250 + j*(3) -105 + j*(-143) -11 + j*(-124) --68 + j*(-156) --247 + j*(-36) --146 + j*(260) -207 + j*(206) -195 + j*(-151) --132 + j*(-167) --176 + j*(112) -36 + j*(192) -151 + j*(66) -110 + j*(-78) --63 + j*(-106) --148 + j*(112) -112 + j*(264) -325 + j*(5) -118 + j*(-218) --31 + j*(-66) -116 + j*(-28) -83 + j*(-211) --91 + j*(-182) --86 + j*(-112) --183 + j*(-161) --344 + j*(81) --52 + j*(357) -272 + j*(78) -11 + j*(-212) --203 + j*(57) -82 + j*(208) -194 + j*(-78) --54 + j*(-166) --121 + j*(7) --37 + j*(44) --34 + j*(38) -3 + j*(48) --25 + j*(-1) --94 + j*(120) -136 + j*(245) -339 + j*(-54) -30 + j*(-305) --209 + j*(-25) -49 + j*(156) -170 + j*(-87) --35 + j*(-169) --88 + j*(-43) --66 + j*(-39) --115 + j*(36) -23 + j*(114) -80 + j*(-83) --192 + j*(-81) --143 + j*(287) -305 + j*(229) -269 + j*(-241) --158 + j*(-226) --134 + j*(123) -133 + j*(91) -112 + j*(-100) -21 + j*(-112) --12 + j*(-141) --151 + j*(-126) --176 + j*(70) -25 + j*(135) -128 + j*(-49) --12 + j*(-217) --269 + j*(-181) --410 + j*(129) --139 + j*(447) -255 + j*(280) -152 + j*(-53) --63 + j*(101) -237 + j*(246) -395 + j*(-192) --105 + j*(-402) --348 + j*(83) -75 + j*(325) -288 + j*(1) -97 + j*(-154) -42 + j*(-95) -8 + j*(-169) --168 + j*(-93) --78 + j*(130) -153 + j*(20) -26 + j*(-214) --209 + j*(-102) --149 + j*(105) --20 + j*(105) -6 + j*(71) -43 + j*(59) -47 + j*(8) -25 + j*(18) -91 + j*(8) -78 + j*(-132) --117 + j*(-150) --182 + j*(47) --35 + j*(133) -28 + j*(59) -6 + j*(62) -74 + j*(63) -69 + j*(-37) --41 + j*(-14) -18 + j*(109) -173 + j*(21) -81 + j*(-160) --103 + j*(-80) --34 + j*(78) -88 + j*(11) -18 + j*(-66) --6 + j*(19) -110 + j*(-4) -63 + j*(-157) --106 + j*(-113) --64 + j*(42) -68 + j*(-10) -10 + j*(-130) --93 + j*(-92) --92 + j*(-38) --109 + j*(-23) --107 + j*(44) --27 + j*(44) --62 + j*(-31) --153 + j*(49) --58 + j*(158) -23 + j*(69) --84 + j*(64) --25 + j*(244) -223 + j*(180) -191 + j*(-71) -10 + j*(-33) -115 + j*(78) -214 + j*(-107) -6 + j*(-233) --123 + j*(-74) --34 + j*(-1) --45 + j*(-49) --81 + j*(33) -39 + j*(55) -24 + j*(-92) --163 + j*(-40) --100 + j*(196) -172 + j*(156) -171 + j*(-119) --78 + j*(-161) --156 + j*(51) -6 + j*(148) -101 + j*(45) -38 + j*(-13) -35 + j*(58) -165 + j*(34) -175 + j*(-161) --36 + j*(-250) --189 + j*(-88) --101 + j*(69) -21 + j*(22) --23 + j*(-78) --138 + j*(-33) --126 + j*(103) --8 + j*(134) -12 + j*(66) --43 + j*(127) -112 + j*(260) -383 + j*(100) -330 + j*(-258) -23 + j*(-337) --91 + j*(-199) --110 + j*(-185) --264 + j*(-117) --245 + j*(149) -30 + j*(205) -112 + j*(-11) --33 + j*(-68) --39 + j*(21) -15 + j*(-33) --98 + j*(-83) --180 + j*(64) --58 + j*(203) -113 + j*(162) -166 + j*(11) -74 + j*(-98) --35 + j*(-45) -30 + j*(42) -125 + j*(-70) --13 + j*(-211) --194 + j*(-110) --166 + j*(54) --81 + j*(71) --74 + j*(62) --68 + j*(71) --101 + j*(92) --91 + j*(233) -141 + j*(305) -310 + j*(66) -131 + j*(-126) -1 + j*(6) -140 + j*(49) -129 + j*(-116) --45 + j*(-67) -49 + j*(110) -257 + j*(-18) -165 + j*(-269) --75 + j*(-278) --187 + j*(-138) --194 + j*(9) --90 + j*(130) -77 + j*(91) -92 + j*(-62) --18 + j*(-95) --43 + j*(-37) --19 + j*(-49) --71 + j*(-74) --126 + j*(-21) --115 + j*(54) --66 + j*(91) --29 + j*(91) --13 + j*(107) -62 + j*(142) -178 + j*(54) -115 + j*(-120) --73 + j*(-76) --18 + j*(118) -209 + j*(47) -165 + j*(-208) --64 + j*(-236) --146 + j*(-114) --171 + j*(-52) --197 + j*(86) --19 + j*(215) -181 + j*(56) -65 + j*(-170) --143 + j*(-106) --127 + j*(49) --51 + j*(53) --61 + j*(43) --43 + j*(68) --45 + j*(40) --124 + j*(97) --59 + j*(291) -234 + j*(317) -419 + j*(34) -269 + j*(-258) -0 + j*(-274) --101 + j*(-117) --46 + j*(-37) --21 + j*(-72) --90 + j*(-83) --137 + j*(1) --93 + j*(83) --21 + j*(95) -9 + j*(76) -27 + j*(77) -75 + j*(76) -117 + j*(24) -112 + j*(-40) -88 + j*(-76) -69 + j*(-136) --57 + j*(-201) --231 + j*(-71) --143 + j*(190) -165 + j*(153) -162 + j*(-180) --190 + j*(-209) --260 + j*(144) -57 + j*(249) -159 + j*(-2) --35 + j*(-54) --25 + j*(131) -188 + j*(100) -193 + j*(-130) -9 + j*(-199) --107 + j*(-110) --122 + j*(3) --39 + j*(104) -126 + j*(49) -95 + j*(-164) --158 + j*(-164) --190 + j*(103) -61 + j*(153) -91 + j*(-58) --81 + j*(-35) -20 + j*(119) -177 + j*(-62) --69 + j*(-240) --276 + j*(49) -34 + j*(281) -285 + j*(-22) -19 + j*(-272) --194 + j*(-66) --27 + j*(69) -28 + j*(-104) --188 + j*(-129) --248 + j*(105) --57 + j*(221) -81 + j*(108) -33 + j*(-18) --84 + j*(-7) --110 + j*(110) --21 + j*(176) -41 + j*(153) -64 + j*(177) -202 + j*(193) -331 + j*(9) -216 + j*(-207) -10 + j*(-214) --82 + j*(-117) --124 + j*(-12) --60 + j*(143) -165 + j*(153) -257 + j*(-86) -69 + j*(-237) --88 + j*(-146) --94 + j*(-47) --86 + j*(23) -16 + j*(106) -173 + j*(-12) -57 + j*(-231) --211 + j*(-134) --149 + j*(158) -141 + j*(144) -181 + j*(-113) --13 + j*(-198) --105 + j*(-86) --56 + j*(-25) --36 + j*(-57) --80 + j*(-63) --96 + j*(-18) --71 + j*(-6) --88 + j*(-24) --124 + j*(11) --108 + j*(51) --127 + j*(59) --153 + j*(185) -56 + j*(325) -334 + j*(108) -181 + j*(-267) --224 + j*(-204) --241 + j*(168) -48 + j*(234) -113 + j*(47) -2 + j*(36) -62 + j*(136) -213 + j*(46) -154 + j*(-175) --127 + j*(-190) --233 + j*(129) -107 + j*(342) -432 + j*(21) -193 + j*(-389) --214 + j*(-258) --167 + j*(44) --10 + j*(-9) --145 + j*(-54) --161 + j*(165) -77 + j*(206) -124 + j*(30) -33 + j*(39) -134 + j*(86) -187 + j*(-78) -29 + j*(-138) -6 + j*(-11) -123 + j*(-55) -44 + j*(-189) --88 + j*(-116) --22 + j*(-35) -0 + j*(-133) --151 + j*(-132) --167 + j*(40) --13 + j*(62) --16 + j*(-68) --141 + j*(-30) --83 + j*(93) -20 + j*(7) --124 + j*(-78) --226 + j*(129) -3 + j*(272) -150 + j*(62) --44 + j*(-34) --73 + j*(190) -191 + j*(197) -207 + j*(-57) -29 + j*(-50) -119 + j*(46) -187 + j*(-148) --65 + j*(-232) --148 + j*(8) -50 + j*(37) --4 + j*(-137) --182 + j*(-20) --45 + j*(158) -105 + j*(30) --4 + j*(-66) --45 + j*(23) -9 + j*(13) --52 + j*(4) --19 + j*(126) -153 + j*(77) -108 + j*(-109) --53 + j*(-69) -4 + j*(52) -96 + j*(-33) -2 + j*(-112) --69 + j*(-32) --9 + j*(22) -33 + j*(-21) -0 + j*(-68) --62 + j*(-46) --46 + j*(37) -66 + j*(11) -30 + j*(-150) --177 + j*(-118) --157 + j*(100) -45 + j*(60) --61 + j*(-139) --303 + j*(23) --157 + j*(322) -144 + j*(255) -147 + j*(33) -25 + j*(8) -7 + j*(61) -13 + j*(86) -44 + j*(142) -145 + j*(150) -210 + j*(77) -241 + j*(18) -287 + j*(-81) -238 + j*(-244) -66 + j*(-323) --96 + j*(-256) --141 + j*(-104) --23 + j*(-13) -90 + j*(-146) --77 + j*(-325) --341 + j*(-188) --293 + j*(81) --135 + j*(83) --202 + j*(64) --162 + j*(275) -168 + j*(275) -245 + j*(-84) --76 + j*(-218) --229 + j*(35) --60 + j*(180) -47 + j*(89) -11 + j*(42) -16 + j*(64) -44 + j*(25) --13 + j*(-21) --99 + j*(47) --55 + j*(198) -146 + j*(237) -291 + j*(61) -218 + j*(-129) -86 + j*(-161) -35 + j*(-143) --24 + j*(-154) --101 + j*(-112) --124 + j*(-42) --135 + j*(21) --102 + j*(127) -57 + j*(161) -150 + j*(1) -18 + j*(-112) --95 + j*(-10) --21 + j*(100) -87 + j*(67) -116 + j*(-28) -54 + j*(-124) --98 + j*(-109) --133 + j*(77) -69 + j*(161) -203 + j*(-35) -54 + j*(-216) --146 + j*(-167) --224 + j*(-10) --188 + j*(171) -14 + j*(291) -250 + j*(158) -218 + j*(-100) -19 + j*(-132) --16 + j*(-2) -76 + j*(18) -112 + j*(-52) -95 + j*(-116) -40 + j*(-169) --35 + j*(-170) --69 + j*(-151) --129 + j*(-165) --239 + j*(-93) --221 + j*(59) --125 + j*(80) --156 + j*(69) --143 + j*(208) -67 + j*(241) -147 + j*(46) -19 + j*(-22) -22 + j*(44) -44 + j*(-50) --145 + j*(-43) --127 + j*(237) -229 + j*(223) -235 + j*(-165) --151 + j*(-180) --155 + j*(177) -153 + j*(168) -124 + j*(-74) --42 + j*(-8) -70 + j*(91) -132 + j*(-57) --16 + j*(-89) --14 + j*(28) -62 + j*(-24) --44 + j*(-62) --59 + j*(84) -106 + j*(90) -103 + j*(-62) --1 + j*(-36) -63 + j*(8) -52 + j*(-102) --98 + j*(-39) -11 + j*(155) -250 + j*(24) -140 + j*(-243) --105 + j*(-181) --74 + j*(-2) -33 + j*(-24) -21 + j*(-81) -16 + j*(-94) --13 + j*(-163) --137 + j*(-158) --172 + j*(-35) --105 + j*(8) --95 + j*(-8) --82 + j*(9) --61 + j*(-47) --184 + j*(-91) --302 + j*(69) --197 + j*(250) --46 + j*(255) -18 + j*(230) -116 + j*(202) -153 + j*(69) -47 + j*(14) -29 + j*(103) -125 + j*(91) -109 + j*(3) -63 + j*(23) -106 + j*(21) -71 + j*(-32) -40 + j*(49) -194 + j*(54) -204 + j*(-183) --79 + j*(-221) --124 + j*(70) -163 + j*(100) -186 + j*(-181) --60 + j*(-213) --83 + j*(-37) -16 + j*(-55) --47 + j*(-115) --82 + j*(-51) --53 + j*(-66) --161 + j*(-73) --185 + j*(126) -58 + j*(189) -151 + j*(-55) --72 + j*(-164) --196 + j*(13) --115 + j*(155) -0 + j*(219) -228 + j*(195) -358 + j*(-156) --49 + j*(-463) --512 + j*(-72) --199 + j*(486) -371 + j*(288) -278 + j*(-197) --54 + j*(-151) -15 + j*(26) -78 + j*(-95) --64 + j*(-87) -24 + j*(35) -124 + j*(-163) --172 + j*(-277) --321 + j*(49) --28 + j*(185) -27 + j*(-65) --226 + j*(-18) --119 + j*(266) -170 + j*(151) -62 + j*(-108) --163 + j*(-12) --113 + j*(191) -39 + j*(240) -192 + j*(206) -313 + j*(23) -193 + j*(-197) --11 + j*(-159) -4 + j*(-62) --11 + j*(-136) --180 + j*(-67) --119 + j*(165) -107 + j*(136) -76 + j*(-18) -13 + j*(76) -216 + j*(109) -313 + j*(-185) -30 + j*(-404) --285 + j*(-245) --296 + j*(75) --49 + j*(220) -146 + j*(54) -26 + j*(-124) --112 + j*(8) -83 + j*(111) -186 + j*(-162) --133 + j*(-306) --315 + j*(-18) --127 + j*(135) --94 + j*(33) --190 + j*(153) -16 + j*(314) -231 + j*(128) -124 + j*(-67) -6 + j*(-33) --10 + j*(6) --33 + j*(81) -122 + j*(173) -308 + j*(-51) -71 + j*(-327) --252 + j*(-132) --125 + j*(173) -107 + j*(110) -95 + j*(-14) -96 + j*(-24) -103 + j*(-139) --78 + j*(-181) --139 + j*(-2) -4 + j*(33) --23 + j*(-80) --119 + j*(13) -23 + j*(93) -81 + j*(-90) --136 + j*(-134) --177 + j*(100) -45 + j*(131) -47 + j*(-78) --180 + j*(-56) --181 + j*(211) -100 + j*(286) -260 + j*(47) -89 + j*(-166) --144 + j*(-52) --66 + j*(201) -208 + j*(168) -238 + j*(-100) -21 + j*(-173) --49 + j*(-18) -68 + j*(19) -83 + j*(-82) -11 + j*(-84) -57 + j*(-57) -86 + j*(-197) --140 + j*(-319) --407 + j*(-100) --293 + j*(264) -62 + j*(272) -123 + j*(-11) --105 + j*(-58) --134 + j*(163) -80 + j*(209) -155 + j*(46) -71 + j*(-19) -59 + j*(8) -74 + j*(-35) -5 + j*(-65) --40 + j*(6) -34 + j*(63) -116 + j*(-18) -32 + j*(-153) --170 + j*(-86) --151 + j*(177) -139 + j*(230) -243 + j*(-25) -66 + j*(-116) -74 + j*(6) -221 + j*(-123) -40 + j*(-356) --243 + j*(-229) --197 + j*(-8) --124 + j*(-42) --238 + j*(3) --178 + j*(206) -31 + j*(197) -49 + j*(81) -47 + j*(99) -131 + j*(35) -40 + j*(-76) --39 + j*(45) -158 + j*(82) -191 + j*(-202) --130 + j*(-276) --243 + j*(3) --60 + j*(94) --45 + j*(-2) --97 + j*(67) -23 + j*(94) -18 + j*(-47) --141 + j*(-11) --109 + j*(154) -14 + j*(155) -25 + j*(129) -100 + j*(160) -185 + j*(37) -62 + j*(-59) -3 + j*(79) -188 + j*(106) -227 + j*(-115) -23 + j*(-181) --41 + j*(-38) -45 + j*(1) -62 + j*(-45) -61 + j*(-53) -73 + j*(-99) -13 + j*(-140) --21 + j*(-116) --33 + j*(-151) --171 + j*(-154) --229 + j*(52) --4 + j*(153) -103 + j*(-88) --177 + j*(-197) --326 + j*(118) --32 + j*(326) -197 + j*(108) -51 + j*(-71) --46 + j*(61) -132 + j*(113) -211 + j*(-117) --11 + j*(-269) --214 + j*(-139) --204 + j*(35) --146 + j*(99) --97 + j*(165) -25 + j*(192) -98 + j*(83) -19 + j*(37) -25 + j*(147) -209 + j*(139) -269 + j*(-86) -95 + j*(-238) --99 + j*(-180) --173 + j*(-10) --62 + j*(173) -209 + j*(134) -254 + j*(-197) --91 + j*(-333) --283 + j*(-34) --62 + j*(144) -40 + j*(-25) --119 + j*(-35) --71 + j*(138) -100 + j*(65) -6 + j*(-73) --84 + j*(53) -74 + j*(112) -125 + j*(-59) --14 + j*(-108) --41 + j*(-36) --42 + j*(-70) --158 + j*(-33) --133 + j*(139) -28 + j*(144) -23 + j*(42) --23 + j*(112) -120 + j*(163) -221 + j*(-5) -98 + j*(-145) --37 + j*(-106) --77 + j*(-18) --59 + j*(86) -88 + j*(149) -236 + j*(-10) -112 + j*(-234) --153 + j*(-170) --163 + j*(105) -103 + j*(191) -279 + j*(-30) -151 + j*(-290) --133 + j*(-298) --257 + j*(-75) --139 + j*(90) --11 + j*(49) --37 + j*(-28) --92 + j*(16) --48 + j*(84) -35 + j*(72) -73 + j*(-1) -42 + j*(-86) --60 + j*(-117) --154 + j*(-37) --120 + j*(92) -1 + j*(97) -3 + j*(-5) --102 + j*(25) --38 + j*(170) -160 + j*(95) -95 + j*(-149) --180 + j*(-106) --170 + j*(175) -74 + j*(199) -105 + j*(33) -28 + j*(47) -117 + j*(69) -129 + j*(-82) --30 + j*(-98) --29 + j*(21) -37 + j*(-44) --129 + j*(-81) --194 + j*(180) -102 + j*(317) -298 + j*(81) -173 + j*(-95) -102 + j*(-45) -161 + j*(-87) -81 + j*(-207) --82 + j*(-163) --88 + j*(-7) -56 + j*(30) -127 + j*(-134) --72 + j*(-274) --305 + j*(-72) --132 + j*(230) -192 + j*(95) -82 + j*(-211) --176 + j*(-114) --77 + j*(59) --11 + j*(-83) --235 + j*(-65) --198 + j*(243) -132 + j*(240) -163 + j*(-30) -12 + j*(-59) -31 + j*(-41) --71 + j*(-137) --261 + j*(53) --30 + j*(332) -298 + j*(107) -107 + j*(-206) --142 + j*(-31) -54 + j*(141) -179 + j*(-92) --74 + j*(-200) --170 + j*(34) -23 + j*(98) -40 + j*(-74) --140 + j*(-59) --141 + j*(135) -32 + j*(186) -118 + j*(77) -79 + j*(4) -48 + j*(21) -94 + j*(35) -141 + j*(-46) -68 + j*(-148) --57 + j*(-112) --39 + j*(-5) -47 + j*(-55) --49 + j*(-160) --205 + j*(-52) --132 + j*(129) -9 + j*(98) --30 + j*(44) --6 + j*(156) -211 + j*(107) -202 + j*(-187) --104 + j*(-248) --214 + j*(-8) --91 + j*(83) --95 + j*(62) --86 + j*(191) -116 + j*(219) -183 + j*(42) -83 + j*(14) -173 + j*(68) -264 + j*(-135) -28 + j*(-305) --180 + j*(-119) --67 + j*(59) -47 + j*(-4) -14 + j*(-62) --4 + j*(-70) --54 + j*(-95) --126 + j*(-25) --64 + j*(67) -6 + j*(30) --21 + j*(11) -15 + j*(41) -45 + j*(-38) --64 + j*(-52) --44 + j*(86) -132 + j*(28) -57 + j*(-187) --176 + j*(-132) --165 + j*(63) --75 + j*(78) --80 + j*(124) -78 + j*(195) -228 + j*(-22) --4 + j*(-223) --209 + j*(0) -10 + j*(181) -164 + j*(-49) --78 + j*(-202) --262 + j*(8) --151 + j*(211) -1 + j*(238) -120 + j*(220) -247 + j*(115) -237 + j*(-69) -106 + j*(-139) -52 + j*(-100) -54 + j*(-134) --59 + j*(-187) --202 + j*(-62) --113 + j*(153) -134 + j*(106) -117 + j*(-168) --192 + j*(-185) --261 + j*(141) -46 + j*(265) -199 + j*(12) -1 + j*(-146) --157 + j*(-1) --92 + j*(164) -56 + j*(206) -194 + j*(130) -205 + j*(-42) -58 + j*(-83) -63 + j*(59) -267 + j*(-2) -223 + j*(-295) --92 + j*(-331) --177 + j*(-91) --37 + j*(-39) --65 + j*(-134) --171 + j*(-64) --117 + j*(47) --39 + j*(30) --30 + j*(-4) --33 + j*(-50) --153 + j*(-89) --280 + j*(112) --45 + j*(370) -330 + j*(176) -233 + j*(-250) --165 + j*(-257) --235 + j*(44) --67 + j*(118) --48 + j*(67) --37 + j*(130) -82 + j*(110) -69 + j*(-7) --2 + j*(18) -66 + j*(23) -4 + j*(-115) --230 + j*(-1) --110 + j*(342) -310 + j*(286) -354 + j*(-125) -48 + j*(-234) --42 + j*(-73) -11 + j*(-70) --78 + j*(-76) --73 + j*(71) -103 + j*(57) -84 + j*(-134) --106 + j*(-129) --124 + j*(27) --36 + j*(40) --80 + j*(10) --114 + j*(134) -54 + j*(240) -247 + j*(107) -209 + j*(-124) -13 + j*(-175) --80 + j*(-55) --42 + j*(37) -24 + j*(83) -164 + j*(77) -269 + j*(-146) -24 + j*(-402) --358 + j*(-215) --275 + j*(216) -124 + j*(223) -179 + j*(-100) --56 + j*(-172) --129 + j*(-26) --68 + j*(35) --28 + j*(37) -10 + j*(16) --11 + j*(-30) --37 + j*(6) -37 + j*(-8) --33 + j*(-153) --266 + j*(-46) --162 + j*(266) -182 + j*(187) -122 + j*(-136) --151 + j*(-84) --108 + j*(118) --5 + j*(82) --60 + j*(91) -23 + j*(199) -167 + j*(116) -136 + j*(15) -152 + j*(13) -181 + j*(-128) --24 + j*(-211) --124 + j*(-5) -68 + j*(65) -100 + j*(-121) --51 + j*(-142) --59 + j*(-98) --165 + j*(-158) --366 + j*(54) --148 + j*(388) -223 + j*(250) -158 + j*(-40) -1 + j*(21) -99 + j*(75) -97 + j*(-37) -21 + j*(12) -141 + j*(35) -142 + j*(-153) --66 + j*(-161) --83 + j*(11) -17 + j*(23) -25 + j*(18) -141 + j*(21) -177 + j*(-226) --158 + j*(-329) --309 + j*(18) -6 + j*(153) -71 + j*(-148) --248 + j*(-166) --279 + j*(146) --52 + j*(199) --49 + j*(99) --93 + j*(208) -93 + j*(319) -321 + j*(184) -340 + j*(-88) -131 + j*(-234) --27 + j*(-103) -121 + j*(-9) -181 + j*(-267) --188 + j*(-376) --365 + j*(25) -10 + j*(214) -159 + j*(-136) --173 + j*(-258) --288 + j*(6) --164 + j*(73) --237 + j*(85) --181 + j*(339) -178 + j*(332) -226 + j*(-12) --47 + j*(-44) --12 + j*(185) -211 + j*(103) -128 + j*(-105) --33 + j*(-25) -66 + j*(81) -156 + j*(-54) -0 + j*(-157) --127 + j*(-10) --4 + j*(132) -139 + j*(40) -79 + j*(-74) -23 + j*(-24) -107 + j*(-37) -53 + j*(-196) --178 + j*(-147) --179 + j*(122) -74 + j*(182) -185 + j*(-1) -119 + j*(-127) -28 + j*(-185) --113 + j*(-173) --170 + j*(-17) --35 + j*(49) --16 + j*(-71) --151 + j*(-37) --85 + j*(115) -68 + j*(21) --51 + j*(-130) --218 + j*(-13) --162 + j*(153) --63 + j*(190) -18 + j*(219) -161 + j*(182) -217 + j*(19) -130 + j*(-104) -2 + j*(-137) --141 + j*(-49) --119 + j*(186) -168 + j*(240) -290 + j*(-35) -86 + j*(-157) -57 + j*(-26) -190 + j*(-136) --6 + j*(-339) --279 + j*(-161) --187 + j*(89) --35 + j*(71) --34 + j*(38) -9 + j*(36) --21 + j*(-38) --119 + j*(59) -58 + j*(194) -231 + j*(-33) --16 + j*(-212) --141 + j*(44) -158 + j*(81) -125 + j*(-313) --374 + j*(-289) --446 + j*(250) -17 + j*(442) -265 + j*(146) -147 + j*(-57) -49 + j*(-35) -74 + j*(-35) -49 + j*(-120) --98 + j*(-146) --208 + j*(21) --69 + j*(197) -124 + j*(98) -37 + j*(-71) --103 + j*(37) -32 + j*(169) -162 + j*(35) -54 + j*(-69) --1 + j*(23) -96 + j*(36) -104 + j*(-56) -58 + j*(-69) -78 + j*(-97) -1 + j*(-203) --190 + j*(-150) --219 + j*(67) --55 + j*(164) -41 + j*(95) -35 + j*(70) -101 + j*(92) -202 + j*(-23) -112 + j*(-209) --103 + j*(-188) --135 + j*(-6) --16 + j*(25) --25 + j*(-49) --83 + j*(2) --8 + j*(53) -23 + j*(-26) --57 + j*(-25) --11 + j*(57) -82 + j*(-37) --43 + j*(-152) --170 + j*(-37) --93 + j*(54) --96 + j*(-8) --214 + j*(91) --90 + j*(313) -190 + j*(255) -225 + j*(22) -115 + j*(-39) -119 + j*(-33) -105 + j*(-135) --41 + j*(-175) --135 + j*(-68) --116 + j*(19) --103 + j*(53) --94 + j*(129) -4 + j*(206) -153 + j*(180) -245 + j*(44) -206 + j*(-132) -28 + j*(-211) --133 + j*(-80) --57 + j*(109) -135 + j*(76) -141 + j*(-91) -40 + j*(-116) -51 + j*(-105) -4 + j*(-216) --210 + j*(-176) --216 + j*(76) -6 + j*(90) --40 + j*(-96) --239 + j*(27) --95 + j*(268) -145 + j*(173) -111 + j*(28) -119 + j*(60) -221 + j*(-74) -40 + j*(-259) --171 + j*(-100) --47 + j*(68) -50 + j*(-38) --37 + j*(-72) --7 + j*(-37) --42 + j*(-154) --260 + j*(-73) --182 + j*(211) -93 + j*(139) -1 + j*(-67) --121 + j*(69) -54 + j*(108) --10 + j*(-86) --221 + j*(101) -77 + j*(344) -349 + j*(-26) --51 + j*(-301) --306 + j*(91) -35 + j*(310) -177 + j*(62) -26 + j*(54) -174 + j*(157) -295 + j*(-98) -20 + j*(-240) --98 + j*(-3) -103 + j*(49) -100 + j*(-137) --69 + j*(-115) --49 + j*(13) -22 + j*(-11) --23 + j*(-35) --29 + j*(40) -65 + j*(64) -139 + j*(-15) -112 + j*(-129) -4 + j*(-163) --49 + j*(-100) --20 + j*(-83) --41 + j*(-118) --83 + j*(-96) --82 + j*(-107) --192 + j*(-139) --315 + j*(43) --140 + j*(250) -73 + j*(127) --40 + j*(-17) --107 + j*(146) -124 + j*(192) -196 + j*(-69) --19 + j*(-176) --128 + j*(-65) --133 + j*(-17) --197 + j*(58) --139 + j*(213) -13 + j*(219) -35 + j*(163) -75 + j*(223) -249 + j*(183) -296 + j*(-32) -154 + j*(-146) -62 + j*(-116) -40 + j*(-108) --14 + j*(-113) --75 + j*(-64) --81 + j*(28) -11 + j*(87) -102 + j*(11) -26 + j*(-83) --47 + j*(13) -97 + j*(66) -144 + j*(-139) --105 + j*(-196) --170 + j*(65) -74 + j*(124) -102 + j*(-91) --80 + j*(-80) --29 + j*(71) -97 + j*(2) -42 + j*(-81) -35 + j*(-62) -48 + j*(-177) --178 + j*(-238) --325 + j*(26) --100 + j*(229) -79 + j*(75) --45 + j*(-35) --101 + j*(106) -62 + j*(166) -164 + j*(25) -97 + j*(-110) --28 + j*(-144) --144 + j*(-75) --161 + j*(84) --7 + j*(173) -120 + j*(52) -18 + j*(-78) --114 + j*(42) -45 + j*(204) -273 + j*(22) -107 + j*(-272) --217 + j*(-142) --112 + j*(176) -195 + j*(71) -88 + j*(-234) --211 + j*(-156) --177 + j*(99) --6 + j*(92) --29 + j*(5) --69 + j*(59) --11 + j*(93) -20 + j*(63) -31 + j*(49) -30 + j*(6) --49 + j*(11) --37 + j*(144) -149 + j*(153) -198 + j*(-51) -23 + j*(-128) --43 + j*(4) -64 + j*(35) -70 + j*(-76) --52 + j*(-81) --86 + j*(45) -15 + j*(118) -117 + j*(75) -143 + j*(-13) -119 + j*(-71) -87 + j*(-121) -4 + j*(-158) --98 + j*(-84) --44 + j*(57) -132 + j*(25) -141 + j*(-175) --33 + j*(-253) --145 + j*(-178) --187 + j*(-118) --250 + j*(-28) --211 + j*(132) --40 + j*(179) -53 + j*(59) --20 + j*(-36) --122 + j*(10) --110 + j*(148) -61 + j*(212) -224 + j*(52) -129 + j*(-190) --135 + j*(-187) --214 + j*(35) --81 + j*(148) -1 + j*(98) --6 + j*(98) -69 + j*(136) -181 + j*(28) -91 + j*(-155) --130 + j*(-107) --113 + j*(127) -132 + j*(112) -103 + j*(-163) --225 + j*(-134) --235 + j*(238) -124 + j*(314) -231 + j*(42) -78 + j*(-9) -156 + j*(80) -275 + j*(-119) -40 + j*(-315) --192 + j*(-129) --70 + j*(52) -16 + j*(-64) --165 + j*(-95) --232 + j*(161) -25 + j*(338) -308 + j*(185) -317 + j*(-112) -103 + j*(-245) --50 + j*(-148) --11 + j*(-56) -17 + j*(-116) --97 + j*(-125) --129 + j*(23) -25 + j*(85) -115 + j*(-62) --6 + j*(-184) --159 + j*(-110) --139 + j*(45) --1 + j*(64) -28 + j*(-65) --100 + j*(-98) --138 + j*(18) --51 + j*(27) --122 + j*(-42) --230 + j*(123) --16 + j*(313) -245 + j*(122) -118 + j*(-151) --115 + j*(-88) --102 + j*(78) --15 + j*(105) -45 + j*(103) -127 + j*(21) -37 + j*(-133) --170 + j*(-50) --119 + j*(180) -85 + j*(175) -108 + j*(61) -115 + j*(46) -151 + j*(-66) --31 + j*(-154) --152 + j*(68) -88 + j*(200) -204 + j*(-35) --8 + j*(-97) -10 + j*(114) -246 + j*(33) -162 + j*(-222) --52 + j*(-168) --8 + j*(-47) -22 + j*(-113) --56 + j*(-87) -23 + j*(-35) -49 + j*(-194) --185 + j*(-232) --262 + j*(21) --47 + j*(101) -8 + j*(-89) --191 + j*(-145) --322 + j*(28) --266 + j*(245) --43 + j*(359) -177 + j*(213) -93 + j*(-14) --114 + j*(91) -46 + j*(342) -381 + j*(202) -356 + j*(-164) -76 + j*(-260) --67 + j*(-126) --42 + j*(-6) -54 + j*(9) -84 + j*(-112) --93 + j*(-175) --216 + j*(41) --4 + j*(220) -187 + j*(48) -62 + j*(-99) --8 + j*(18) -151 + j*(32) -170 + j*(-167) -1 + j*(-237) --81 + j*(-171) --116 + j*(-170) --235 + j*(-134) --296 + j*(37) --192 + j*(194) --21 + j*(214) -74 + j*(98) --1 + j*(-1) --93 + j*(92) -38 + j*(225) -244 + j*(106) -206 + j*(-135) -13 + j*(-202) --122 + j*(-124) --175 + j*(12) --77 + j*(171) -138 + j*(122) -132 + j*(-113) --93 + j*(-131) --113 + j*(52) -14 + j*(35) --81 + j*(-54) --184 + j*(119) -7 + j*(270) -177 + j*(148) -148 + j*(47) -192 + j*(47) -250 + j*(-116) -63 + j*(-264) --123 + j*(-127) --39 + j*(22) -52 + j*(-51) --25 + j*(-103) --47 + j*(-40) --6 + j*(-68) --97 + j*(-120) --204 + j*(-2) --122 + j*(153) -33 + j*(144) -76 + j*(43) -42 + j*(-7) -21 + j*(-5) -32 + j*(-12) -24 + j*(-70) --91 + j*(-107) --226 + j*(40) --106 + j*(296) -238 + j*(284) -373 + j*(-71) -105 + j*(-325) --190 + j*(-192) --182 + j*(65) --12 + j*(129) -65 + j*(48) -39 + j*(-4) -18 + j*(13) -54 + j*(33) -107 + j*(-6) -110 + j*(-91) -38 + j*(-165) --86 + j*(-168) --182 + j*(-47) --103 + j*(130) -128 + j*(115) -190 + j*(-144) --47 + j*(-298) --258 + j*(-156) --246 + j*(28) --178 + j*(105) --101 + j*(175) -53 + j*(149) -76 + j*(-33) --113 + j*(-80) --179 + j*(104) --24 + j*(184) -38 + j*(68) --64 + j*(44) --83 + j*(166) -38 + j*(235) -155 + j*(177) -173 + j*(84) -158 + j*(74) -257 + j*(64) -337 + j*(-165) -70 + j*(-406) --300 + j*(-202) --197 + j*(201) -158 + j*(170) -151 + j*(-98) --24 + j*(-82) -13 + j*(11) -29 + j*(-41) --23 + j*(28) -142 + j*(89) -243 + j*(-152) --11 + j*(-301) --160 + j*(-95) --9 + j*(-13) --18 + j*(-156) --180 + j*(-100) --137 + j*(49) --59 + j*(32) --93 + j*(57) -9 + j*(139) -139 + j*(30) -85 + j*(-95) -49 + j*(-113) --1 + j*(-236) --292 + j*(-232) --390 + j*(163) -18 + j*(347) -232 + j*(-16) --69 + j*(-199) --178 + j*(31) --9 + j*(29) --153 + j*(-123) --350 + j*(132) --78 + j*(395) -177 + j*(175) --3 + j*(17) --54 + j*(233) -233 + j*(250) -274 + j*(-47) -47 + j*(-99) -62 + j*(39) -161 + j*(-92) --80 + j*(-226) --301 + j*(77) --18 + j*(404) -385 + j*(230) -369 + j*(-156) -106 + j*(-264) --22 + j*(-159) --18 + j*(-98) --25 + j*(-91) --62 + j*(-67) --71 + j*(3) -14 + j*(64) -128 + j*(-19) -71 + j*(-185) --119 + j*(-175) --159 + j*(-13) --60 + j*(39) --55 + j*(-1) --75 + j*(60) -33 + j*(105) -115 + j*(1) -66 + j*(-100) -3 + j*(-122) --59 + j*(-150) --186 + j*(-126) --264 + j*(36) --168 + j*(209) -22 + j*(231) -126 + j*(107) -83 + j*(4) -36 + j*(27) -107 + j*(28) -112 + j*(-110) --60 + j*(-147) --120 + j*(21) -26 + j*(76) -58 + j*(-45) --23 + j*(-40) -44 + j*(-8) -48 + j*(-170) --195 + j*(-199) --287 + j*(54) --105 + j*(174) --40 + j*(91) --74 + j*(122) -21 + j*(158) -40 + j*(59) --60 + j*(115) -76 + j*(275) -334 + j*(137) -289 + j*(-160) -68 + j*(-228) --31 + j*(-156) --88 + j*(-124) --161 + j*(-33) --124 + j*(107) -8 + j*(153) -107 + j*(76) -85 + j*(-28) --11 + j*(-13) -36 + j*(100) -209 + j*(28) -150 + j*(-202) --91 + j*(-184) --93 + j*(16) -47 + j*(-1) --6 + j*(-98) --74 + j*(-21) -4 + j*(15) -9 + j*(-45) --18 + j*(-18) -45 + j*(-42) --28 + j*(-154) --188 + j*(-57) --95 + j*(119) -54 + j*(37) --26 + j*(-59) --64 + j*(36) -48 + j*(21) -4 + j*(-108) --123 + j*(-68) --115 + j*(13) --122 + j*(18) --150 + j*(101) --64 + j*(182) -11 + j*(168) -74 + j*(197) -255 + j*(128) -258 + j*(-156) --20 + j*(-245) --132 + j*(-64) --83 + j*(-25) --188 + j*(30) --97 + j*(302) -292 + j*(246) -298 + j*(-159) --21 + j*(-179) -32 + j*(19) -153 + j*(-161) --119 + j*(-269) --227 + j*(11) -1 + j*(71) --40 + j*(-97) --175 + j*(52) -53 + j*(170) -153 + j*(-105) --145 + j*(-195) --250 + j*(85) --49 + j*(207) -48 + j*(129) -20 + j*(-16) --153 + j*(39) --67 + j*(248) -168 + j*(204) -190 + j*(6) -79 + j*(-42) -55 + j*(11) -116 + j*(11) -151 + j*(-91) -37 + j*(-217) --189 + j*(-141) --180 + j*(150) -139 + j*(216) -272 + j*(-98) -0 + j*(-273) --162 + j*(-72) --13 + j*(18) --18 + j*(-144) --253 + j*(-80) --201 + j*(224) -119 + j*(223) -158 + j*(-62) --76 + j*(-111) --123 + j*(72) --8 + j*(115) -5 + j*(85) -42 + j*(146) -187 + j*(103) -190 + j*(-75) -51 + j*(-117) -18 + j*(-45) -43 + j*(-53) -4 + j*(-48) -48 + j*(8) -132 + j*(-81) -28 + j*(-197) --75 + j*(-110) -22 + j*(-79) --21 + j*(-257) --312 + j*(-221) --363 + j*(127) --65 + j*(267) -102 + j*(74) -8 + j*(-53) --57 + j*(-21) --49 + j*(-23) --98 + j*(-45) --168 + j*(1) --192 + j*(103) --134 + j*(218) -10 + j*(260) -124 + j*(185) -151 + j*(85) -132 + j*(1) -42 + j*(-52) --50 + j*(34) -49 + j*(156) -209 + j*(53) -132 + j*(-117) -2 + j*(-72) -53 + j*(-21) -35 + j*(-124) --127 + j*(-79) --94 + j*(112) -71 + j*(101) -65 + j*(6) -58 + j*(45) -162 + j*(-21) -55 + j*(-196) --175 + j*(-70) --47 + j*(199) -252 + j*(92) -190 + j*(-209) --69 + j*(-199) --71 + j*(-8) -73 + j*(-34) -11 + j*(-181) --168 + j*(-110) --112 + j*(105) -133 + j*(71) -139 + j*(-204) --138 + j*(-275) --276 + j*(-60) --179 + j*(93) --94 + j*(119) -18 + j*(148) -162 + j*(6) -26 + j*(-228) --247 + j*(-132) --196 + j*(110) --56 + j*(52) --201 + j*(25) --186 + j*(303) -185 + j*(322) -255 + j*(-55) --76 + j*(-139) --141 + j*(135) -88 + j*(190) -140 + j*(19) -35 + j*(-28) --6 + j*(30) -34 + j*(95) -163 + j*(86) -219 + j*(-117) --15 + j*(-264) --230 + j*(-56) --86 + j*(169) -83 + j*(84) -21 + j*(7) -28 + j*(96) -162 + j*(54) -146 + j*(-94) -45 + j*(-119) -13 + j*(-106) --49 + j*(-112) --103 + j*(-21) --24 + j*(58) -58 + j*(6) -44 + j*(-64) --5 + j*(-103) --108 + j*(-93) --155 + j*(63) -35 + j*(171) -190 + j*(-23) -7 + j*(-206) --175 + j*(-45) --35 + j*(121) -113 + j*(-3) -18 + j*(-146) --119 + j*(-103) --148 + j*(11) --88 + j*(97) -18 + j*(88) -26 + j*(-2) --47 + j*(23) -50 + j*(112) -197 + j*(-47) -23 + j*(-272) --256 + j*(-141) --197 + j*(119) --28 + j*(103) --75 + j*(49) --61 + j*(182) -146 + j*(168) -159 + j*(-66) --41 + j*(-97) --52 + j*(81) -131 + j*(78) -152 + j*(-101) --6 + j*(-171) --116 + j*(-80) --110 + j*(36) --23 + j*(101) -86 + j*(69) -116 + j*(-40) -59 + j*(-113) --4 + j*(-137) --81 + j*(-152) --188 + j*(-98) --225 + j*(40) --157 + j*(156) --58 + j*(203) -49 + j*(203) -142 + j*(134) -159 + j*(27) -109 + j*(-42) -33 + j*(-64) --49 + j*(4) -13 + j*(147) -227 + j*(116) -262 + j*(-137) -35 + j*(-221) --35 + j*(-57) -105 + j*(-54) -57 + j*(-218) --124 + j*(-179) --112 + j*(-45) --62 + j*(-72) --150 + j*(-71) --165 + j*(53) --93 + j*(107) --51 + j*(159) -119 + j*(214) -309 + j*(1) -148 + j*(-280) --118 + j*(-215) --103 + j*(-68) --106 + j*(-115) --245 + j*(-18) --124 + j*(192) -93 + j*(70) --49 + j*(-119) --227 + j*(47) --80 + j*(221) -50 + j*(139) -16 + j*(105) -64 + j*(148) -132 + j*(102) -154 + j*(76) -253 + j*(1) -211 + j*(-228) --62 + j*(-268) --141 + j*(-52) --21 + j*(-23) --99 + j*(-81) --146 + j*(102) -98 + j*(163) -176 + j*(-89) --30 + j*(-168) --74 + j*(-58) --72 + j*(-105) --255 + j*(-44) --206 + j*(249) -106 + j*(258) -140 + j*(19) -6 + j*(35) -111 + j*(107) -173 + j*(-62) -7 + j*(-121) --20 + j*(1) -59 + j*(-44) --64 + j*(-100) --124 + j*(90) -105 + j*(177) -235 + j*(-37) -90 + j*(-192) --28 + j*(-144) --42 + j*(-128) --148 + j*(-137) --256 + j*(38) --103 + j*(261) -194 + j*(200) -233 + j*(-95) --8 + j*(-198) --115 + j*(-16) -40 + j*(62) -106 + j*(-97) --47 + j*(-189) --173 + j*(-98) --190 + j*(20) --149 + j*(123) --37 + j*(182) -63 + j*(129) -74 + j*(73) -105 + j*(53) -122 + j*(-39) -19 + j*(-87) --16 + j*(11) -98 + j*(8) -78 + j*(-145) --92 + j*(-151) --136 + j*(-19) --94 + j*(37) --70 + j*(81) -18 + j*(103) -47 + j*(9) --56 + j*(27) -33 + j*(182) -274 + j*(57) -168 + j*(-253) --151 + j*(-201) --143 + j*(74) -79 + j*(80) -96 + j*(-104) --49 + j*(-161) --158 + j*(-77) --153 + j*(47) --65 + j*(85) --58 + j*(42) --104 + j*(119) -37 + j*(215) -175 + j*(63) -37 + j*(-49) -5 + j*(101) -208 + j*(50) -102 + j*(-205) --168 + j*(-50) -47 + j*(210) -306 + j*(-73) --16 + j*(-332) --255 + j*(-18) -41 + j*(160) -139 + j*(-130) --158 + j*(-171) --180 + j*(115) -55 + j*(134) -56 + j*(-25) --40 + j*(18) -54 + j*(101) -173 + j*(-6) -116 + j*(-182) --86 + j*(-226) --232 + j*(-57) --132 + j*(143) -54 + j*(100) -23 + j*(-40) --83 + j*(20) -1 + j*(123) -117 + j*(54) -103 + j*(-50) -57 + j*(-96) --11 + j*(-141) --128 + j*(-109) --163 + j*(13) --107 + j*(88) --53 + j*(115) -16 + j*(123) -62 + j*(72) -40 + j*(47) -73 + j*(71) -129 + j*(-10) -32 + j*(-91) --40 + j*(18) -92 + j*(69) -134 + j*(-86) --20 + j*(-116) --22 + j*(19) -113 + j*(-21) -64 + j*(-169) --74 + j*(-158) --113 + j*(-92) --147 + j*(-40) --122 + j*(71) -29 + j*(62) -12 + j*(-122) --220 + j*(-116) --272 + j*(134) --90 + j*(245) --1 + j*(192) -25 + j*(218) -171 + j*(227) -279 + j*(64) -198 + j*(-95) -87 + j*(-100) -73 + j*(-67) -80 + j*(-100) -35 + j*(-149) --53 + j*(-163) --153 + j*(-111) --209 + j*(27) --129 + j*(186) -68 + j*(223) -205 + j*(86) -179 + j*(-74) -88 + j*(-138) -5 + j*(-157) --96 + j*(-119) --115 + j*(1) --16 + j*(38) --15 + j*(-49) --125 + j*(6) --32 + j*(174) -199 + j*(79) -140 + j*(-194) --129 + j*(-188) --168 + j*(26) --37 + j*(71) --35 + j*(20) --45 + j*(83) -76 + j*(84) -86 + j*(-76) --113 + j*(-103) --179 + j*(133) -62 + j*(269) -273 + j*(88) -204 + j*(-132) -66 + j*(-167) -2 + j*(-162) --103 + j*(-144) --148 + j*(13) -28 + j*(86) -103 + j*(-114) --116 + j*(-188) --182 + j*(15) --18 + j*(18) --134 + j*(-136) --347 + j*(89) --95 + j*(383) -220 + j*(180) -69 + j*(-60) --48 + j*(91) -146 + j*(103) -101 + j*(-139) --162 + j*(-80) --118 + j*(158) -24 + j*(144) --9 + j*(153) -144 + j*(295) -445 + j*(102) -343 + j*(-304) --41 + j*(-339) --161 + j*(-82) --35 + j*(47) -82 + j*(1) -88 + j*(-138) --106 + j*(-212) --285 + j*(14) --85 + j*(303) -262 + j*(192) -267 + j*(-119) -84 + j*(-187) -59 + j*(-170) --18 + j*(-281) --279 + j*(-235) --345 + j*(93) --56 + j*(264) -149 + j*(54) --6 + j*(-124) --141 + j*(19) -14 + j*(121) -86 + j*(-53) --107 + j*(-88) --104 + j*(133) -148 + j*(91) -79 + j*(-190) --215 + j*(-110) --141 + j*(163) -71 + j*(98) --9 + j*(-30) --50 + j*(76) -74 + j*(47) --21 + j*(-69) --111 + j*(97) -124 + j*(161) -175 + j*(-124) --117 + j*(-168) --140 + j*(79) -18 + j*(42) --129 + j*(-30) --170 + j*(247) -187 + j*(317) -292 + j*(-23) -37 + j*(-107) -30 + j*(71) -175 + j*(-1) -69 + j*(-127) --26 + j*(-14) -93 + j*(53) -172 + j*(-49) -153 + j*(-153) -76 + j*(-268) --137 + j*(-300) --285 + j*(-99) --179 + j*(86) --56 + j*(67) --50 + j*(33) --41 + j*(37) --47 + j*(40) --22 + j*(98) -101 + j*(63) -71 + j*(-103) --99 + j*(-73) --39 + j*(54) -16 + j*(-78) --238 + j*(-69) --216 + j*(317) -238 + j*(336) -301 + j*(-74) -30 + j*(-109) -119 + j*(-5) -102 + j*(-274) --336 + j*(-198) --234 + j*(338) -317 + j*(203) -107 + j*(-310) --373 + j*(9) -39 + j*(494) -548 + j*(83) -259 + j*(-392) --59 + j*(-276) --50 + j*(-222) --245 + j*(-243) --345 + j*(76) --46 + j*(217) -41 + j*(0) --101 + j*(28) -41 + j*(107) -47 + j*(-132) --296 + j*(-61) --186 + j*(387) -322 + j*(310) -317 + j*(-164) --23 + j*(-210) --63 + j*(-51) --68 + j*(-73) --175 + j*(40) --20 + j*(210) -158 + j*(66) -35 + j*(-66) --25 + j*(49) -91 + j*(58) -83 + j*(-30) -75 + j*(-8) -147 + j*(-103) --15 + j*(-257) --227 + j*(-94) --94 + j*(96) -3 + j*(-42) --209 + j*(-49) --199 + j*(257) -140 + j*(306) -250 + j*(40) -117 + j*(-65) -97 + j*(-48) -59 + j*(-125) --77 + j*(-87) --37 + j*(62) -100 + j*(11) -37 + j*(-114) --59 + j*(-43) -25 + j*(4) -25 + j*(-114) --153 + j*(-93) --145 + j*(137) -109 + j*(171) -191 + j*(-75) --13 + j*(-193) --144 + j*(-52) --71 + j*(59) --11 + j*(46) -20 + j*(59) -115 + j*(11) -86 + j*(-164) --141 + j*(-180) --206 + j*(53) --4 + j*(141) -72 + j*(-33) --84 + j*(-98) --161 + j*(37) --96 + j*(133) --21 + j*(173) -110 + j*(175) -214 + j*(13) -74 + j*(-158) --111 + j*(-55) --28 + j*(112) -115 + j*(41) -57 + j*(-75) --24 + j*(-36) --1 + j*(-3) --20 + j*(-16) --31 + j*(53) -78 + j*(77) -124 + j*(-49) -11 + j*(-101) --12 + j*(-10) -84 + j*(-37) -29 + j*(-175) --149 + j*(-140) --162 + j*(32) --39 + j*(63) --34 + j*(-16) --105 + j*(19) --59 + j*(109) -41 + j*(71) -3 + j*(-23) --98 + j*(30) --42 + j*(162) -121 + j*(127) -112 + j*(-46) --64 + j*(-49) --78 + j*(147) -136 + j*(196) -232 + j*(0) -93 + j*(-115) --5 + j*(-24) -59 + j*(53) -144 + j*(33) -218 + j*(-44) -221 + j*(-222) -6 + j*(-361) --238 + j*(-199) --153 + j*(69) -88 + j*(24) -55 + j*(-197) --150 + j*(-198) --190 + j*(-41) --102 + j*(-2) --101 + j*(-59) --194 + j*(-53) --261 + j*(78) --156 + j*(254) -87 + j*(235) -144 + j*(-18) --100 + j*(-113) --231 + j*(132) --11 + j*(312) -197 + j*(161) -122 + j*(-5) -43 + j*(53) -148 + j*(74) -173 + j*(-95) --18 + j*(-148) --86 + j*(41) -116 + j*(92) -151 + j*(-148) --134 + j*(-187) --187 + j*(127) -143 + j*(188) -202 + j*(-142) --109 + j*(-194) --141 + j*(74) -67 + j*(52) --37 + j*(-107) --177 + j*(85) -66 + j*(231) -214 + j*(-20) --19 + j*(-139) --97 + j*(74) -100 + j*(126) -143 + j*(-30) -59 + j*(-60) -67 + j*(-48) -49 + j*(-99) --6 + j*(-85) -2 + j*(-83) --78 + j*(-118) --170 + j*(35) -22 + j*(202) -261 + j*(16) -144 + j*(-269) --115 + j*(-267) --222 + j*(-120) --230 + j*(24) --117 + j*(153) -61 + j*(76) --21 + j*(-107) --218 + j*(6) --86 + j*(230) -141 + j*(103) -21 + j*(-98) --153 + j*(20) --58 + j*(168) -37 + j*(133) -56 + j*(142) -192 + j*(128) -230 + j*(-85) -17 + j*(-165) --42 + j*(20) -144 + j*(10) -78 + j*(-226) --221 + j*(-146) --165 + j*(190) -173 + j*(174) -194 + j*(-137) --57 + j*(-189) --112 + j*(-10) -4 + j*(12) --13 + j*(-78) --116 + j*(-51) --128 + j*(61) --35 + j*(141) -119 + j*(104) -158 + j*(-125) --125 + j*(-265) --395 + j*(30) --168 + j*(416) -249 + j*(329) -288 + j*(0) -127 + j*(-76) -122 + j*(-61) -76 + j*(-166) --107 + j*(-134) --115 + j*(67) -70 + j*(103) -136 + j*(-47) -35 + j*(-147) --89 + j*(-117) --135 + j*(0) --57 + j*(94) -35 + j*(58) -16 + j*(11) -26 + j*(54) -121 + j*(8) -77 + j*(-132) --66 + j*(-115) --62 + j*(-21) --44 + j*(-54) --147 + j*(-11) --90 + j*(163) -119 + j*(127) -98 + j*(-64) --51 + j*(-28) -23 + j*(93) -136 + j*(-2) -59 + j*(-98) -25 + j*(-46) -92 + j*(-109) --35 + j*(-244) --247 + j*(-124) --176 + j*(107) -21 + j*(59) --58 + j*(-110) --253 + j*(-2) --168 + j*(241) -71 + j*(222) -96 + j*(59) -28 + j*(57) -93 + j*(68) -86 + j*(-60) --78 + j*(-46) --54 + j*(137) -134 + j*(111) -105 + j*(-52) --15 + j*(-2) -73 + j*(86) -153 + j*(-13) -109 + j*(-70) -141 + j*(-113) -49 + j*(-303) --291 + j*(-239) --296 + j*(175) -111 + j*(217) -139 + j*(-158) --216 + j*(-148) --193 + j*(179) -64 + j*(148) --6 + j*(-11) --98 + j*(140) -112 + j*(226) -215 + j*(31) -93 + j*(-42) -110 + j*(34) -212 + j*(-61) -122 + j*(-230) --73 + j*(-220) --151 + j*(-72) --80 + j*(49) -42 + j*(33) -48 + j*(-71) --34 + j*(-74) --5 + j*(-15) -45 + j*(-105) --96 + j*(-188) --226 + j*(-47) --139 + j*(88) --63 + j*(54) --95 + j*(61) --36 + j*(117) -24 + j*(41) --85 + j*(0) --132 + j*(162) -52 + j*(274) -237 + j*(158) -254 + j*(-29) -160 + j*(-160) -0 + j*(-185) --93 + j*(-59) -9 + j*(45) -118 + j*(-73) --11 + j*(-226) --217 + j*(-146) --233 + j*(57) --114 + j*(142) --49 + j*(125) --33 + j*(145) -49 + j*(185) -175 + j*(114) -163 + j*(-51) -4 + j*(-78) --24 + j*(78) -165 + j*(107) -232 + j*(-113) -29 + j*(-233) --103 + j*(-90) --6 + j*(2) -33 + j*(-94) --83 + j*(-117) --119 + j*(-3) --40 + j*(37) --17 + j*(-3) --37 + j*(-3) --30 + j*(6) --42 + j*(1) --52 + j*(42) -6 + j*(63) -35 + j*(1) --27 + j*(-25) --57 + j*(37) --6 + j*(85) -65 + j*(64) -93 + j*(-26) --6 + j*(-112) --162 + j*(-6) --62 + j*(223) -232 + j*(156) -214 + j*(-170) --101 + j*(-198) --153 + j*(74) -57 + j*(127) -87 + j*(-12) -13 + j*(11) -103 + j*(54) -158 + j*(-85) -23 + j*(-167) --68 + j*(-73) --16 + j*(6) -66 + j*(-13) -106 + j*(-112) -16 + j*(-253) --206 + j*(-235) --287 + j*(-20) --161 + j*(94) --115 + j*(45) --179 + j*(110) --66 + j*(265) -177 + j*(206) -229 + j*(-56) -29 + j*(-212) --180 + j*(-122) --211 + j*(67) --111 + j*(175) --7 + j*(196) -98 + j*(174) -173 + j*(52) -76 + j*(-78) --70 + j*(-5) --7 + j*(144) -130 + j*(100) -120 + j*(18) -137 + j*(25) -191 + j*(-89) -27 + j*(-209) --123 + j*(-37) -49 + j*(95) -144 + j*(-89) --53 + j*(-139) --40 + j*(62) -180 + j*(-23) -50 + j*(-293) --267 + j*(-175) --211 + j*(141) -48 + j*(148) -93 + j*(-32) --21 + j*(-88) --88 + j*(-21) --52 + j*(52) -20 + j*(28) --15 + j*(-39) --94 + j*(19) --23 + j*(121) -88 + j*(68) -71 + j*(-22) -28 + j*(-31) -0 + j*(-36) --36 + j*(21) -67 + j*(81) -156 + j*(-72) --31 + j*(-177) --110 + j*(28) -133 + j*(40) -74 + j*(-280) --330 + j*(-195) --272 + j*(250) -146 + j*(238) -168 + j*(-88) --37 + j*(-124) --72 + j*(-48) --106 + j*(-19) --66 + j*(86) -80 + j*(-11) --115 + j*(-216) --410 + j*(63) --127 + j*(443) -249 + j*(223) -89 + j*(-33) -8 + j*(133) -240 + j*(65) -91 + j*(-233) --233 + j*(-70) --98 + j*(220) -87 + j*(124) -2 + j*(88) -93 + j*(220) -280 + j*(86) -178 + j*(-92) -82 + j*(-25) -150 + j*(-11) -131 + j*(-62) -169 + j*(-24) -284 + j*(-177) -86 + j*(-409) --194 + j*(-261) --110 + j*(-54) --40 + j*(-146) --190 + j*(-113) --112 + j*(75) -57 + j*(-34) --89 + j*(-157) --156 + j*(21) -44 + j*(25) --8 + j*(-208) --265 + j*(-150) --250 + j*(71) --143 + j*(82) --176 + j*(101) --104 + j*(218) -48 + j*(175) -52 + j*(69) -42 + j*(62) -76 + j*(-13) --42 + j*(-117) --218 + j*(-21) --216 + j*(183) --65 + j*(296) -95 + j*(268) -155 + j*(155) -118 + j*(115) -166 + j*(144) -257 + j*(42) -170 + j*(-81) -105 + j*(-21) -202 + j*(-64) -71 + j*(-257) --216 + j*(-83) --33 + j*(272) -344 + j*(103) -203 + j*(-236) --35 + j*(-91) -180 + j*(45) -285 + j*(-255) --16 + j*(-395) --144 + j*(-194) --54 + j*(-185) --204 + j*(-263) --358 + j*(-25) --134 + j*(192) -87 + j*(17) --61 + j*(-190) --274 + j*(-67) --202 + j*(146) --24 + j*(114) --71 + j*(-14) --197 + j*(93) --50 + j*(267) -165 + j*(129) -54 + j*(-76) --102 + j*(35) -39 + j*(137) -101 + j*(-47) --115 + j*(-85) --144 + j*(139) -53 + j*(161) -45 + j*(17) --57 + j*(78) -47 + j*(170) -136 + j*(62) -45 + j*(-3) -9 + j*(91) -122 + j*(133) -210 + j*(30) -152 + j*(-102) -6 + j*(-80) -28 + j*(83) -249 + j*(54) -253 + j*(-223) --12 + j*(-285) --82 + j*(-117) --32 + j*(-133) --198 + j*(-104) --148 + j*(222) -318 + j*(199) -364 + j*(-360) --198 + j*(-505) --407 + j*(-36) --81 + j*(146) -15 + j*(-82) --185 + j*(-115) --231 + j*(62) --135 + j*(154) --32 + j*(180) -85 + j*(121) -83 + j*(-10) --6 + j*(-30) --6 + j*(5) --22 + j*(-37) --99 + j*(20) --8 + j*(119) -107 + j*(-13) --62 + j*(-148) --233 + j*(29) --110 + j*(229) -69 + j*(205) -139 + j*(107) -148 + j*(-12) -15 + j*(-99) --117 + j*(44) -35 + j*(213) -230 + j*(81) -153 + j*(-101) -45 + j*(-81) -46 + j*(-70) --18 + j*(-79) --33 + j*(27) -107 + j*(33) -115 + j*(-139) --54 + j*(-181) --138 + j*(-85) --167 + j*(-8) --170 + j*(141) -24 + j*(254) -207 + j*(93) -97 + j*(-66) -15 + j*(45) -188 + j*(88) -281 + j*(-124) -144 + j*(-306) --56 + j*(-351) --270 + j*(-260) --339 + j*(7) --134 + j*(148) --58 + j*(4) --243 + j*(64) --98 + j*(387) -372 + j*(268) -358 + j*(-269) --140 + j*(-374) --326 + j*(1) --108 + j*(205) -54 + j*(144) -113 + j*(67) -145 + j*(-55) -17 + j*(-186) --179 + j*(-106) --173 + j*(105) -6 + j*(173) -120 + j*(52) -62 + j*(-79) --54 + j*(-76) --91 + j*(-2) --81 + j*(37) --84 + j*(86) --18 + j*(156) -94 + j*(109) -66 + j*(1) --30 + j*(43) -35 + j*(156) -177 + j*(122) -224 + j*(-8) -184 + j*(-121) -73 + j*(-189) --50 + j*(-130) --21 + j*(-18) -64 + j*(-62) -3 + j*(-136) --38 + j*(-88) -1 + j*(-141) --177 + j*(-245) --417 + j*(-3) --223 + j*(356) -144 + j*(274) -133 + j*(2) --23 + j*(29) -54 + j*(130) -156 + j*(40) -117 + j*(-54) -80 + j*(-83) -22 + j*(-125) --69 + j*(-81) --42 + j*(8) -26 + j*(-35) --51 + j*(-103) --154 + j*(-21) --129 + j*(120) --1 + j*(198) -175 + j*(153) -254 + j*(-54) -97 + j*(-231) --97 + j*(-167) --103 + j*(-42) --78 + j*(-31) --126 + j*(18) --64 + j*(139) -108 + j*(125) -172 + j*(-43) -69 + j*(-180) --100 + j*(-182) --194 + j*(-36) --94 + j*(103) -51 + j*(16) --61 + j*(-156) --307 + j*(-35) --250 + j*(295) -100 + j*(351) -247 + j*(54) -11 + j*(-116) --156 + j*(104) -71 + j*(301) -324 + j*(105) -209 + j*(-163) -2 + j*(-124) -25 + j*(-20) -53 + j*(-74) --29 + j*(-71) --11 + j*(-1) -18 + j*(-50) --83 + j*(-41) --61 + j*(117) -119 + j*(110) -141 + j*(-40) -78 + j*(-63) -103 + j*(-100) --4 + j*(-199) --146 + j*(-67) -11 + j*(60) -96 + j*(-160) --206 + j*(-229) --296 + j*(124) -49 + j*(225) -127 + j*(-81) --148 + j*(-121) --178 + j*(133) -12 + j*(196) -109 + j*(129) -199 + j*(47) -197 + j*(-168) --59 + j*(-260) --194 + j*(-43) --33 + j*(56) --24 + j*(-89) --209 + j*(-33) --154 + j*(204) -91 + j*(205) -155 + j*(6) -28 + j*(-95) --91 + j*(-32) --73 + j*(102) -71 + j*(110) -86 + j*(-47) --96 + j*(-49) --97 + j*(175) -162 + j*(208) -236 + j*(-28) -86 + j*(-104) -83 + j*(-31) -144 + j*(-143) --41 + j*(-261) --227 + j*(-84) --100 + j*(122) -78 + j*(37) -5 + j*(-104) --107 + j*(-34) --36 + j*(46) --1 + j*(-52) --163 + j*(-68) --221 + j*(161) -13 + j*(306) -222 + j*(154) -190 + j*(-35) -95 + j*(-87) -23 + j*(-92) --39 + j*(-25) -51 + j*(57) -160 + j*(-88) --40 + j*(-257) --277 + j*(-37) --72 + j*(240) -201 + j*(61) -33 + j*(-181) --167 + j*(-4) -23 + j*(164) -177 + j*(-35) --9 + j*(-182) --146 + j*(-37) --55 + j*(64) --23 + j*(12) --80 + j*(59) -23 + j*(174) -213 + j*(78) -189 + j*(-164) --45 + j*(-227) --160 + j*(-63) --71 + j*(49) -1 + j*(5) --30 + j*(-38) --71 + j*(-27) --113 + j*(4) --131 + j*(110) -4 + j*(221) -197 + j*(117) -167 + j*(-107) --25 + j*(-143) --84 + j*(-18) --26 + j*(17) --46 + j*(-12) --90 + j*(59) --5 + j*(156) -136 + j*(110) -164 + j*(-22) -103 + j*(-94) -66 + j*(-124) --8 + j*(-197) --194 + j*(-173) --287 + j*(54) --124 + j*(237) -52 + j*(200) -112 + j*(145) -231 + j*(81) -262 + j*(-181) --52 + j*(-349) --326 + j*(-77) --149 + j*(221) -91 + j*(129) -30 + j*(-11) --32 + j*(62) -56 + j*(96) -81 + j*(35) -79 + j*(51) -174 + j*(16) -170 + j*(-146) --2 + j*(-214) --122 + j*(-100) --80 + j*(30) -39 + j*(37) -77 + j*(-76) --37 + j*(-143) --120 + j*(-40) --34 + j*(30) -1 + j*(-59) --99 + j*(-75) --117 + j*(10) --101 + j*(12) --173 + j*(83) --59 + j*(276) -235 + j*(181) -185 + j*(-144) --124 + j*(-111) --71 + j*(191) -264 + j*(134) -277 + j*(-245) --90 + j*(-402) --404 + j*(-138) --311 + j*(268) -90 + j*(347) -272 + j*(21) -45 + j*(-173) --86 + j*(-25) -25 + j*(-8) --83 + j*(-120) --233 + j*(86) -33 + j*(272) -226 + j*(-22) --98 + j*(-202) --271 + j*(151) -78 + j*(340) -279 + j*(57) -95 + j*(-117) --16 + j*(-28) --4 + j*(8) --40 + j*(69) -78 + j*(198) -313 + j*(81) -272 + j*(-214) -9 + j*(-281) --112 + j*(-127) --78 + j*(-23) --30 + j*(23) -56 + j*(36) -119 + j*(-63) -35 + j*(-156) --47 + j*(-92) -40 + j*(-49) -76 + j*(-214) --148 + j*(-326) --365 + j*(-142) --317 + j*(88) --206 + j*(148) --161 + j*(208) --7 + j*(267) -136 + j*(120) -17 + j*(-25) --86 + j*(106) -84 + j*(185) -154 + j*(1) --25 + j*(-38) --8 + j*(156) -233 + j*(115) -233 + j*(-157) -8 + j*(-231) --100 + j*(-129) --130 + j*(-64) --159 + j*(37) --62 + j*(146) -66 + j*(83) -18 + j*(-22) --67 + j*(44) -8 + j*(146) -142 + j*(98) -158 + j*(-36) -64 + j*(-110) --27 + j*(-71) --23 + j*(11) -54 + j*(26) -107 + j*(-57) -52 + j*(-185) --147 + j*(-221) --330 + j*(-16) --221 + j*(300) -131 + j*(345) -312 + j*(74) -192 + j*(-150) -23 + j*(-168) --71 + j*(-105) --102 + j*(1) --19 + j*(91) -97 + j*(45) -91 + j*(-66) -22 + j*(-88) -5 + j*(-83) --33 + j*(-119) --137 + j*(-95) --184 + j*(43) --74 + j*(170) -91 + j*(133) -119 + j*(-13) -25 + j*(-51) -32 + j*(11) -110 + j*(-62) -6 + j*(-186) --143 + j*(-97) --69 + j*(28) -4 + j*(-74) --153 + j*(-144) --278 + j*(28) --190 + j*(209) --28 + j*(267) -151 + j*(206) -205 + j*(-18) --10 + j*(-141) --157 + j*(59) -28 + j*(205) -158 + j*(63) -80 + j*(-13) -98 + j*(9) -91 + j*(-105) --86 + j*(-76) --18 + j*(132) -211 + j*(1) -16 + j*(-245) --234 + j*(1) -52 + j*(231) -251 + j*(-89) --86 + j*(-255) --217 + j*(79) -84 + j*(165) -110 + j*(-91) --110 + j*(-47) --6 + j*(163) -218 + j*(46) -154 + j*(-189) --40 + j*(-220) --156 + j*(-128) --184 + j*(17) --69 + j*(131) -78 + j*(55) -26 + j*(-98) --136 + j*(-69) --156 + j*(100) --10 + j*(195) -146 + j*(112) -135 + j*(-62) --30 + j*(-98) --86 + j*(69) -99 + j*(153) -250 + j*(-33) -122 + j*(-255) --124 + j*(-231) --188 + j*(-32) --55 + j*(51) --4 + j*(-64) --158 + j*(-104) --240 + j*(84) --83 + j*(220) -44 + j*(142) -14 + j*(95) -55 + j*(151) -163 + j*(98) -175 + j*(-11) -154 + j*(-71) -121 + j*(-178) --61 + j*(-245) --223 + j*(-83) --134 + j*(109) -23 + j*(90) -40 + j*(-26) --63 + j*(-75) --184 + j*(28) --112 + j*(262) -214 + j*(273) -328 + j*(-78) -25 + j*(-257) --150 + j*(-34) --2 + j*(88) -49 + j*(14) -53 + j*(50) -209 + j*(-34) -84 + j*(-334) --343 + j*(-233) --317 + j*(254) -139 + j*(308) -239 + j*(-45) -21 + j*(-132) -0 + j*(-38) -14 + j*(-110) --142 + j*(-103) --156 + j*(95) -34 + j*(137) -92 + j*(-17) --23 + j*(-77) --86 + j*(4) --31 + j*(71) -35 + j*(28) --18 + j*(-49) --136 + j*(23) --76 + j*(206) -143 + j*(209) -216 + j*(33) -142 + j*(-41) -165 + j*(-47) -182 + j*(-200) --25 + j*(-333) --278 + j*(-192) --284 + j*(89) --81 + j*(228) -116 + j*(163) -187 + j*(-5) -106 + j*(-158) --52 + j*(-189) --170 + j*(-98) --185 + j*(35) --110 + j*(132) --6 + j*(145) -54 + j*(98) -74 + j*(59) -112 + j*(23) -127 + j*(-89) --16 + j*(-196) --223 + j*(-80) --173 + j*(192) -114 + j*(220) -196 + j*(-34) --5 + j*(-118) --51 + j*(45) -115 + j*(42) -88 + j*(-138) --77 + j*(-112) --34 + j*(0) -28 + j*(-119) --189 + j*(-197) --359 + j*(57) --176 + j*(310) -58 + j*(261) -83 + j*(140) -59 + j*(148) -132 + j*(187) -263 + j*(144) -366 + j*(-21) -301 + j*(-267) -38 + j*(-374) --177 + j*(-218) --143 + j*(-13) -6 + j*(8) -45 + j*(-118) --83 + j*(-208) --263 + j*(-126) --303 + j*(107) --120 + j*(285) -124 + j*(221) -164 + j*(6) -16 + j*(-66) --30 + j*(45) -92 + j*(52) -81 + j*(-104) --105 + j*(-95) --105 + j*(107) -95 + j*(117) -110 + j*(-64) --30 + j*(-69) --7 + j*(24) -49 + j*(-38) --51 + j*(-72) --76 + j*(49) -45 + j*(69) -59 + j*(-28) -1 + j*(-32) -18 + j*(-15) -1 + j*(-49) --28 + j*(1) -68 + j*(8) -63 + j*(-148) --140 + j*(-156) --158 + j*(49) -18 + j*(35) --69 + j*(-136) --291 + j*(12) --151 + j*(303) -156 + j*(231) -154 + j*(-16) -4 + j*(-32) -25 + j*(35) -49 + j*(-44) --81 + j*(-60) --117 + j*(100) -45 + j*(158) -107 + j*(18) --14 + j*(-22) --25 + j*(106) -119 + j*(108) -124 + j*(-33) -1 + j*(-24) -39 + j*(105) -204 + j*(71) -243 + j*(-117) -103 + j*(-262) --107 + j*(-233) --186 + j*(-18) -9 + j*(117) -169 + j*(-78) --38 + j*(-264) --255 + j*(-65) --93 + j*(146) -71 + j*(24) --35 + j*(-64) --45 + j*(53) -103 + j*(7) -45 + j*(-185) --169 + j*(-179) --259 + j*(-13) --221 + j*(146) --75 + j*(259) -122 + j*(190) -117 + j*(1) --24 + j*(11) -30 + j*(129) -163 + j*(53) -115 + j*(-79) -39 + j*(-78) -24 + j*(-94) --67 + j*(-115) --146 + j*(-1) --71 + j*(117) -44 + j*(117) -119 + j*(50) -122 + j*(-75) --22 + j*(-142) --129 + j*(-4) --5 + j*(119) -114 + j*(24) -69 + j*(-62) -50 + j*(-61) -43 + j*(-132) --81 + j*(-155) --127 + j*(-49) --80 + j*(-35) --148 + j*(-53) --191 + j*(80) --61 + j*(153) --11 + j*(72) --51 + j*(94) -46 + j*(123) -75 + j*(-23) --107 + j*(-56) --169 + j*(133) --46 + j*(234) -39 + j*(260) -209 + j*(301) -429 + j*(98) -305 + j*(-234) --11 + j*(-199) --4 + j*(39) -181 + j*(17) -167 + j*(-130) -95 + j*(-141) -110 + j*(-161) -57 + j*(-264) --107 + j*(-279) --221 + j*(-151) --187 + j*(2) --64 + j*(31) --30 + j*(-67) --136 + j*(-105) --219 + j*(-16) --222 + j*(110) --134 + j*(257) -118 + j*(292) -275 + j*(26) -51 + j*(-173) --101 + j*(43) -176 + j*(127) -243 + j*(-247) --187 + j*(-356) --349 + j*(45) --35 + j*(218) -104 + j*(-2) --42 + j*(-104) --130 + j*(-30) --140 + j*(59) --53 + j*(153) -100 + j*(58) --21 + j*(-139) --265 + j*(11) --124 + j*(286) -123 + j*(177) -21 + j*(18) --54 + j*(158) -110 + j*(206) -146 + j*(98) -148 + j*(144) -346 + j*(78) -331 + j*(-241) -21 + j*(-313) --62 + j*(-134) --5 + j*(-163) --192 + j*(-202) --315 + j*(64) --100 + j*(282) -128 + j*(213) -204 + j*(84) -226 + j*(-52) -133 + j*(-189) --13 + j*(-185) --60 + j*(-127) --117 + j*(-110) --192 + j*(11) --81 + j*(163) -76 + j*(117) -71 + j*(33) -98 + j*(65) -218 + j*(-32) -136 + j*(-245) --103 + j*(-230) --140 + j*(-43) --17 + j*(-5) -2 + j*(-107) --103 + j*(-146) --204 + j*(-68) --201 + j*(74) --77 + j*(156) -43 + j*(87) -18 + j*(-26) --78 + j*(-23) --92 + j*(71) --6 + j*(110) -65 + j*(51) -54 + j*(-28) -3 + j*(-69) --63 + j*(-95) --188 + j*(-63) --260 + j*(119) --112 + j*(305) -105 + j*(266) -153 + j*(124) -122 + j*(88) -158 + j*(67) -161 + j*(-8) -119 + j*(-23) -158 + j*(-27) -180 + j*(-141) -59 + j*(-246) --91 + j*(-214) --161 + j*(-121) --182 + j*(-28) --158 + j*(57) --108 + j*(107) --62 + j*(150) -40 + j*(182) -164 + j*(95) -141 + j*(-78) --38 + j*(-122) --150 + j*(40) --28 + j*(221) -210 + j*(173) -235 + j*(-68) -36 + j*(-117) -44 + j*(62) -269 + j*(-25) -148 + j*(-341) --221 + j*(-246) --154 + j*(107) -140 + j*(24) -11 + j*(-214) --194 + j*(-41) --2 + j*(136) -152 + j*(-42) -34 + j*(-159) -0 + j*(-144) --70 + j*(-254) --342 + j*(-173) --310 + j*(194) -59 + j*(204) -55 + j*(-135) --282 + j*(-95) --249 + j*(260) -87 + j*(286) -177 + j*(19) -3 + j*(-105) --130 + j*(-4) --79 + j*(127) -51 + j*(107) -32 + j*(-21) --107 + j*(11) --69 + j*(170) -93 + j*(142) -66 + j*(13) --25 + j*(60) -45 + j*(134) -104 + j*(72) -62 + j*(64) -124 + j*(116) -233 + j*(27) -179 + j*(-120) -54 + j*(-121) -39 + j*(-40) -120 + j*(-28) -174 + j*(-146) -57 + j*(-303) --192 + j*(-267) --262 + j*(-21) --100 + j*(103) --4 + j*(28) --45 + j*(-1) --27 + j*(39) -15 + j*(4) --26 + j*(-27) --45 + j*(16) --8 + j*(23) --14 + j*(3) --22 + j*(30) -24 + j*(40) -49 + j*(-11) -18 + j*(-54) --32 + j*(-62) --83 + j*(-26) --80 + j*(49) --13 + j*(76) -18 + j*(38) -1 + j*(34) -29 + j*(61) -78 + j*(30) -78 + j*(-23) -62 + j*(-53) -33 + j*(-89) --33 + j*(-95) --72 + j*(-38) --35 + j*(1) --16 + j*(-37) --78 + j*(-54) --124 + j*(26) --56 + j*(110) -44 + j*(68) -13 + j*(-25) --82 + j*(21) --27 + j*(143) -125 + j*(108) -138 + j*(-32) -62 + j*(-75) -40 + j*(-86) --35 + j*(-128) --145 + j*(-28) --37 + j*(131) -164 + j*(13) -54 + j*(-241) --240 + j*(-185) --275 + j*(87) --105 + j*(175) --54 + j*(129) --41 + j*(175) -83 + j*(185) -124 + j*(48) -2 + j*(26) -26 + j*(180) -254 + j*(150) -280 + j*(-119) -47 + j*(-206) --38 + j*(-61) -35 + j*(-46) --37 + j*(-86) --65 + j*(52) -115 + j*(58) -78 + j*(-153) --162 + j*(-54) -6 + j*(223) -328 + j*(5) -98 + j*(-344) --228 + j*(-127) --13 + j*(134) -175 + j*(-97) --51 + j*(-226) --109 + j*(-45) -19 + j*(-105) --165 + j*(-229) --330 + j*(17) --105 + j*(196) -25 + j*(25) --117 + j*(-30) --136 + j*(91) --75 + j*(111) --64 + j*(157) -81 + j*(193) -156 + j*(-6) --69 + j*(-76) --107 + j*(180) -178 + j*(200) -199 + j*(-71) --4 + j*(-74) -49 + j*(42) -105 + j*(-75) --48 + j*(-87) --8 + j*(64) -129 + j*(-42) --34 + j*(-173) --140 + j*(16) -51 + j*(69) -30 + j*(-128) --188 + j*(-42) --73 + j*(185) -127 + j*(80) -44 + j*(-42) -45 + j*(36) -153 + j*(-95) --71 + j*(-272) --311 + j*(-13) --74 + j*(242) -141 + j*(32) --62 + j*(-125) --179 + j*(77) --16 + j*(167) -16 + j*(71) --38 + j*(141) -119 + j*(219) -250 + j*(59) -155 + j*(-83) -79 + j*(-50) -105 + j*(-57) -56 + j*(-115) --28 + j*(-63) -15 + j*(38) -155 + j*(28) -233 + j*(-149) -82 + j*(-362) --228 + j*(-315) --295 + j*(-9) --49 + j*(83) --19 + j*(-139) --301 + j*(-110) --281 + j*(252) -97 + j*(297) -186 + j*(-23) --48 + j*(-92) --55 + j*(87) -105 + j*(33) -14 + j*(-136) --166 + j*(-42) --105 + j*(145) -69 + j*(142) -126 + j*(14) -69 + j*(-76) --10 + j*(-82) --33 + j*(-52) --43 + j*(-77) --158 + j*(-76) --227 + j*(112) --27 + j*(276) -199 + j*(119) -109 + j*(-119) --103 + j*(-88) --129 + j*(78) --34 + j*(158) -71 + j*(153) -141 + j*(63) -81 + j*(-21) -36 + j*(50) -183 + j*(53) -187 + j*(-201) --153 + j*(-245) --253 + j*(144) -149 + j*(292) -339 + j*(-86) -25 + j*(-294) --154 + j*(-68) --1 + j*(33) -15 + j*(-88) --103 + j*(-47) --32 + j*(57) -37 + j*(-40) --107 + j*(-82) --166 + j*(107) -23 + j*(222) -186 + j*(107) -190 + j*(-50) -103 + j*(-158) --57 + j*(-165) --136 + j*(8) -44 + j*(134) -214 + j*(-54) -40 + j*(-269) --199 + j*(-137) --110 + j*(89) -91 + j*(24) -50 + j*(-169) --138 + j*(-184) --230 + j*(-40) --163 + j*(98) --31 + j*(94) --35 + j*(-19) --166 + j*(23) --93 + j*(205) -140 + j*(119) -37 + j*(-144) --257 + j*(-19) --130 + j*(305) -187 + j*(207) -112 + j*(-46) --50 + j*(41) -73 + j*(127) -92 + j*(-15) --51 + j*(43) -88 + j*(204) -276 + j*(23) -107 + j*(-150) -25 + j*(11) -241 + j*(-28) -145 + j*(-346) --242 + j*(-277) --223 + j*(87) -62 + j*(66) --9 + j*(-175) --272 + j*(-85) --260 + j*(204) --30 + j*(338) -209 + j*(269) -321 + j*(43) -205 + j*(-158) -29 + j*(-143) -21 + j*(-46) -69 + j*(-63) -43 + j*(-95) -40 + j*(-97) -26 + j*(-156) --83 + j*(-180) --163 + j*(-90) --137 + j*(-2) --98 + j*(28) --65 + j*(42) --40 + j*(33) --45 + j*(40) -2 + j*(71) -71 + j*(3) -12 + j*(-86) --49 + j*(-52) --18 + j*(-75) --158 + j*(-172) --394 + j*(39) --216 + j*(417) -215 + j*(356) -267 + j*(-4) -39 + j*(-91) --21 + j*(19) -14 + j*(40) -23 + j*(61) -95 + j*(56) -98 + j*(-49) -4 + j*(-43) -59 + j*(7) -77 + j*(-148) --192 + j*(-173) --273 + j*(172) -69 + j*(319) -239 + j*(54) -88 + j*(-60) -86 + j*(-1) -102 + j*(-127) --129 + j*(-129) --141 + j*(173) -198 + j*(213) -281 + j*(-101) -58 + j*(-202) -4 + j*(-91) -53 + j*(-126) --39 + j*(-185) --129 + j*(-119) --148 + j*(-39) --126 + j*(63) -30 + j*(96) -95 + j*(-108) --163 + j*(-204) --314 + j*(91) --50 + j*(296) -163 + j*(134) -129 + j*(0) -139 + j*(-59) -47 + j*(-234) --250 + j*(-158) --202 + j*(202) -178 + j*(155) -110 + j*(-235) --288 + j*(-155) --218 + j*(224) -96 + j*(153) --20 + j*(-86) --237 + j*(98) --28 + j*(359) -277 + j*(214) -241 + j*(-70) -39 + j*(-107) --6 + j*(23) -114 + j*(50) -146 + j*(-100) --25 + j*(-165) --116 + j*(1) -40 + j*(86) -90 + j*(-74) --91 + j*(-78) --48 + j*(143) -234 + j*(71) -175 + j*(-279) --200 + j*(-285) --286 + j*(40) --75 + j*(151) --17 + j*(57) --71 + j*(105) -59 + j*(202) -235 + j*(68) -175 + j*(-158) --39 + j*(-190) --136 + j*(-37) --61 + j*(75) -27 + j*(76) -87 + j*(53) -165 + j*(-28) -125 + j*(-212) --119 + j*(-264) --262 + j*(-40) --106 + j*(139) -42 + j*(45) --30 + j*(-46) --74 + j*(23) --8 + j*(40) --19 + j*(-18) --76 + j*(11) --53 + j*(69) --13 + j*(94) -71 + j*(114) -192 + j*(-9) -81 + j*(-239) --222 + j*(-189) --243 + j*(119) -6 + j*(170) -20 + j*(-16) --153 + j*(39) --67 + j*(248) -168 + j*(204) -190 + j*(6) -79 + j*(-42) -55 + j*(11) -116 + j*(11) -151 + j*(-91) -37 + j*(-217) --189 + j*(-141) --180 + j*(150) -139 + j*(216) -272 + j*(-98) -0 + j*(-273) --162 + j*(-72) --13 + j*(18) --18 + j*(-144) --253 + j*(-80) --201 + j*(224) -119 + j*(223) -158 + j*(-62) --76 + j*(-111) --123 + j*(72) --8 + j*(115) -5 + j*(85) -42 + j*(146) -187 + j*(103) -190 + j*(-75) -51 + j*(-117) -18 + j*(-45) -43 + j*(-53) -4 + j*(-48) -48 + j*(8) -132 + j*(-81) -28 + j*(-197) --75 + j*(-110) -22 + j*(-79) --21 + j*(-257) --312 + j*(-221) --363 + j*(127) --65 + j*(267) -102 + j*(74) -8 + j*(-53) --57 + j*(-21) --49 + j*(-23) --98 + j*(-45) --168 + j*(1) --192 + j*(103) --134 + j*(218) -10 + j*(260) -124 + j*(185) -151 + j*(85) -132 + j*(1) -42 + j*(-52) --50 + j*(34) -49 + j*(156) -209 + j*(53) -132 + j*(-117) -2 + j*(-72) -53 + j*(-21) -35 + j*(-124) --127 + j*(-79) --94 + j*(112) -71 + j*(101) -65 + j*(6) -58 + j*(45) -162 + j*(-21) -55 + j*(-196) --175 + j*(-70) --47 + j*(199) -252 + j*(92) -190 + j*(-209) --69 + j*(-199) --71 + j*(-8) -73 + j*(-34) -11 + j*(-181) --168 + j*(-110) --112 + j*(105) -133 + j*(71) -139 + j*(-204) --138 + j*(-275) --276 + j*(-60) --179 + j*(93) --94 + j*(119) -18 + j*(148) -162 + j*(6) -26 + j*(-228) --247 + j*(-132) --196 + j*(110) --56 + j*(52) --201 + j*(25) --186 + j*(303) -185 + j*(322) -255 + j*(-55) --76 + j*(-139) --141 + j*(135) -88 + j*(190) -140 + j*(19) -35 + j*(-28) --6 + j*(30) -34 + j*(95) -163 + j*(86) -219 + j*(-117) --15 + j*(-264) --230 + j*(-56) --86 + j*(169) -83 + j*(84) -21 + j*(7) -28 + j*(96) -162 + j*(54) -146 + j*(-94) -45 + j*(-119) -13 + j*(-106) --49 + j*(-112) --103 + j*(-21) --24 + j*(58) -58 + j*(6) -44 + j*(-64) --5 + j*(-103) --108 + j*(-93) --155 + j*(63) -35 + j*(171) -190 + j*(-23) -7 + j*(-206) --175 + j*(-45) --35 + j*(121) -113 + j*(-3) -18 + j*(-146) --119 + j*(-103) --148 + j*(11) --88 + j*(97) -18 + j*(88) -26 + j*(-2) --47 + j*(23) -50 + j*(112) -197 + j*(-47) -23 + j*(-272) --256 + j*(-141) --197 + j*(119) --28 + j*(103) --75 + j*(49) --61 + j*(182) -146 + j*(168) -223 + j*(-352) --117 + j*(-362) --214 + j*(-116) --118 + j*(-18) --79 + j*(3) -4 + j*(16) -34 + j*(-110) --133 + j*(-130) --123 + j*(67) -101 + j*(-2) --35 + j*(-277) --377 + j*(-114) --243 + j*(260) -86 + j*(173) -13 + j*(-74) --164 + j*(1) --120 + j*(128) --76 + j*(166) -41 + j*(252) -271 + j*(109) -152 + j*(-218) --205 + j*(-132) --139 + j*(202) -138 + j*(141) -63 + j*(-48) --29 + j*(73) -163 + j*(103) -194 + j*(-156) --71 + j*(-252) --256 + j*(-65) --218 + j*(179) -21 + j*(313) -284 + j*(127) -158 + j*(-184) --140 + j*(-66) -32 + j*(200) -288 + j*(-52) --25 + j*(-322) --303 + j*(11) -8 + j*(266) -199 + j*(1) --21 + j*(-95) --13 + j*(100) -170 + j*(16) -52 + j*(-146) --64 + j*(-15) -80 + j*(44) -100 + j*(-100) --12 + j*(-95) -40 + j*(-29) -87 + j*(-139) --32 + j*(-217) --127 + j*(-185) --219 + j*(-163) --351 + j*(-13) --260 + j*(244) -8 + j*(251) -52 + j*(61) --82 + j*(55) --55 + j*(198) -103 + j*(207) -172 + j*(102) -163 + j*(34) -175 + j*(-6) -187 + j*(-92) -112 + j*(-191) --13 + j*(-187) --48 + j*(-117) --37 + j*(-129) --129 + j*(-146) --194 + j*(-21) --95 + j*(64) --56 + j*(-2) --133 + j*(26) --59 + j*(139) -74 + j*(41) --53 + j*(-100) --219 + j*(56) --78 + j*(266) -144 + j*(188) -136 + j*(12) -25 + j*(2) -35 + j*(95) -173 + j*(95) -249 + j*(-93) -69 + j*(-274) --174 + j*(-158) --117 + j*(83) -91 + j*(48) -60 + j*(-139) --109 + j*(-133) --146 + j*(-28) --153 + j*(18) --174 + j*(133) --21 + j*(262) -191 + j*(147) -131 + j*(-84) --91 + j*(-60) --91 + j*(168) -141 + j*(219) -254 + j*(37) -179 + j*(-83) -151 + j*(-97) -132 + j*(-204) --59 + j*(-262) --197 + j*(-70) --52 + j*(82) -57 + j*(-21) --24 + j*(-64) -4 + j*(2) -58 + j*(-95) --100 + j*(-137) --112 + j*(71) -148 + j*(45) -110 + j*(-274) --224 + j*(-282) --287 + j*(-44) --231 + j*(-8) --341 + j*(89) --217 + j*(372) -134 + j*(326) -149 + j*(50) -1 + j*(65) -110 + j*(130) -159 + j*(-41) --1 + j*(-98) --35 + j*(-6) --40 + j*(-34) --161 + j*(46) --49 + j*(272) -239 + j*(190) -215 + j*(-86) -18 + j*(-94) -22 + j*(13) -71 + j*(-9) -58 + j*(-19) -90 + j*(-33) -60 + j*(-100) --13 + j*(-57) -71 + j*(-2) -117 + j*(-132) --30 + j*(-194) --86 + j*(-75) --5 + j*(-81) --77 + j*(-177) --211 + j*(-114) --216 + j*(12) --179 + j*(95) --92 + j*(181) -43 + j*(148) -42 + j*(47) -11 + j*(85) -128 + j*(83) -135 + j*(-89) --26 + j*(-108) --13 + j*(-4) -34 + j*(-100) --165 + j*(-124) --202 + j*(153) -97 + j*(221) -173 + j*(-41) --33 + j*(-90) --23 + j*(67) -114 + j*(-3) -16 + j*(-141) --141 + j*(-59) --120 + j*(104) -6 + j*(171) -139 + j*(124) -180 + j*(-7) -117 + j*(-78) -108 + j*(-89) -84 + j*(-193) --108 + j*(-221) --190 + j*(-8) -10 + j*(79) -62 + j*(-123) --175 + j*(-160) --235 + j*(95) --3 + j*(199) -134 + j*(30) -48 + j*(-132) --129 + j*(-153) --287 + j*(-12) --277 + j*(249) --39 + j*(432) -274 + j*(365) -433 + j*(85) -322 + j*(-204) -59 + j*(-260) --57 + j*(-103) -18 + j*(-27) -33 + j*(-77) --15 + j*(-50) -49 + j*(-8) -103 + j*(-109) -4 + j*(-202) --118 + j*(-167) --178 + j*(-77) --171 + j*(42) --45 + j*(113) -62 + j*(-1) --47 + j*(-123) --185 + j*(-22) --116 + j*(124) -4 + j*(99) -1 + j*(15) --64 + j*(18) --69 + j*(95) -28 + j*(132) -93 + j*(33) --4 + j*(-34) --49 + j*(76) -84 + j*(90) -58 + j*(-60) --105 + j*(33) -72 + j*(223) -306 + j*(-32) -3 + j*(-308) --298 + j*(17) -28 + j*(320) -315 + j*(13) -51 + j*(-237) --146 + j*(-25) --1 + j*(113) -62 + j*(49) -73 + j*(97) -251 + j*(71) -310 + j*(-189) -95 + j*(-368) --134 + j*(-315) --258 + j*(-168) --263 + j*(39) --74 + j*(165) -98 + j*(18) --33 + j*(-171) --260 + j*(-57) --216 + j*(215) -39 + j*(288) -199 + j*(135) -175 + j*(-11) -128 + j*(-47) -139 + j*(-87) -107 + j*(-184) --12 + j*(-233) --125 + j*(-194) --191 + j*(-104) --168 + j*(8) --58 + j*(2) --112 + j*(-141) --364 + j*(-62) --354 + j*(296) --7 + j*(395) -122 + j*(168) -4 + j*(133) -89 + j*(241) -245 + j*(127) -202 + j*(-16) -177 + j*(-44) -158 + j*(-179) --78 + j*(-233) --194 + j*(-3) --25 + j*(98) --21 + j*(-19) --141 + j*(86) -23 + j*(247) -190 + j*(107) -105 + j*(16) -142 + j*(83) -241 + j*(-56) -65 + j*(-168) -5 + j*(20) -246 + j*(1) -198 + j*(-315) --134 + j*(-306) --176 + j*(-57) --74 + j*(-21) --92 + j*(25) -76 + j*(118) -253 + j*(-148) --59 + j*(-423) --412 + j*(-146) --233 + j*(209) -33 + j*(124) --13 + j*(-18) --54 + j*(36) -2 + j*(25) --38 + j*(-10) --30 + j*(65) -95 + j*(10) -16 + j*(-184) --251 + j*(-123) --256 + j*(179) -20 + j*(262) -134 + j*(60) -3 + j*(-25) --24 + j*(76) -87 + j*(51) -25 + j*(-78) --124 + j*(8) --28 + j*(175) -152 + j*(83) -81 + j*(-86) --64 + j*(-41) --49 + j*(65) --4 + j*(88) -44 + j*(122) -156 + j*(86) -158 + j*(-56) -40 + j*(-72) -57 + j*(4) -123 + j*(-68) -23 + j*(-143) --40 + j*(-57) -34 + j*(-45) --11 + j*(-144) --154 + j*(-81) --125 + j*(83) -10 + j*(102) -62 + j*(28) -48 + j*(-32) --8 + j*(-69) --83 + j*(-17) --49 + j*(91) -76 + j*(95) -133 + j*(-16) -76 + j*(-117) --46 + j*(-124) --100 + j*(-6) -15 + j*(78) -121 + j*(-42) -18 + j*(-172) --105 + j*(-120) --112 + j*(-68) --171 + j*(-49) --202 + j*(98) --40 + j*(182) -48 + j*(47) --74 + j*(1) --91 + j*(130) -13 + j*(153) -28 + j*(134) -112 + j*(191) -283 + j*(66) -190 + j*(-181) --50 + j*(-140) --25 + j*(47) -116 + j*(8) -77 + j*(-105) --1 + j*(-88) --8 + j*(-64) --26 + j*(-51) --6 + j*(-22) -13 + j*(-75) --98 + j*(-91) --134 + j*(87) -96 + j*(171) -262 + j*(-78) -49 + j*(-341) --283 + j*(-235) --309 + j*(95) --49 + j*(218) -96 + j*(40) --30 + j*(-72) --94 + j*(37) -9 + j*(51) --33 + j*(-47) --124 + j*(53) -39 + j*(127) -79 + j*(-116) --263 + j*(-139) --325 + j*(289) -103 + j*(416) -244 + j*(88) -29 + j*(35) -117 + j*(213) -332 + j*(40) -176 + j*(-206) --27 + j*(-109) -34 + j*(4) -69 + j*(-52) -26 + j*(-38) -86 + j*(-21) -98 + j*(-133) --35 + j*(-187) --146 + j*(-99) --163 + j*(30) --75 + j*(153) -102 + j*(144) -151 + j*(-22) -29 + j*(-74) -21 + j*(30) -142 + j*(8) -147 + j*(-128) -60 + j*(-193) --25 + j*(-213) --138 + j*(-165) --137 + j*(-36) --25 + j*(-57) --117 + j*(-185) --313 + j*(-41) --186 + j*(215) -73 + j*(129) -10 + j*(-91) --188 + j*(-33) --156 + j*(150) --1 + j*(170) -66 + j*(65) -9 + j*(-28) --105 + j*(-4) --117 + j*(129) -7 + j*(177) -62 + j*(92) -2 + j*(70) --1 + j*(146) -91 + j*(202) -249 + j*(173) -368 + j*(-40) -200 + j*(-308) --124 + j*(-233) --95 + j*(58) -148 + j*(-4) -25 + j*(-247) --243 + j*(-95) --110 + j*(173) -111 + j*(69) -13 + j*(-80) --71 + j*(30) -45 + j*(75) -62 + j*(-25) --4 + j*(-7) -66 + j*(32) -112 + j*(-86) --21 + j*(-180) --173 + j*(-95) --192 + j*(79) --62 + j*(213) -132 + j*(177) -175 + j*(3) -57 + j*(-47) -61 + j*(55) -217 + j*(21) -240 + j*(-191) -69 + j*(-334) --145 + j*(-303) --267 + j*(-139) --214 + j*(37) --87 + j*(57) --81 + j*(0) --100 + j*(49) --11 + j*(47) --57 + j*(-75) --234 + j*(18) --134 + j*(261) -125 + j*(190) -74 + j*(-13) --49 + j*(70) -92 + j*(134) -115 + j*(-39) --58 + j*(3) -84 + j*(188) -326 + j*(-57) -28 + j*(-380) --365 + j*(-95) --148 + j*(321) -235 + j*(210) -224 + j*(-69) -118 + j*(-110) -112 + j*(-178) --54 + j*(-281) --257 + j*(-122) --157 + j*(101) -25 + j*(32) --56 + j*(-122) --231 + j*(-43) --213 + j*(147) --79 + j*(205) --19 + j*(182) -27 + j*(203) -136 + j*(184) -176 + j*(63) -98 + j*(25) -138 + j*(98) -284 + j*(-20) -152 + j*(-266) --157 + j*(-163) --75 + j*(167) -272 + j*(98) -243 + j*(-262) --79 + j*(-310) --180 + j*(-104) --121 + j*(-22) --129 + j*(17) --73 + j*(122) -73 + j*(115) -127 + j*(-4) -89 + j*(-89) -13 + j*(-136) --88 + j*(-99) --75 + j*(14) -24 + j*(-11) --43 + j*(-105) --148 + j*(16) -12 + j*(148) -184 + j*(-37) -13 + j*(-256) --235 + j*(-158) --253 + j*(63) --132 + j*(175) -7 + j*(188) -121 + j*(86) -82 + j*(-61) --48 + j*(-65) --71 + j*(22) --37 + j*(45) --30 + j*(61) -25 + j*(79) -67 + j*(5) --13 + j*(-47) --65 + j*(34) -18 + j*(83) -67 + j*(-1) --18 + j*(-66) --122 + j*(-3) --121 + j*(146) -42 + j*(250) -243 + j*(139) -220 + j*(-100) -18 + j*(-141) --32 + j*(-6) -63 + j*(11) -41 + j*(-72) --39 + j*(-31) -7 + j*(40) -64 + j*(-4) -33 + j*(-47) -13 + j*(-38) --11 + j*(-57) --86 + j*(-13) --52 + j*(140) -160 + j*(158) -261 + j*(-52) -122 + j*(-205) -4 + j*(-161) -17 + j*(-146) --57 + j*(-216) --218 + j*(-132) --185 + j*(71) -6 + j*(81) -26 + j*(-89) --151 + j*(-119) --225 + j*(56) --95 + j*(184) -45 + j*(132) -45 + j*(26) --18 + j*(23) -0 + j*(76) -54 + j*(44) -15 + j*(1) --4 + j*(78) -135 + j*(101) -208 + j*(-83) -43 + j*(-216) --100 + j*(-126) --80 + j*(-51) --107 + j*(-56) --152 + j*(42) --45 + j*(132) -49 + j*(54) -0 + j*(1) -0 + j*(45) -58 + j*(7) -15 + j*(-72) --64 + j*(-62) --104 + j*(-23) --142 + j*(49) --80 + j*(156) -31 + j*(118) --28 + j*(48) --75 + j*(192) -141 + j*(274) -272 + j*(69) -136 + j*(-35) -148 + j*(63) -301 + j*(-52) -177 + j*(-295) --89 + j*(-259) --163 + j*(-65) --95 + j*(74) -64 + j*(137) -232 + j*(-18) -102 + j*(-238) --108 + j*(-122) -47 + j*(31) -162 + j*(-208) --146 + j*(-344) --315 + j*(-50) --107 + j*(96) --50 + j*(-24) --119 + j*(23) --1 + j*(54) --10 + j*(-113) --206 + j*(-80) --172 + j*(90) --112 + j*(31) --278 + j*(105) --152 + j*(428) -272 + j*(356) -274 + j*(-40) --8 + j*(-49) -43 + j*(140) -188 + j*(39) -100 + j*(-66) -71 + j*(-19) -104 + j*(-89) --40 + j*(-136) --99 + j*(35) -70 + j*(86) -100 + j*(-71) --41 + j*(-81) --35 + j*(41) -64 + j*(29) -54 + j*(-48) -4 + j*(-39) -16 + j*(-15) -30 + j*(-28) -23 + j*(-38) -37 + j*(-33) -69 + j*(-82) -5 + j*(-177) --146 + j*(-139) --141 + j*(26) -6 + j*(3) --82 + j*(-157) --302 + j*(-16) --176 + j*(260) -77 + j*(187) -21 + j*(42) -0 + j*(155) -213 + j*(106) -161 + j*(-171) --105 + j*(-142) --74 + j*(41) --6 + j*(-48) --200 + j*(-20) --127 + j*(281) -233 + j*(215) -174 + j*(-139) --139 + j*(-53) --16 + j*(238) -275 + j*(110) -204 + j*(-158) -18 + j*(-156) --12 + j*(-95) --54 + j*(-97) --115 + j*(-15) --56 + j*(88) -47 + j*(91) -103 + j*(29) -100 + j*(-44) -52 + j*(-76) -48 + j*(-64) -62 + j*(-144) --107 + j*(-223) --295 + j*(-20) --124 + j*(269) -211 + j*(180) -210 + j*(-136) --30 + j*(-187) --75 + j*(-37) -23 + j*(-43) --26 + j*(-152) --160 + j*(-112) --173 + j*(-1) --141 + j*(27) --179 + j*(72) --134 + j*(211) -62 + j*(235) -153 + j*(57) -18 + j*(-49) --91 + j*(59) --9 + j*(190) -154 + j*(190) -287 + j*(50) -264 + j*(-194) --6 + j*(-338) --285 + j*(-137) --204 + j*(201) -122 + j*(242) -264 + j*(-21) -90 + j*(-225) --133 + j*(-137) --104 + j*(73) -94 + j*(60) -81 + j*(-141) --124 + j*(-130) --107 + j*(52) -30 + j*(-14) --123 + j*(-132) --267 + j*(105) --4 + j*(286) -173 + j*(42) --68 + j*(-75) --126 + j*(203) -191 + j*(258) -284 + j*(-37) -79 + j*(-140) -24 + j*(-43) -53 + j*(-62) --16 + j*(-51) -40 + j*(43) -168 + j*(-70) -23 + j*(-254) --206 + j*(-125) --115 + j*(107) -86 + j*(30) --8 + j*(-153) --216 + j*(-48) --146 + j*(204) -122 + j*(213) -206 + j*(-9) -70 + j*(-124) --12 + j*(-57) -35 + j*(-30) -35 + j*(-92) --35 + j*(-102) --54 + j*(-55) --30 + j*(-59) --64 + j*(-103) --161 + j*(-87) --221 + j*(37) --135 + j*(186) -44 + j*(175) -94 + j*(25) -1 + j*(-35) --40 + j*(4) --54 + j*(4) --107 + j*(71) -4 + j*(193) -194 + j*(51) -24 + j*(-204) --309 + j*(-17) --148 + j*(399) -307 + j*(319) -320 + j*(-84) -30 + j*(-134) -13 + j*(58) -161 + j*(40) -166 + j*(-69) -151 + j*(-122) -107 + j*(-256) --153 + j*(-310) --333 + j*(-22) --107 + j*(238) -148 + j*(95) -56 + j*(-95) --53 + j*(-16) -44 + j*(20) -18 + j*(-106) --148 + j*(-36) --59 + j*(171) -180 + j*(93) -134 + j*(-147) --69 + j*(-138) --74 + j*(8) -19 + j*(6) -6 + j*(-56) --35 + j*(-47) --35 + j*(-32) --45 + j*(-34) --56 + j*(-30) --88 + j*(-30) --137 + j*(29) --98 + j*(129) -4 + j*(142) -40 + j*(108) -86 + j*(119) -192 + j*(45) -163 + j*(-137) --23 + j*(-178) --109 + j*(-47) --45 + j*(38) -23 + j*(16) -29 + j*(-38) --18 + j*(-78) --82 + j*(-54) --97 + j*(-8) --124 + j*(24) --136 + j*(148) -54 + j*(250) -238 + j*(50) -54 + j*(-159) --132 + j*(24) -81 + j*(172) -197 + j*(-84) --91 + j*(-178) --169 + j*(130) -138 + j*(212) -238 + j*(-50) -71 + j*(-148) -27 + j*(-93) -21 + j*(-141) --101 + j*(-151) --175 + j*(-35) --143 + j*(88) --20 + j*(175) -168 + j*(91) -126 + j*(-157) --150 + j*(-144) --145 + j*(139) -122 + j*(133) -107 + j*(-90) --35 + j*(-45) -81 + j*(3) -63 + j*(-230) --289 + j*(-218) --350 + j*(189) -14 + j*(330) -170 + j*(72) --1 + j*(-24) --21 + j*(124) -160 + j*(117) -177 + j*(-96) --41 + j*(-163) --151 + j*(40) -27 + j*(177) -166 + j*(32) -45 + j*(-67) -13 + j*(75) -225 + j*(71) -252 + j*(-197) -13 + j*(-288) --76 + j*(-163) --52 + j*(-177) --203 + j*(-203) --318 + j*(5) --170 + j*(200) -23 + j*(168) -77 + j*(37) -5 + j*(-57) --119 + j*(-8) --84 + j*(159) -120 + j*(156) -163 + j*(-39) -38 + j*(-105) -2 + j*(-85) --69 + j*(-130) --208 + j*(-8) --69 + j*(190) -144 + j*(28) --67 + j*(-190) --315 + j*(65) --78 + j*(351) -194 + j*(199) -129 + j*(35) -116 + j*(79) -212 + j*(-13) -105 + j*(-165) --42 + j*(-103) --18 + j*(-26) --33 + j*(-53) --98 + j*(36) -28 + j*(151) -187 + j*(27) -95 + j*(-152) --76 + j*(-102) --53 + j*(45) -81 + j*(30) -79 + j*(-110) --73 + j*(-139) --142 + j*(-1) --56 + j*(91) -11 + j*(70) -44 + j*(74) -137 + j*(27) -115 + j*(-141) --91 + j*(-153) --125 + j*(53) -66 + j*(93) -107 + j*(-72) --11 + j*(-115) --41 + j*(-74) --77 + j*(-88) --153 + j*(-8) --74 + j*(104) -13 + j*(44) --59 + j*(32) -12 + j*(166) -238 + j*(53) -144 + j*(-252) --177 + j*(-214) --190 + j*(52) --13 + j*(71) --35 + j*(-33) --102 + j*(30) --28 + j*(89) -14 + j*(33) --23 + j*(18) --9 + j*(43) -12 + j*(16) --22 + j*(-2) --42 + j*(20) --49 + j*(36) --61 + j*(78) --13 + j*(137) -71 + j*(127) -106 + j*(69) -105 + j*(23) -86 + j*(-14) -47 + j*(-19) -42 + j*(12) -81 + j*(4) -81 + j*(-41) -54 + j*(-64) -29 + j*(-87) --44 + j*(-96) --117 + j*(-6) --57 + j*(128) -97 + j*(144) -198 + j*(35) -192 + j*(-114) -61 + j*(-221) --120 + j*(-144) --91 + j*(68) -144 + j*(69) -187 + j*(-185) --45 + j*(-290) --186 + j*(-134) --126 + j*(-23) --78 + j*(-33) --77 + j*(-47) --109 + j*(-83) --236 + j*(-37) --226 + j*(202) -79 + j*(271) -223 + j*(-45) --52 + j*(-234) --246 + j*(-39) --148 + j*(95) --148 + j*(66) --197 + j*(212) -18 + j*(345) -206 + j*(161) -88 + j*(6) -4 + j*(106) -112 + j*(158) -176 + j*(88) -209 + j*(41) -247 + j*(-77) -134 + j*(-211) --4 + j*(-175) --25 + j*(-144) --153 + j*(-154) --265 + j*(98) -23 + j*(327) -317 + j*(71) -131 + j*(-193) --20 + j*(-42) -173 + j*(-32) -96 + j*(-317) --264 + j*(-239) --225 + j*(116) -62 + j*(96) -35 + j*(-115) --110 + j*(-95) --129 + j*(-40) --211 + j*(5) --209 + j*(233) -86 + j*(327) -258 + j*(68) -91 + j*(-89) -32 + j*(23) -170 + j*(-24) -79 + j*(-250) --222 + j*(-204) --284 + j*(109) --35 + j*(264) -156 + j*(127) -106 + j*(-33) -9 + j*(1) -76 + j*(74) -187 + j*(-17) -138 + j*(-182) --18 + j*(-234) --148 + j*(-174) --220 + j*(-49) --185 + j*(90) --85 + j*(149) --6 + j*(161) -112 + j*(158) -230 + j*(0) -107 + j*(-209) --117 + j*(-146) --82 + j*(18) --1 + j*(-53) --151 + j*(-81) --170 + j*(132) -49 + j*(147) -28 + j*(-42) --135 + j*(54) -24 + j*(213) -176 + j*(22) --32 + j*(-86) --86 + j*(156) -201 + j*(181) -238 + j*(-119) --22 + j*(-173) --73 + j*(19) -60 + j*(59) -112 + j*(-21) -105 + j*(-103) -6 + j*(-199) --177 + j*(-119) --129 + j*(101) -83 + j*(54) --2 + j*(-140) --205 + j*(7) --2 + j*(243) -291 + j*(10) -77 + j*(-358) --356 + j*(-235) --397 + j*(187) --103 + j*(388) -156 + j*(310) -265 + j*(131) -234 + j*(-39) -114 + j*(-98) -68 + j*(-42) -121 + j*(-46) -118 + j*(-134) -43 + j*(-175) --6 + j*(-183) --94 + j*(-211) --239 + j*(-127) --238 + j*(78) --62 + j*(156) -25 + j*(55) --22 + j*(17) --8 + j*(59) -60 + j*(25) -52 + j*(-66) --31 + j*(-122) --165 + j*(-97) --246 + j*(84) --81 + j*(274) -169 + j*(173) -129 + j*(-61) --41 + j*(-42) --1 + j*(53) -28 + j*(-37) --127 + j*(-18) --95 + j*(196) -140 + j*(185) -142 + j*(-6) -23 + j*(27) -132 + j*(103) -218 + j*(-57) -79 + j*(-162) -8 + j*(-87) -34 + j*(-99) --49 + j*(-119) --70 + j*(-13) -31 + j*(-25) --42 + j*(-132) --174 + j*(-13) --49 + j*(132) -66 + j*(23) --40 + j*(-21) --6 + j*(108) -163 + j*(21) -55 + j*(-175) --128 + j*(-65) --13 + j*(71) -65 + j*(-69) --99 + j*(-96) --74 + j*(76) -100 + j*(-28) --100 + j*(-233) --386 + j*(34) --129 + j*(409) -279 + j*(222) -163 + j*(-144) --134 + j*(-53) --40 + j*(199) -188 + j*(122) -153 + j*(-63) -43 + j*(-46) -86 + j*(-2) -121 + j*(-87) -28 + j*(-152) --52 + j*(-89) --8 + j*(-25) -50 + j*(-85) --23 + j*(-180) --165 + j*(-146) --204 + j*(-16) --154 + j*(54) --144 + j*(88) --98 + j*(173) -43 + j*(182) -98 + j*(55) -8 + j*(6) --11 + j*(95) -104 + j*(115) -175 + j*(6) -135 + j*(-130) --28 + j*(-204) --218 + j*(-63) --127 + j*(205) -177 + j*(165) -170 + j*(-130) --81 + j*(-122) --25 + j*(62) -99 + j*(-93) --175 + j*(-198) --305 + j*(164) -71 + j*(327) -210 + j*(6) --46 + j*(-25) -81 + j*(217) -372 + j*(-47) -49 + j*(-410) --353 + j*(-103) --105 + j*(274) -185 + j*(89) -45 + j*(-71) -21 + j*(68) -194 + j*(-9) -76 + j*(-224) --145 + j*(-120) --81 + j*(67) -43 + j*(45) -63 + j*(8) -141 + j*(-40) -125 + j*(-245) --159 + j*(-333) --387 + j*(-76) --262 + j*(242) -52 + j*(285) -228 + j*(51) -97 + j*(-194) --165 + j*(-156) --192 + j*(86) -6 + j*(148) -72 + j*(6) --21 + j*(-44) --42 + j*(8) --21 + j*(-8) --69 + j*(-26) --122 + j*(25) --125 + j*(115) --47 + j*(216) -127 + j*(212) -209 + j*(37) -93 + j*(-69) -43 + j*(0) -126 + j*(-35) -35 + j*(-187) --184 + j*(-109) --168 + j*(132) -25 + j*(175) -89 + j*(71) -62 + j*(46) -91 + j*(54) -129 + j*(8) -129 + j*(-59) -84 + j*(-127) --25 + j*(-149) --112 + j*(-56) --74 + j*(61) -32 + j*(75) -75 + j*(9) -45 + j*(-30) -35 + j*(-6) -99 + j*(-19) -99 + j*(-148) --78 + j*(-198) --180 + j*(-15) --16 + j*(105) -88 + j*(-45) --67 + j*(-121) --122 + j*(45) -47 + j*(96) -112 + j*(-54) -18 + j*(-138) --59 + j*(-147) --173 + j*(-126) --249 + j*(50) --78 + j*(206) -102 + j*(76) -4 + j*(-79) --115 + j*(8) --25 + j*(96) -45 + j*(4) --52 + j*(-67) --154 + j*(13) --117 + j*(154) -38 + j*(181) -104 + j*(40) --29 + j*(-26) --80 + j*(121) -78 + j*(172) -119 + j*(44) -52 + j*(59) -178 + j*(81) -203 + j*(-158) --105 + j*(-211) --176 + j*(105) -100 + j*(158) -86 + j*(-57) --78 + j*(70) -170 + j*(234) -381 + j*(-73) -115 + j*(-324) --103 + j*(-158) --21 + j*(-47) --13 + j*(-86) --24 + j*(-48) -26 + j*(-95) --98 + j*(-156) --170 + j*(23) -34 + j*(74) -33 + j*(-156) --228 + j*(-105) --163 + j*(162) -49 + j*(91) --55 + j*(-23) --78 + j*(143) -136 + j*(117) -88 + j*(-100) --74 + j*(-24) -45 + j*(58) -47 + j*(-107) --160 + j*(-49) --60 + j*(171) -133 + j*(49) --1 + j*(-78) --38 + j*(78) -146 + j*(24) -27 + j*(-180) --169 + j*(-9) -54 + j*(150) -183 + j*(-133) --143 + j*(-261) --291 + j*(56) --34 + j*(204) -76 + j*(14) --81 + j*(-49) --136 + j*(98) --8 + j*(189) -109 + j*(116) -85 + j*(4) --1 + j*(27) -54 + j*(110) -161 + j*(28) -81 + j*(-88) --9 + j*(-13) -81 + j*(32) -89 + j*(-84) --42 + j*(-56) -25 + j*(90) -211 + j*(2) -165 + j*(-228) --50 + j*(-291) --224 + j*(-180) --269 + j*(36) --84 + j*(199) -123 + j*(67) -13 + j*(-132) --170 + j*(-20) --52 + j*(141) -76 + j*(28) --49 + j*(-59) --116 + j*(81) -17 + j*(170) -146 + j*(95) -168 + j*(-48) -49 + j*(-161) --111 + j*(-78) --35 + j*(81) -108 + j*(-36) --85 + j*(-177) --255 + j*(91) -52 + j*(313) -323 + j*(22) -112 + j*(-261) --116 + j*(-156) --99 + j*(-52) --137 + j*(-53) --193 + j*(76) --76 + j*(194) -32 + j*(173) -106 + j*(176) -270 + j*(93) -274 + j*(-181) -8 + j*(-296) --151 + j*(-134) --101 + j*(-42) --129 + j*(-54) --191 + j*(64) --76 + j*(199) -84 + j*(156) -115 + j*(51) -105 + j*(1) -103 + j*(-62) -23 + j*(-135) --111 + j*(-93) --134 + j*(71) -18 + j*(165) -168 + j*(69) -170 + j*(-89) -86 + j*(-190) --62 + j*(-257) --286 + j*(-156) --298 + j*(162) -30 + j*(271) -175 + j*(-34) --128 + j*(-179) --298 + j*(134) --25 + j*(361) -221 + j*(213) -233 + j*(49) -245 + j*(-49) -184 + j*(-243) --98 + j*(-312) --303 + j*(-71) --190 + j*(200) -52 + j*(226) -160 + j*(67) -76 + j*(-42) -1 + j*(37) -141 + j*(112) -286 + j*(-86) -103 + j*(-325) --180 + j*(-226) --165 + j*(12) --15 + j*(30) --6 + j*(-50) --42 + j*(-57) --66 + j*(-71) --141 + j*(-52) --167 + j*(64) --81 + j*(138) --5 + j*(130) -53 + j*(117) -122 + j*(42) -70 + j*(-81) --72 + j*(-55) --62 + j*(87) -76 + j*(93) -98 + j*(-37) --18 + j*(-68) --57 + j*(47) -69 + j*(101) -165 + j*(-36) -36 + j*(-178) --132 + j*(-77) --51 + j*(88) -105 + j*(7) -21 + j*(-148) --135 + j*(-89) --132 + j*(34) --95 + j*(84) --34 + j*(168) -147 + j*(148) -190 + j*(-71) --7 + j*(-144) --42 + j*(10) -92 + j*(-43) --45 + j*(-206) --257 + j*(-30) --90 + j*(206) -115 + j*(66) --11 + j*(-71) --69 + j*(61) -85 + j*(42) --3 + j*(-151) --255 + j*(-30) --164 + j*(272) -136 + j*(253) -180 + j*(23) -35 + j*(-36) --21 + j*(70) -77 + j*(161) -246 + j*(105) -296 + j*(-127) -86 + j*(-293) --139 + j*(-175) --122 + j*(16) --23 + j*(62) -29 + j*(76) -148 + j*(69) -228 + j*(-103) -88 + j*(-265) --78 + j*(-213) --85 + j*(-136) --115 + j*(-165) --247 + j*(-107) --253 + j*(92) --76 + j*(185) -58 + j*(76) -3 + j*(-54) --125 + j*(-25) --125 + j*(115) -2 + j*(161) -76 + j*(91) -89 + j*(49) -140 + j*(-18) -88 + j*(-181) --148 + j*(-204) --255 + j*(20) --112 + j*(158) --23 + j*(98) --56 + j*(100) --4 + j*(156) -62 + j*(124) -68 + j*(116) -159 + j*(119) -223 + j*(-42) -63 + j*(-168) --75 + j*(-52) --2 + j*(51) -45 + j*(11) -22 + j*(23) -86 + j*(39) -112 + j*(-45) -52 + j*(-62) -90 + j*(-48) -91 + j*(-175) --97 + j*(-210) --167 + j*(-32) --47 + j*(19) --75 + j*(-48) --134 + j*(64) -28 + j*(141) -114 + j*(-26) --23 + j*(-104) --72 + j*(-25) --67 + j*(-39) --186 + j*(16) --132 + j*(243) -148 + j*(263) -255 + j*(40) -181 + j*(-93) -116 + j*(-193) --99 + j*(-260) --295 + j*(-11) --73 + j*(253) -186 + j*(70) -24 + j*(-122) --80 + j*(49) -122 + j*(68) -71 + j*(-155) --151 + j*(-36) -57 + j*(177) -284 + j*(-136) --108 + j*(-418) --460 + j*(-14) --102 + j*(373) -259 + j*(76) -0 + j*(-238) --278 + j*(4) --77 + j*(258) -132 + j*(125) -50 + j*(5) -30 + j*(89) -156 + j*(59) -136 + j*(-91) -25 + j*(-89) -60 + j*(-50) -67 + j*(-173) --136 + j*(-235) --296 + j*(-33) --186 + j*(202) -47 + j*(213) -152 + j*(32) -25 + j*(-130) --182 + j*(-38) --134 + j*(219) -156 + j*(234) -235 + j*(-38) -19 + j*(-140) --61 + j*(23) -84 + j*(67) -126 + j*(-87) --25 + j*(-165) --162 + j*(-55) --124 + j*(133) -90 + j*(179) -211 + j*(-38) -13 + j*(-212) --182 + j*(-48) --60 + j*(128) -51 + j*(36) --46 + j*(10) --1 + j*(147) -177 + j*(74) -106 + j*(-110) --42 + j*(-34) -55 + j*(71) -138 + j*(-32) -71 + j*(-79) -117 + j*(-62) -138 + j*(-248) --153 + j*(-356) --378 + j*(-59) --158 + j*(226) -103 + j*(93) -21 + j*(-108) --128 + j*(-50) --100 + j*(57) --52 + j*(62) --37 + j*(88) -56 + j*(103) -120 + j*(-14) -18 + j*(-119) --86 + j*(-52) --49 + j*(19) --28 + j*(-16) --78 + j*(4) --28 + j*(66) -40 + j*(-21) --94 + j*(-110) --235 + j*(46) --122 + j*(244) -82 + j*(224) -149 + j*(86) -103 + j*(-18) -2 + j*(-36) --35 + j*(56) -57 + j*(84) -52 + j*(-11) --54 + j*(59) -101 + j*(197) -290 + j*(-27) -21 + j*(-250) --200 + j*(57) -144 + j*(256) -317 + j*(-111) --35 + j*(-231) --62 + j*(93) -255 + j*(8) -97 + j*(-315) --196 + j*(-134) --5 + j*(62) -65 + j*(-169) --229 + j*(-138) --146 + j*(197) -177 + j*(89) -48 + j*(-173) --131 + j*(-8) -79 + j*(94) -136 + j*(-148) --89 + j*(-189) --98 + j*(-37) --33 + j*(-115) --235 + j*(-156) --340 + j*(135) --59 + j*(346) -229 + j*(163) -170 + j*(-139) --100 + j*(-177) --182 + j*(55) -35 + j*(134) -83 + j*(-104) --205 + j*(-132) --235 + j*(199) -92 + j*(236) -101 + j*(-49) --137 + j*(12) -4 + j*(226) -203 + j*(23) --34 + j*(-153) --190 + j*(95) -35 + j*(227) -117 + j*(71) -25 + j*(83) -146 + j*(158) -243 + j*(-14) -93 + j*(-117) -33 + j*(-8) -132 + j*(-5) -119 + j*(-95) -81 + j*(-100) -89 + j*(-154) --29 + j*(-220) --136 + j*(-104) --52 + j*(-29) --68 + j*(-131) --256 + j*(-42) --174 + j*(246) -167 + j*(237) -245 + j*(-77) -22 + j*(-215) --128 + j*(-107) --121 + j*(9) --64 + j*(64) -8 + j*(53) -4 + j*(-2) --37 + j*(31) -57 + j*(78) -134 + j*(-76) --64 + j*(-196) --221 + j*(20) --8 + j*(187) -134 + j*(-31) --113 + j*(-128) --178 + j*(175) -181 + j*(239) -266 + j*(-146) --107 + j*(-251) --209 + j*(91) -103 + j*(182) -199 + j*(-104) --37 + j*(-228) --179 + j*(-75) --117 + j*(39) --67 + j*(19) --123 + j*(6) --182 + j*(136) --29 + j*(314) -270 + j*(224) -297 + j*(-118) -5 + j*(-243) --147 + j*(-53) --59 + j*(62) --13 + j*(42) -6 + j*(65) -78 + j*(22) -16 + j*(-84) --120 + j*(-11) --54 + j*(141) -86 + j*(102) -69 + j*(6) -18 + j*(23) -39 + j*(59) -78 + j*(63) -129 + j*(35) -130 + j*(-42) -67 + j*(-43) -124 + j*(16) -233 + j*(-110) -101 + j*(-299) --107 + j*(-228) --93 + j*(-87) --44 + j*(-103) --73 + j*(-93) --12 + j*(-100) --74 + j*(-272) --402 + j*(-230) --477 + j*(182) --138 + j*(373) -49 + j*(196) --4 + j*(135) -72 + j*(177) -160 + j*(41) -48 + j*(-70) --42 + j*(-15) --48 + j*(32) --59 + j*(100) -64 + j*(181) -217 + j*(40) -97 + j*(-146) --69 + j*(-56) -16 + j*(49) -51 + j*(-58) --100 + j*(-43) --62 + j*(161) -190 + j*(142) -240 + j*(-128) -1 + j*(-267) --202 + j*(-106) --123 + j*(113) -81 + j*(69) -27 + j*(-138) --227 + j*(-65) --180 + j*(252) -156 + j*(284) -272 + j*(17) -142 + j*(-124) -55 + j*(-136) --46 + j*(-150) --151 + j*(-18) --26 + j*(148) -173 + j*(47) -125 + j*(-160) --49 + j*(-190) --146 + j*(-95) --146 + j*(23) --39 + j*(73) --4 + j*(-42) --192 + j*(-47) --214 + j*(250) -153 + j*(349) -335 + j*(-4) -52 + j*(-206) --117 + j*(13) -78 + j*(148) -223 + j*(-25) -107 + j*(-204) --91 + j*(-177) --137 + j*(24) -80 + j*(119) -240 + j*(-135) --16 + j*(-385) --337 + j*(-204) --276 + j*(81) --131 + j*(95) --144 + j*(98) --69 + j*(190) -58 + j*(122) -11 + j*(36) --13 + j*(97) -72 + j*(85) -51 + j*(5) -15 + j*(36) -71 + j*(20) -8 + j*(-52) --58 + j*(57) -110 + j*(100) -132 + j*(-136) --168 + j*(-152) --199 + j*(187) -130 + j*(242) -191 + j*(-30) --13 + j*(-49) -32 + j*(131) -248 + j*(64) -243 + j*(-201) --5 + j*(-322) --230 + j*(-169) --196 + j*(75) --16 + j*(98) --35 + j*(-2) --109 + j*(129) -127 + j*(247) -310 + j*(-20) -88 + j*(-214) --17 + j*(-38) -181 + j*(-79) -35 + j*(-376) --369 + j*(-230) --305 + j*(204) -51 + j*(236) -142 + j*(31) -117 + j*(-63) -76 + j*(-205) --181 + j*(-262) --340 + j*(21) --110 + j*(234) -94 + j*(80) --3 + j*(-83) --133 + j*(-50) --197 + j*(47) --180 + j*(219) -45 + j*(315) -223 + j*(128) -105 + j*(-37) -23 + j*(57) -156 + j*(66) -145 + j*(-112) --32 + j*(-117) --41 + j*(13) -35 + j*(-1) --9 + j*(-37) --20 + j*(28) -58 + j*(18) -37 + j*(-65) --47 + j*(-47) --27 + j*(33) -58 + j*(1) -15 + j*(-119) --175 + j*(-94) --216 + j*(169) -78 + j*(308) -295 + j*(36) -76 + j*(-201) --128 + j*(-14) -61 + j*(145) -202 + j*(-52) -37 + j*(-194) --88 + j*(-111) --111 + j*(-56) --168 + j*(45) --43 + j*(217) -190 + j*(112) -100 + j*(-115) --81 + j*(7) -115 + j*(171) -320 + j*(-76) -110 + j*(-345) --170 + j*(-251) --202 + j*(-48) --118 + j*(45) --31 + j*(53) -4 + j*(-3) --32 + j*(0) -56 + j*(38) -139 + j*(-158) --148 + j*(-346) --462 + j*(-49) --251 + j*(342) -106 + j*(250) -93 + j*(13) --2 + j*(1) --17 + j*(-29) --165 + j*(-13) --170 + j*(245) -145 + j*(297) -227 + j*(16) -27 + j*(-17) -124 + j*(132) -296 + j*(-95) -11 + j*(-325) --241 + j*(-57) --6 + j*(150) -126 + j*(-81) --124 + j*(-161) --195 + j*(89) -9 + j*(161) -58 + j*(30) --7 + j*(32) -46 + j*(65) -68 + j*(-27) --42 + j*(-48) --82 + j*(63) -6 + j*(127) -64 + j*(95) -73 + j*(83) -127 + j*(93) -195 + j*(22) -158 + j*(-81) -71 + j*(-58) -144 + j*(21) -292 + j*(-108) -192 + j*(-371) --107 + j*(-387) --221 + j*(-170) --129 + j*(-66) --102 + j*(-100) --140 + j*(-81) --131 + j*(-42) --135 + j*(-43) --150 + j*(-1) --105 + j*(19) --119 + j*(-37) --231 + j*(11) --203 + j*(185) --24 + j*(214) -26 + j*(82) --66 + j*(65) --45 + j*(161) -74 + j*(134) -50 + j*(-1) --112 + j*(23) --123 + j*(243) -134 + j*(355) -374 + j*(153) -311 + j*(-141) -69 + j*(-212) --59 + j*(-82) --23 + j*(46) -91 + j*(78) -191 + j*(-21) -141 + j*(-179) --24 + j*(-198) --78 + j*(-90) --41 + j*(-75) --111 + j*(-91) --164 + j*(45) --13 + j*(144) -105 + j*(21) -13 + j*(-90) --83 + j*(-31) --72 + j*(54) --16 + j*(114) -120 + j*(117) -209 + j*(-67) -25 + j*(-232) --168 + j*(-74) --19 + j*(94) -112 + j*(-90) --132 + j*(-218) --303 + j*(52) --74 + j*(267) -127 + j*(127) -59 + j*(10) -42 + j*(67) -127 + j*(27) -88 + j*(-70) -38 + j*(-35) -120 + j*(-59) -69 + j*(-244) --210 + j*(-252) --332 + j*(38) --124 + j*(254) -103 + j*(177) -129 + j*(16) -62 + j*(-56) --5 + j*(-55) --28 + j*(-5) -31 + j*(23) -71 + j*(-66) --43 + j*(-142) --154 + j*(-28) --56 + j*(91) -49 + j*(-14) --91 + j*(-120) --241 + j*(49) --97 + j*(265) -147 + j*(204) -175 + j*(4) -71 + j*(-74) -1 + j*(-69) --74 + j*(-44) --116 + j*(86) -41 + j*(211) -260 + j*(69) -173 + j*(-223) --151 + j*(-216) --218 + j*(95) -50 + j*(211) -184 + j*(-8) -11 + j*(-132) --96 + j*(4) -8 + j*(103) -95 + j*(48) -112 + j*(-3) -138 + j*(-74) -71 + j*(-193) --90 + j*(-191) --160 + j*(-76) --156 + j*(2) --149 + j*(106) -6 + j*(211) -207 + j*(63) -96 + j*(-185) --151 + j*(-116) --106 + j*(91) -28 + j*(43) --65 + j*(-14) --70 + j*(153) -167 + j*(157) -202 + j*(-108) --39 + j*(-171) --103 + j*(11) -18 + j*(47) -8 + j*(-15) --13 + j*(47) -106 + j*(54) -124 + j*(-97) --13 + j*(-128) --19 + j*(-32) -59 + j*(-93) --58 + j*(-210) --235 + j*(-93) --173 + j*(105) --12 + j*(91) --19 + j*(-16) --87 + j*(3) --59 + j*(40) --63 + j*(-13) --190 + j*(8) --238 + j*(218) --28 + j*(414) -288 + j*(330) -379 + j*(11) -155 + j*(-177) --21 + j*(-29) -142 + j*(110) -308 + j*(-112) -76 + j*(-364) --228 + j*(-204) --165 + j*(69) -11 + j*(55) --9 + j*(-9) -11 + j*(54) -137 + j*(-18) -57 + j*(-210) --174 + j*(-170) --202 + j*(40) --80 + j*(119) --4 + j*(99) -57 + j*(72) -91 + j*(-23) -2 + j*(-104) --105 + j*(-46) --95 + j*(64) --4 + j*(102) -67 + j*(42) -27 + j*(-38) --49 + j*(8) -37 + j*(84) -137 + j*(-60) --59 + j*(-211) --276 + j*(-4) --111 + j*(245) -100 + j*(150) -39 + j*(45) -44 + j*(131) -165 + j*(78) -103 + j*(-25) -91 + j*(86) -328 + j*(23) -293 + j*(-351) --117 + j*(-438) --303 + j*(-141) --199 + j*(38) --134 + j*(95) -3 + j*(163) -148 + j*(17) -15 + j*(-133) --74 + j*(6) -112 + j*(-8) -0 + j*(-288) --395 + j*(-139) --284 + j*(327) -161 + j*(292) -171 + j*(-38) --12 + j*(-35) -43 + j*(32) -42 + j*(-57) --28 + j*(-5) -96 + j*(-1) -39 + j*(-228) --286 + j*(-150) --209 + j*(217) -135 + j*(122) --25 + j*(-186) --325 + j*(42) --75 + j*(346) -185 + j*(126) --11 + j*(-35) --67 + j*(190) -208 + j*(199) -223 + j*(-86) --15 + j*(-120) --46 + j*(49) -71 + j*(74) -103 + j*(-5) -66 + j*(-67) --37 + j*(-75) --94 + j*(66) -62 + j*(173) -192 + j*(35) -88 + j*(-50) -105 + j*(66) -313 + j*(-35) -223 + j*(-352) --117 + j*(-362) --214 + j*(-116) --118 + j*(-18) --79 + j*(3) -4 + j*(16) -34 + j*(-110) --133 + j*(-130) --123 + j*(67) -101 + j*(-2) --35 + j*(-277) --377 + j*(-114) --243 + j*(260) -86 + j*(173) -13 + j*(-74) --164 + j*(1) --120 + j*(128) --76 + j*(166) -41 + j*(252) -271 + j*(109) -152 + j*(-218) --205 + j*(-132) --139 + j*(202) -138 + j*(141) -63 + j*(-48) --29 + j*(73) -163 + j*(103) -194 + j*(-156) --71 + j*(-252) --256 + j*(-65) --218 + j*(179) -21 + j*(313) -284 + j*(127) -158 + j*(-184) --140 + j*(-66) -32 + j*(200) -288 + j*(-52) --25 + j*(-322) --303 + j*(11) -8 + j*(266) -199 + j*(1) --21 + j*(-95) --13 + j*(100) -170 + j*(16) -52 + j*(-146) --64 + j*(-15) -80 + j*(44) -100 + j*(-100) --12 + j*(-95) -40 + j*(-29) -87 + j*(-139) --32 + j*(-217) --127 + j*(-185) --219 + j*(-163) --351 + j*(-13) --260 + j*(244) -8 + j*(251) -52 + j*(61) --82 + j*(55) --55 + j*(198) -103 + j*(207) -172 + j*(102) -163 + j*(34) -175 + j*(-6) -187 + j*(-92) -112 + j*(-191) --13 + j*(-187) --48 + j*(-117) --37 + j*(-129) --129 + j*(-146) --194 + j*(-21) --95 + j*(64) --56 + j*(-2) --133 + j*(26) --59 + j*(139) -74 + j*(41) --53 + j*(-100) --219 + j*(56) --78 + j*(266) -144 + j*(188) -136 + j*(12) -25 + j*(2) -35 + j*(95) -173 + j*(95) -249 + j*(-93) -69 + j*(-274) --174 + j*(-158) --117 + j*(83) -91 + j*(48) -60 + j*(-139) --109 + j*(-133) --146 + j*(-28) --153 + j*(18) --174 + j*(133) --21 + j*(262) -191 + j*(147) -131 + j*(-84) --91 + j*(-60) --91 + j*(168) -141 + j*(219) -254 + j*(37) -179 + j*(-83) -151 + j*(-97) -132 + j*(-204) --59 + j*(-262) --197 + j*(-70) --52 + j*(82) -57 + j*(-21) --24 + j*(-64) -4 + j*(2) -58 + j*(-95) --100 + j*(-137) --112 + j*(71) -148 + j*(45) -110 + j*(-274) --224 + j*(-282) --287 + j*(-44) --231 + j*(-8) --341 + j*(89) --217 + j*(372) -134 + j*(326) -149 + j*(50) -1 + j*(65) -110 + j*(130) -159 + j*(-41) --1 + j*(-98) --35 + j*(-6) --40 + j*(-34) --161 + j*(46) --49 + j*(272) -239 + j*(190) -215 + j*(-86) -18 + j*(-94) -22 + j*(13) -71 + j*(-9) -58 + j*(-19) -90 + j*(-33) -60 + j*(-100) --13 + j*(-57) -71 + j*(-2) -117 + j*(-132) --30 + j*(-194) --86 + j*(-75) --5 + j*(-81) -138 + j*(169) -171 + j*(-16) -31 + j*(-37) -76 + j*(78) -231 + j*(-36) -105 + j*(-274) --192 + j*(-209) --205 + j*(77) -11 + j*(123) -16 + j*(-23) --105 + j*(62) -64 + j*(218) -275 + j*(9) -74 + j*(-238) --168 + j*(-60) --8 + j*(139) -133 + j*(-11) --16 + j*(-84) --25 + j*(78) -161 + j*(52) -138 + j*(-136) --6 + j*(-127) -21 + j*(-45) -83 + j*(-111) -18 + j*(-208) --103 + j*(-223) --221 + j*(-151) --252 + j*(-1) --166 + j*(93) --98 + j*(93) --58 + j*(98) --4 + j*(57) --63 + j*(-6) --138 + j*(103) -16 + j*(211) -146 + j*(52) -10 + j*(-53) --27 + j*(73) -110 + j*(28) --1 + j*(-129) --175 + j*(21) --14 + j*(196) -130 + j*(52) -11 + j*(-21) -27 + j*(103) -193 + j*(16) -107 + j*(-202) --131 + j*(-188) --225 + j*(0) --151 + j*(190) -72 + j*(253) -236 + j*(65) -118 + j*(-120) -0 + j*(-57) -58 + j*(-48) --39 + j*(-142) --183 + j*(23) -5 + j*(203) -180 + j*(36) -63 + j*(-68) -97 + j*(18) -214 + j*(-175) --72 + j*(-381) --351 + j*(-119) --185 + j*(129) --79 + j*(41) --179 + j*(95) --40 + j*(252) -127 + j*(124) -24 + j*(40) -58 + j*(175) -269 + j*(78) -195 + j*(-171) -1 + j*(-156) --3 + j*(-79) --44 + j*(-112) --129 + j*(-7) --21 + j*(110) -84 + j*(32) -48 + j*(-4) -119 + j*(15) -174 + j*(-157) --36 + j*(-284) --210 + j*(-117) --117 + j*(38) --27 + j*(-5) --57 + j*(-45) --81 + j*(-31) --107 + j*(-19) --129 + j*(36) --92 + j*(88) --56 + j*(98) --28 + j*(129) -60 + j*(140) -129 + j*(58) -108 + j*(-37) -47 + j*(-77) --11 + j*(-66) --13 + j*(-17) -44 + j*(-52) --26 + j*(-168) --223 + j*(-115) --238 + j*(111) --64 + j*(192) -21 + j*(105) --16 + j*(61) --45 + j*(96) --6 + j*(173) -145 + j*(181) -225 + j*(-13) -28 + j*(-133) --81 + j*(72) -163 + j*(156) -250 + j*(-125) --13 + j*(-226) --88 + j*(-43) -2 + j*(-64) --158 + j*(-110) --231 + j*(163) -66 + j*(300) -243 + j*(77) -145 + j*(-66) -91 + j*(-82) --3 + j*(-118) --97 + j*(46) -150 + j*(188) -357 + j*(-127) -28 + j*(-403) --263 + j*(-116) --34 + j*(139) -162 + j*(-49) -13 + j*(-190) --71 + j*(-94) --10 + j*(-69) --17 + j*(-113) --30 + j*(-117) --39 + j*(-168) --137 + j*(-205) --234 + j*(-144) --278 + j*(-71) --324 + j*(36) --268 + j*(194) --107 + j*(233) --40 + j*(147) --77 + j*(115) --82 + j*(144) --68 + j*(184) -1 + j*(250) -151 + j*(223) -182 + j*(59) -47 + j*(4) -1 + j*(134) -144 + j*(217) -321 + j*(108) -336 + j*(-132) -124 + j*(-289) --108 + j*(-170) --71 + j*(62) -132 + j*(80) -207 + j*(-77) -137 + j*(-212) --21 + j*(-270) --189 + j*(-154) --143 + j*(55) -40 + j*(48) -29 + j*(-76) --23 + j*(-30) -86 + j*(-61) --16 + j*(-259) --301 + j*(-136) --191 + j*(176) -76 + j*(64) --82 + j*(-138) --248 + j*(69) --47 + j*(208) -20 + j*(65) --73 + j*(123) -99 + j*(208) -180 + j*(-16) --52 + j*(-37) -25 + j*(211) -308 + j*(54) -112 + j*(-242) --138 + j*(-21) -132 + j*(167) -282 + j*(-146) --18 + j*(-290) --132 + j*(-64) --1 + j*(-25) --52 + j*(-86) --66 + j*(31) -93 + j*(6) -41 + j*(-172) --129 + j*(-120) --83 + j*(-8) --58 + j*(-74) --164 + j*(-30) --86 + j*(102) -34 + j*(-6) --129 + j*(-104) --228 + j*(110) --2 + j*(228) -122 + j*(19) --69 + j*(-95) --194 + j*(75) --91 + j*(233) -55 + j*(252) -185 + j*(220) -327 + j*(85) -330 + j*(-186) -59 + j*(-378) --275 + j*(-226) --273 + j*(152) -69 + j*(266) -235 + j*(-11) -22 + j*(-172) --91 + j*(0) -83 + j*(44) -72 + j*(-172) --193 + j*(-160) --221 + j*(110) --21 + j*(165) --10 + j*(71) --45 + j*(179) -176 + j*(250) -351 + j*(4) -187 + j*(-248) --58 + j*(-215) --134 + j*(-49) --70 + j*(90) -96 + j*(116) -197 + j*(-52) -59 + j*(-202) --98 + j*(-122) --70 + j*(-14) --54 + j*(-15) --69 + j*(80) -129 + j*(153) -303 + j*(-96) -85 + j*(-378) --241 + j*(-274) --278 + j*(-6) --146 + j*(123) -7 + j*(137) -139 + j*(-3) -30 + j*(-230) --274 + j*(-177) --313 + j*(152) --42 + j*(278) -115 + j*(126) -76 + j*(6) -21 + j*(-25) --47 + j*(-20) --79 + j*(77) -37 + j*(151) -155 + j*(52) -115 + j*(-82) -19 + j*(-114) --53 + j*(-88) --88 + j*(-23) --47 + j*(28) --21 + j*(-10) --91 + j*(-20) --108 + j*(88) -8 + j*(125) -48 + j*(22) --56 + j*(-13) --115 + j*(101) --33 + j*(222) -136 + j*(245) -288 + j*(110) -260 + j*(-110) -67 + j*(-175) --20 + j*(-52) -64 + j*(-1) -83 + j*(-84) --3 + j*(-98) --11 + j*(-27) -53 + j*(-38) -29 + j*(-122) --88 + j*(-127) --158 + j*(-10) --103 + j*(127) -46 + j*(177) -194 + j*(92) -219 + j*(-91) -73 + j*(-203) --47 + j*(-112) -50 + j*(-37) -113 + j*(-226) --173 + j*(-369) --459 + j*(-75) --267 + j*(309) -103 + j*(266) -158 + j*(7) -39 + j*(-69) --4 + j*(-54) --42 + j*(-57) --64 + j*(-7) --15 + j*(-8) --68 + j*(-75) --190 + j*(26) --75 + j*(214) -159 + j*(127) -119 + j*(-120) --113 + j*(-125) --154 + j*(73) --1 + j*(133) -53 + j*(23) --35 + j*(-5) --37 + j*(91) -76 + j*(78) -54 + j*(-48) --77 + j*(-11) --22 + j*(120) -104 + j*(47) -5 + j*(-65) --92 + j*(55) -28 + j*(141) -81 + j*(59) -44 + j*(87) -179 + j*(117) -244 + j*(-84) -56 + j*(-171) -18 + j*(-42) -110 + j*(-112) --64 + j*(-203) --151 + j*(35) -129 + j*(78) -115 + j*(-264) --286 + j*(-228) --276 + j*(174) -35 + j*(175) --31 + j*(3) --115 + j*(204) -204 + j*(310) -392 + j*(-6) -218 + j*(-228) -87 + j*(-224) -16 + j*(-268) --153 + j*(-245) --214 + j*(-83) --144 + j*(-13) --146 + j*(-17) --177 + j*(42) --155 + j*(139) --41 + j*(238) -184 + j*(183) -202 + j*(-103) --98 + j*(-148) --96 + j*(172) -290 + j*(103) -187 + j*(-378) --361 + j*(-303) --335 + j*(233) -112 + j*(228) -70 + j*(-117) --220 + j*(-16) --105 + j*(269) -175 + j*(218) -240 + j*(-1) -139 + j*(-170) --76 + j*(-202) --206 + j*(-1) --41 + j*(163) -97 + j*(21) --49 + j*(-71) --110 + j*(96) -61 + j*(147) -104 + j*(8) -9 + j*(-8) -31 + j*(57) -87 + j*(23) -74 + j*(-18) -83 + j*(-41) -50 + j*(-121) --93 + j*(-125) --170 + j*(37) --49 + j*(194) -160 + j*(169) -248 + j*(-33) -101 + j*(-201) --77 + j*(-106) -16 + j*(42) -153 + j*(-100) --37 + j*(-273) --260 + j*(-90) --132 + j*(139) -43 + j*(68) --6 + j*(-21) --18 + j*(41) -70 + j*(1) --1 + j*(-109) --128 + j*(-21) --35 + j*(126) -136 + j*(49) -116 + j*(-148) --77 + j*(-223) --245 + j*(-94) --228 + j*(111) --66 + j*(186) -25 + j*(107) --4 + j*(63) --1 + j*(93) -39 + j*(82) -38 + j*(65) -63 + j*(76) -94 + j*(30) -45 + j*(6) -70 + j*(89) -226 + j*(30) -187 + j*(-206) --70 + j*(-217) --106 + j*(1) -54 + j*(12) -25 + j*(-103) --43 + j*(-42) -50 + j*(-44) --26 + j*(-195) --242 + j*(-65) --86 + j*(187) -168 + j*(5) --59 + j*(-237) --286 + j*(36) -18 + j*(249) -221 + j*(-82) --111 + j*(-298) --361 + j*(-28) --236 + j*(218) --90 + j*(258) -46 + j*(279) -197 + j*(146) -99 + j*(-45) --68 + j*(61) -70 + j*(210) -206 + j*(71) -90 + j*(-3) -121 + j*(132) -343 + j*(42) -306 + j*(-258) -44 + j*(-334) --93 + j*(-221) --117 + j*(-137) --129 + j*(-74) --117 + j*(-31) --138 + j*(6) --113 + j*(123) -61 + j*(161) -150 + j*(2) -51 + j*(-83) -28 + j*(-44) -50 + j*(-108) --72 + j*(-148) --126 + j*(-25) --35 + j*(-13) --116 + j*(-93) --243 + j*(79) --44 + j*(286) -213 + j*(133) -146 + j*(-103) --11 + j*(-98) --22 + j*(-30) --7 + j*(-33) --11 + j*(-42) --28 + j*(-73) --112 + j*(-69) --141 + j*(33) --66 + j*(71) --74 + j*(28) --130 + j*(108) --23 + j*(220) -121 + j*(146) -100 + j*(47) -80 + j*(74) -177 + j*(49) -192 + j*(-122) -4 + j*(-225) --177 + j*(-88) --115 + j*(122) -74 + j*(116) -81 + j*(-32) --33 + j*(-11) -33 + j*(89) -124 + j*(-4) -15 + j*(-59) -33 + j*(91) -272 + j*(5) -190 + j*(-344) --204 + j*(-337) --279 + j*(-7) --79 + j*(77) --61 + j*(-11) --98 + j*(45) --18 + j*(73) --5 + j*(12) --30 + j*(23) --7 + j*(-3) --117 + j*(-27) --175 + j*(190) -113 + j*(332) -339 + j*(58) -153 + j*(-180) --6 + j*(-69) -95 + j*(-9) -112 + j*(-137) -5 + j*(-180) --50 + j*(-175) --165 + j*(-189) --298 + j*(-45) --235 + j*(155) --98 + j*(201) --30 + j*(216) -103 + j*(233) -236 + j*(89) -165 + j*(-84) -43 + j*(-76) -48 + j*(-39) -39 + j*(-93) --65 + j*(-92) --103 + j*(33) -16 + j*(115) -131 + j*(11) -40 + j*(-123) --109 + j*(-20) -25 + j*(151) -238 + j*(-4) -93 + j*(-249) --129 + j*(-137) --25 + j*(4) -26 + j*(-148) --188 + j*(-151) --175 + j*(78) -18 + j*(22) --127 + j*(-142) --316 + j*(84) --95 + j*(322) -147 + j*(190) -126 + j*(31) -100 + j*(-28) -6 + j*(-132) --205 + j*(-31) --122 + j*(247) -168 + j*(197) -136 + j*(-45) --29 + j*(11) -76 + j*(120) -163 + j*(-8) -53 + j*(-73) -34 + j*(-1) -80 + j*(-33) -23 + j*(-58) -38 + j*(-1) -97 + j*(-74) --21 + j*(-153) --113 + j*(-23) --6 + j*(59) -35 + j*(-18) --14 + j*(3) -79 + j*(45) -146 + j*(-105) --11 + j*(-223) --163 + j*(-120) --147 + j*(15) --73 + j*(63) --5 + j*(44) --18 + j*(-26) --122 + j*(21) --46 + j*(200) -216 + j*(142) -220 + j*(-159) --49 + j*(-223) --127 + j*(-42) --32 + j*(-11) --76 + j*(-63) --124 + j*(33) --28 + j*(82) --2 + j*(9) --49 + j*(31) -21 + j*(60) -26 + j*(-55) --136 + j*(-30) --95 + j*(194) -192 + j*(163) -202 + j*(-169) --139 + j*(-247) --292 + j*(45) --106 + j*(243) -64 + j*(181) -78 + j*(105) -98 + j*(102) -156 + j*(51) -143 + j*(-47) -60 + j*(-82) -14 + j*(-37) -42 + j*(-9) -54 + j*(-51) --11 + j*(-55) --8 + j*(37) -132 + j*(31) -141 + j*(-167) --99 + j*(-227) --214 + j*(21) -16 + j*(170) -176 + j*(-35) -1 + j*(-192) --143 + j*(-53) --38 + j*(50) -16 + j*(-36) --76 + j*(-49) --75 + j*(47) -4 + j*(50) -15 + j*(9) -35 + j*(7) -62 + j*(-85) --89 + j*(-181) --284 + j*(-24) --200 + j*(250) -75 + j*(296) -235 + j*(119) -209 + j*(-78) -54 + j*(-180) --109 + j*(-104) --86 + j*(60) -50 + j*(40) --7 + j*(-86) --163 + j*(18) --50 + j*(236) -219 + j*(178) -261 + j*(-81) -93 + j*(-204) --46 + j*(-151) --62 + j*(-53) -9 + j*(-37) --6 + j*(-150) --204 + j*(-142) --251 + j*(129) -44 + j*(235) -179 + j*(-49) --92 + j*(-185) --224 + j*(63) --23 + j*(180) -44 + j*(37) --61 + j*(49) -11 + j*(160) -138 + j*(74) -73 + j*(-49) --30 + j*(-4) --8 + j*(94) -106 + j*(132) -247 + j*(18) -187 + j*(-228) --112 + j*(-264) --233 + j*(19) --22 + j*(182) -129 + j*(60) -98 + j*(-37) -78 + j*(-68) -28 + j*(-122) --53 + j*(-83) --20 + j*(-33) --34 + j*(-88) --128 + j*(-16) --5 + j*(105) -121 + j*(-70) --107 + j*(-190) --213 + j*(73) -61 + j*(124) -12 + j*(-165) --330 + j*(-8) --106 + j*(413) -366 + j*(186) -166 + j*(-272) --235 + j*(-93) --61 + j*(252) -247 + j*(101) -165 + j*(-173) --52 + j*(-185) --144 + j*(-51) --87 + j*(78) -44 + j*(53) --8 + j*(-77) --158 + j*(33) --1 + j*(223) -214 + j*(47) -35 + j*(-146) --105 + j*(49) -132 + j*(135) -194 + j*(-134) --62 + j*(-203) --132 + j*(-12) --42 + j*(33) --53 + j*(45) -37 + j*(127) -180 + j*(4) -67 + j*(-156) --43 + j*(-66) -58 + j*(-57) --21 + j*(-222) --253 + j*(-117) --170 + j*(121) -4 + j*(33) --148 + j*(-78) --264 + j*(141) --60 + j*(298) -76 + j*(199) -69 + j*(198) -254 + j*(226) -409 + j*(-74) -118 + j*(-368) --250 + j*(-156) --117 + j*(216) -229 + j*(144) -211 + j*(-153) -4 + j*(-170) -17 + j*(-78) -25 + j*(-194) --210 + j*(-213) --315 + j*(76) --71 + j*(266) -132 + j*(136) -108 + j*(-1) -71 + j*(-26) -48 + j*(-62) --4 + j*(-49) -31 + j*(-17) -52 + j*(-103) --76 + j*(-139) --118 + j*(-13) --18 + j*(-8) --95 + j*(-107) --242 + j*(40) --76 + j*(244) -146 + j*(102) -25 + j*(-105) --175 + j*(8) --96 + j*(219) -109 + j*(235) -243 + j*(102) -238 + j*(-103) -35 + j*(-230) --175 + j*(-71) --66 + j*(175) -197 + j*(110) -174 + j*(-141) --46 + j*(-141) --14 + j*(55) -214 + j*(-29) -127 + j*(-362) --308 + j*(-368) --463 + j*(72) --127 + j*(339) -137 + j*(142) -37 + j*(-33) --33 + j*(45) -71 + j*(40) -31 + j*(-100) --148 + j*(-56) --133 + j*(151) -80 + j*(188) -175 + j*(-13) --8 + j*(-161) --218 + j*(16) --62 + j*(306) -307 + j*(204) -282 + j*(-192) --77 + j*(-222) --102 + j*(70) -148 + j*(46) -76 + j*(-195) --163 + j*(-113) --102 + j*(98) -49 + j*(60) -26 + j*(-11) -32 + j*(3) -41 + j*(-80) --122 + j*(-91) --158 + j*(142) -111 + j*(235) -263 + j*(-9) -100 + j*(-180) --24 + j*(-112) --10 + j*(-76) --56 + j*(-92) --91 + j*(-4) -8 + j*(40) -39 + j*(-65) --73 + j*(-80) --68 + j*(33) -44 + j*(-6) --33 + j*(-130) --175 + j*(-30) --64 + j*(118) -66 + j*(-15) --110 + j*(-141) --264 + j*(64) --81 + j*(255) -96 + j*(142) -45 + j*(30) -16 + j*(57) -28 + j*(26) --52 + j*(40) --20 + j*(188) -189 + j*(180) -245 + j*(-30) -107 + j*(-127) -26 + j*(-82) -10 + j*(-51) -16 + j*(-8) -87 + j*(-27) -52 + j*(-146) --113 + j*(-113) --96 + j*(65) -66 + j*(48) -40 + j*(-81) --51 + j*(-44) --7 + j*(-4) --27 + j*(-67) --122 + j*(-4) --56 + j*(119) -57 + j*(86) -60 + j*(37) -102 + j*(34) -138 + j*(-71) -28 + j*(-156) --66 + j*(-100) --81 + j*(-52) --119 + j*(24) --2 + j*(164) -234 + j*(32) -120 + j*(-280) --211 + j*(-208) --163 + j*(80) -48 + j*(6) --82 + j*(-158) --237 + j*(8) --83 + j*(151) -16 + j*(23) --105 + j*(-33) --162 + j*(88) --88 + j*(173) --7 + j*(180) -49 + j*(146) -41 + j*(116) -52 + j*(172) -192 + j*(187) -280 + j*(25) -190 + j*(-87) -165 + j*(-76) -192 + j*(-189) -2 + j*(-319) --212 + j*(-167) --150 + j*(40) --28 + j*(29) --51 + j*(-14) --64 + j*(33) --37 + j*(63) --5 + j*(105) -121 + j*(116) -203 + j*(-59) -33 + j*(-202) --124 + j*(-63) --6 + j*(66) -93 + j*(-57) --46 + j*(-152) --161 + j*(-16) --57 + j*(126) -104 + j*(80) -132 + j*(-82) -4 + j*(-183) --140 + j*(-127) --165 + j*(3) --103 + j*(65) --59 + j*(71) --27 + j*(72) --1 + j*(49) --18 + j*(29) --30 + j*(56) --1 + j*(76) -23 + j*(69) -44 + j*(73) -88 + j*(52) -102 + j*(-11) -66 + j*(-52) -34 + j*(-64) --6 + j*(-72) --51 + j*(-47) --64 + j*(-3) --70 + j*(43) --40 + j*(127) -103 + j*(165) -236 + j*(36) -203 + j*(-141) -91 + j*(-225) --43 + j*(-272) --245 + j*(-207) --314 + j*(58) --100 + j*(226) -71 + j*(105) -6 + j*(12) -8 + j*(86) -137 + j*(24) -72 + j*(-169) --155 + j*(-161) --243 + j*(38) --152 + j*(206) -35 + j*(274) -239 + j*(147) -209 + j*(-130) --77 + j*(-184) --187 + j*(78) -30 + j*(220) -177 + j*(68) -86 + j*(-40) -37 + j*(33) -138 + j*(57) -199 + j*(-63) -119 + j*(-182) --6 + j*(-187) --65 + j*(-117) --58 + j*(-79) --84 + j*(-76) --130 + j*(1) --47 + j*(105) -95 + j*(50) -74 + j*(-98) --52 + j*(-102) --61 + j*(-11) -1 + j*(-19) --22 + j*(-62) --42 + j*(-39) --13 + j*(-65) --95 + j*(-143) --254 + j*(-52) --218 + j*(170) --1 + j*(207) -68 + j*(42) --62 + j*(-22) --127 + j*(99) --28 + j*(198) -100 + j*(168) -161 + j*(67) -137 + j*(-53) -23 + j*(-115) --88 + j*(-56) --102 + j*(47) --71 + j*(115) --13 + j*(189) -136 + j*(218) -274 + j*(76) -213 + j*(-101) -94 + j*(-103) -122 + j*(-74) -119 + j*(-194) --63 + j*(-236) --153 + j*(-74) --51 + j*(-9) --75 + j*(-94) --219 + j*(11) --104 + j*(242) -171 + j*(182) -173 + j*(-53) -30 + j*(-60) -84 + j*(1) -123 + j*(-148) --86 + j*(-216) --199 + j*(-1) --18 + j*(121) -79 + j*(-26) --52 + j*(-82) --74 + j*(56) -83 + j*(62) -101 + j*(-119) --90 + j*(-180) --211 + j*(-8) --95 + j*(165) -104 + j*(121) -125 + j*(-66) --21 + j*(-136) --109 + j*(-46) --74 + j*(21) --54 + j*(21) --50 + j*(49) -8 + j*(59) -33 + j*(-11) --33 + j*(-55) --105 + j*(-14) --122 + j*(79) --34 + j*(183) -147 + j*(138) -163 + j*(-91) --69 + j*(-154) --146 + j*(50) -21 + j*(95) --13 + j*(-51) --182 + j*(74) --1 + j*(296) -258 + j*(112) -97 + j*(-134) --93 + j*(26) -86 + j*(161) -185 + j*(-30) -3 + j*(-100) --35 + j*(62) -97 + j*(78) -108 + j*(9) -132 + j*(20) -209 + j*(-88) -66 + j*(-243) --126 + j*(-114) --15 + j*(74) -154 + j*(-27) -83 + j*(-182) --23 + j*(-168) --54 + j*(-163) --157 + j*(-145) --198 + j*(7) --65 + j*(86) --8 + j*(4) --59 + j*(11) -16 + j*(64) -93 + j*(-59) --44 + j*(-173) --175 + j*(-67) --128 + j*(35) --103 + j*(34) --101 + j*(98) -22 + j*(112) -37 + j*(-44) --161 + j*(-40) --138 + j*(218) -171 + j*(208) -193 + j*(-130) --136 + j*(-187) --226 + j*(96) --24 + j*(198) -43 + j*(97) -25 + j*(105) -112 + j*(83) -74 + j*(-59) --106 + j*(-1) --40 + j*(228) -238 + j*(198) -291 + j*(-81) -85 + j*(-223) --102 + j*(-134) --134 + j*(42) --7 + j*(164) -153 + j*(119) -189 + j*(-5) -176 + j*(-74) -160 + j*(-194) --38 + j*(-299) --253 + j*(-97) --90 + j*(166) -163 + j*(25) -18 + j*(-195) --168 + j*(-37) -6 + j*(115) -129 + j*(-74) --57 + j*(-192) --192 + j*(-52) --152 + j*(83) --61 + j*(173) -138 + j*(174) -239 + j*(-86) --32 + j*(-259) --235 + j*(6) -30 + j*(211) -244 + j*(-52) -16 + j*(-287) --218 + j*(-146) --188 + j*(21) --148 + j*(50) --149 + j*(127) --40 + j*(220) -122 + j*(177) -188 + j*(19) -91 + j*(-129) --91 + j*(-100) --105 + j*(88) -85 + j*(121) -137 + j*(-74) --48 + j*(-150) --143 + j*(8) --28 + j*(99) -43 + j*(16) --33 + j*(-38) --91 + j*(52) -11 + j*(128) -108 + j*(16) --25 + j*(-107) --197 + j*(54) --35 + j*(287) -231 + j*(175) -180 + j*(-54) -37 + j*(-19) -104 + j*(53) -146 + j*(-32) -103 + j*(-37) -197 + j*(-47) -201 + j*(-274) --88 + j*(-373) --273 + j*(-151) --202 + j*(18) --151 + j*(68) --64 + j*(161) -115 + j*(89) -55 + j*(-106) --114 + j*(-28) -2 + j*(107) -102 + j*(-45) --75 + j*(-107) --86 + j*(72) -73 + j*(25) --35 + j*(-103) --129 + j*(71) -110 + j*(129) -143 + j*(-177) --216 + j*(-223) --318 + j*(144) --21 + j*(317) -190 + j*(157) -169 + j*(-28) -50 + j*(-92) --35 + j*(-16) -55 + j*(55) -124 + j*(-91) --76 + j*(-184) --195 + j*(43) -23 + j*(168) -127 + j*(-21) --24 + j*(-86) --48 + j*(16) --13 + j*(1) --77 + j*(50) -61 + j*(185) -277 + j*(-13) -76 + j*(-301) --230 + j*(-147) --134 + j*(109) -17 + j*(51) --36 + j*(18) -34 + j*(83) -119 + j*(-69) --88 + j*(-181) --231 + j*(35) --56 + j*(187) -56 + j*(81) -0 + j*(47) -33 + j*(84) -54 + j*(20) --30 + j*(49) -67 + j*(183) -291 + j*(59) -209 + j*(-247) --123 + j*(-255) --218 + j*(47) -18 + j*(204) -210 + j*(45) -127 + j*(-150) --28 + j*(-127) --19 + j*(-28) -41 + j*(-64) --23 + j*(-112) --67 + j*(-49) --11 + j*(-40) --58 + j*(-117) --178 + j*(-32) --90 + j*(123) -77 + j*(41) --18 + j*(-128) --199 + j*(-32) --130 + j*(159) -25 + j*(129) -2 + j*(50) --11 + j*(135) -169 + j*(147) -255 + j*(-99) -20 + j*(-288) --238 + j*(-140) --201 + j*(104) --42 + j*(139) --18 + j*(82) --24 + j*(129) -86 + j*(163) -189 + j*(54) -141 + j*(-90) -16 + j*(-121) --60 + j*(-47) --37 + j*(35) -34 + j*(42) -54 + j*(-21) -1 + j*(-56) --64 + j*(-23) --86 + j*(66) --4 + j*(176) -185 + j*(168) -293 + j*(-25) -189 + j*(-211) -37 + j*(-234) --41 + j*(-211) --153 + j*(-193) --257 + j*(-36) --156 + j*(163) -59 + j*(153) -124 + j*(-12) -31 + j*(-100) --38 + j*(-74) --36 + j*(-50) --52 + j*(-71) --115 + j*(-49) --112 + j*(33) --35 + j*(22) --97 + j*(-69) --265 + j*(47) --158 + j*(327) -183 + j*(303) -255 + j*(-6) -49 + j*(-117) --35 + j*(-29) --37 + j*(-11) --100 + j*(52) --19 + j*(184) -144 + j*(127) -116 + j*(0) -74 + j*(40) -171 + j*(14) -134 + j*(-144) --31 + j*(-127) --19 + j*(-9) -37 + j*(-53) --46 + j*(-69) --46 + j*(33) -40 + j*(25) -20 + j*(-9) -61 + j*(40) -169 + j*(-71) -25 + j*(-241) --170 + j*(-106) --41 + j*(49) -47 + j*(-108) --164 + j*(-161) --221 + j*(74) --23 + j*(134) -0 + j*(1) --84 + j*(45) -12 + j*(110) -64 + j*(-10) --69 + j*(-43) --93 + j*(108) -71 + j*(156) -163 + j*(8) -57 + j*(-125) --102 + j*(-61) --56 + j*(121) -161 + j*(79) -127 + j*(-186) --178 + j*(-166) --173 + j*(155) -146 + j*(148) -126 + j*(-161) --166 + j*(-127) --125 + j*(134) -91 + j*(84) -23 + j*(-89) --124 + j*(-6) --51 + j*(129) -67 + j*(97) -84 + j*(18) -59 + j*(-33) -6 + j*(-53) --37 + j*(-18) --30 + j*(18) --25 + j*(32) --8 + j*(62) -33 + j*(58) -24 + j*(46) -67 + j*(115) -241 + j*(51) -215 + j*(-228) --107 + j*(-264) --177 + j*(41) -102 + j*(90) -109 + j*(-188) --174 + j*(-182) --178 + j*(73) -10 + j*(71) --40 + j*(-48) --136 + j*(58) --13 + j*(171) -109 + j*(90) -91 + j*(7) -77 + j*(-2) -96 + j*(-32) -83 + j*(-88) -29 + j*(-134) --59 + j*(-119) --66 + j*(-29) -28 + j*(-53) --49 + j*(-205) --292 + j*(-125) --271 + j*(165) --31 + j*(194) --34 + j*(57) --119 + j*(175) -101 + j*(296) -293 + j*(71) -163 + j*(-140) -30 + j*(-122) --22 + j*(-136) --182 + j*(-74) --144 + j*(190) -173 + j*(177) -170 + j*(-153) --148 + j*(-142) --109 + j*(144) -128 + j*(57) --21 + j*(-135) --193 + j*(74) -42 + j*(246) -203 + j*(37) -45 + j*(-69) -21 + j*(54) -144 + j*(16) -93 + j*(-97) -38 + j*(-51) -118 + j*(-80) -45 + j*(-235) --166 + j*(-204) --220 + j*(-24) --149 + j*(75) --78 + j*(117) -16 + j*(105) -23 + j*(11) --76 + j*(37) --7 + j*(185) -194 + j*(125) -190 + j*(-84) -45 + j*(-119) -28 + j*(-83) --14 + j*(-139) --162 + j*(-71) --115 + j*(148) -133 + j*(147) -187 + j*(-83) -16 + j*(-179) --76 + j*(-82) --33 + j*(-36) --30 + j*(-78) --91 + j*(-79) --127 + j*(-24) --125 + j*(30) --112 + j*(84) --52 + j*(161) -103 + j*(162) -213 + j*(-22) -71 + j*(-232) --186 + j*(-186) --230 + j*(35) --110 + j*(97) --126 + j*(50) --202 + j*(181) --38 + j*(369) -234 + j*(290) -279 + j*(59) -192 + j*(-30) -180 + j*(-76) -80 + j*(-197) --156 + j*(-118) --127 + j*(197) -230 + j*(240) -357 + j*(-110) -89 + j*(-301) --90 + j*(-158) --49 + j*(-65) --64 + j*(-64) --56 + j*(29) -84 + j*(9) -41 + j*(-170) --170 + j*(-97) --65 + j*(140) -202 + j*(-10) -26 + j*(-335) --357 + j*(-192) --310 + j*(196) --2 + j*(245) -78 + j*(64) -8 + j*(8) --12 + j*(19) --44 + j*(29) --33 + j*(104) -85 + j*(107) -105 + j*(-25) --24 + j*(-45) --27 + j*(93) -144 + j*(96) -188 + j*(-94) -28 + j*(-198) --100 + j*(-114) --93 + j*(-23) --74 + j*(-4) --90 + j*(39) --28 + j*(117) -111 + j*(85) -137 + j*(-92) --47 + j*(-187) --205 + j*(-25) --78 + j*(178) -155 + j*(92) -112 + j*(-166) --160 + j*(-181) --235 + j*(68) --44 + j*(175) -44 + j*(33) --103 + j*(-21) --174 + j*(165) -8 + j*(320) -242 + j*(232) -292 + j*(9) -166 + j*(-132) -25 + j*(-111) --6 + j*(-17) -49 + j*(25) -98 + j*(0) -110 + j*(-52) -78 + j*(-95) -43 + j*(-95) -57 + j*(-105) -17 + j*(-192) --161 + j*(-177) --211 + j*(55) -24 + j*(159) -147 + j*(-49) --27 + j*(-159) --86 + j*(-21) -30 + j*(-39) --74 + j*(-160) --217 + j*(10) -6 + j*(170) -178 + j*(-110) --146 + j*(-326) --436 + j*(-13) --206 + j*(317) -84 + j*(190) --2 + j*(-10) --135 + j*(107) -26 + j*(238) -175 + j*(51) --33 + j*(-112) --230 + j*(151) -72 + j*(428) -441 + j*(163) -285 + j*(-211) -31 + j*(-141) -122 + j*(-71) -59 + j*(-276) --257 + j*(-174) --159 + j*(170) -137 + j*(47) --65 + j*(-188) --270 + j*(93) -35 + j*(292) -190 + j*(24) --17 + j*(-28) -60 + j*(139) -204 + j*(-42) --46 + j*(-151) --100 + j*(155) -249 + j*(170) -259 + j*(-165) -19 + j*(-155) -119 + j*(-50) -136 + j*(-286) --193 + j*(-291) --197 + j*(45) -93 + j*(-6) --42 + j*(-261) --276 + j*(-72) --58 + j*(115) -63 + j*(-158) --290 + j*(-265) --474 + j*(115) --182 + j*(390) -96 + j*(258) -81 + j*(59) --41 + j*(51) --43 + j*(172) -125 + j*(212) -248 + j*(37) -133 + j*(-148) --28 + j*(-124) --58 + j*(-66) --134 + j*(-73) --265 + j*(95) --115 + j*(383) -272 + j*(359) -402 + j*(-1) -164 + j*(-211) --20 + j*(-98) -35 + j*(7) -76 + j*(-46) -15 + j*(-50) -42 + j*(10) -103 + j*(-47) -29 + j*(-105) -1 + j*(-14) -133 + j*(-28) -109 + j*(-211) --85 + j*(-211) --73 + j*(-80) --12 + j*(-185) --257 + j*(-252) --415 + j*(74) --114 + j*(316) -127 + j*(92) --46 + j*(-83) --161 + j*(90) -21 + j*(185) -119 + j*(18) --19 + j*(-86) --134 + j*(21) --71 + j*(149) -52 + j*(132) -54 + j*(53) -23 + j*(91) -148 + j*(122) -232 + j*(-80) -6 + j*(-236) --189 + j*(-35) --30 + j*(151) -110 + j*(29) -18 + j*(-44) -18 + j*(25) -71 + j*(-54) --92 + j*(-98) --150 + j*(140) -132 + j*(248) -313 + j*(-16) -139 + j*(-256) --113 + j*(-218) --223 + j*(-1) --79 + j*(244) -271 + j*(206) -365 + j*(-177) -55 + j*(-370) --127 + j*(-204) --74 + j*(-156) --203 + j*(-210) --339 + j*(19) --121 + j*(228) -83 + j*(73) --7 + j*(-76) --74 + j*(-42) --105 + j*(-87) --296 + j*(-25) --277 + j*(303) -100 + j*(375) -226 + j*(42) --40 + j*(-61) --86 + j*(187) -175 + j*(223) -258 + j*(-19) -107 + j*(-147) --11 + j*(-129) --97 + j*(-93) --180 + j*(18) --139 + j*(190) -23 + j*(274) -184 + j*(236) -315 + j*(129) -383 + j*(-73) -267 + j*(-321) --45 + j*(-396) --294 + j*(-148) --168 + j*(194) -203 + j*(185) -301 + j*(-173) --1 + j*(-367) --240 + j*(-165) --136 + j*(38) -1 + j*(-26) --81 + j*(-139) --235 + j*(-66) --253 + j*(145) --54 + j*(307) -235 + j*(204) -265 + j*(-140) --65 + j*(-286) --284 + j*(-6) --80 + j*(246) -168 + j*(127) -129 + j*(-69) -18 + j*(-79) -10 + j*(-55) --6 + j*(-84) --62 + j*(-88) --127 + j*(-64) --195 + j*(52) --80 + j*(241) -212 + j*(180) -235 + j*(-160) --88 + j*(-255) --211 + j*(1) --27 + j*(86) --21 + j*(-64) --187 + j*(-4) --112 + j*(192) -86 + j*(136) -46 + j*(-40) --119 + j*(-14) --132 + j*(142) --19 + j*(224) -86 + j*(201) -132 + j*(159) -184 + j*(144) -286 + j*(71) -287 + j*(-121) -101 + j*(-206) -8 + j*(-66) -159 + j*(-26) -183 + j*(-241) --70 + j*(-322) --205 + j*(-115) --80 + j*(1) --47 + j*(-96) --193 + j*(-70) --182 + j*(145) -61 + j*(205) -191 + j*(-12) -30 + j*(-181) --134 + j*(-75) --66 + j*(42) --21 + j*(-38) --177 + j*(-21) --162 + j*(250) -190 + j*(324) -389 + j*(-1) -202 + j*(-268) --9 + j*(-250) --85 + j*(-190) --165 + j*(-132) --175 + j*(-1) --69 + j*(38) --55 + j*(-35) --124 + j*(-18) --110 + j*(44) --94 + j*(37) --130 + j*(83) --62 + j*(179) -81 + j*(139) -98 + j*(-9) --30 + j*(-78) --156 + j*(11) --132 + j*(190) -69 + j*(250) -196 + j*(72) -58 + j*(-65) --54 + j*(53) -72 + j*(150) -165 + j*(21) -50 + j*(-70) --45 + j*(34) -35 + j*(168) -235 + j*(170) -391 + j*(-54) -242 + j*(-366) --132 + j*(-349) --209 + j*(-13) -61 + j*(66) -103 + j*(-178) --140 + j*(-204) --170 + j*(10) --18 + j*(20) --69 + j*(-89) --191 + j*(18) --77 + j*(186) -122 + j*(123) -134 + j*(-72) --21 + j*(-153) --157 + j*(-62) --147 + j*(90) --30 + j*(162) -78 + j*(128) -128 + j*(52) -129 + j*(-39) -54 + j*(-112) --57 + j*(-70) --37 + j*(69) -148 + j*(86) -257 + j*(-141) -59 + j*(-385) --279 + j*(-310) --349 + j*(4) --136 + j*(132) --54 + j*(-13) --226 + j*(-44) --296 + j*(187) --86 + j*(364) -149 + j*(270) -174 + j*(87) -90 + j*(40) -105 + j*(76) -181 + j*(-5) -86 + j*(-147) --91 + j*(-65) --9 + j*(110) -159 + j*(-8) --11 + j*(-176) --190 + j*(42) -68 + j*(233) -261 + j*(-37) -21 + j*(-206) --69 + j*(-16) -96 + j*(-71) --120 + j*(-277) --433 + j*(43) --113 + j*(453) -306 + j*(214) -134 + j*(-105) --35 + j*(83) -228 + j*(158) -294 + j*(-152) -21 + j*(-230) --8 + j*(-52) -100 + j*(-127) --74 + j*(-223) --178 + j*(4) -83 + j*(98) -169 + j*(-205) --161 + j*(-320) --317 + j*(-17) --81 + j*(132) -8 + j*(-56) --179 + j*(-90) --199 + j*(103) --43 + j*(113) --83 + j*(4) --197 + j*(112) --80 + j*(269) -73 + j*(223) -95 + j*(174) -190 + j*(176) -292 + j*(6) -148 + j*(-172) --16 + j*(-81) -67 + j*(17) -118 + j*(-107) --34 + j*(-157) --94 + j*(-16) -16 + j*(43) -71 + j*(-37) -34 + j*(-95) --16 + j*(-122) --96 + j*(-127) --170 + j*(-51) --168 + j*(58) --98 + j*(134) -1 + j*(136) -44 + j*(64) --2 + j*(47) -29 + j*(110) -141 + j*(53) -81 + j*(-95) --76 + j*(-31) -3 + j*(137) -197 + j*(63) -176 + j*(-136) -30 + j*(-194) --62 + j*(-160) --128 + j*(-101) --132 + j*(-6) --75 + j*(22) --81 + j*(8) --88 + j*(57) --30 + j*(64) --62 + j*(31) --95 + j*(136) -72 + j*(214) -193 + j*(50) -74 + j*(-64) -23 + j*(25) -122 + j*(24) -123 + j*(-87) -58 + j*(-127) -1 + j*(-174) --169 + j*(-155) --218 + j*(85) -28 + j*(179) -113 + j*(-44) --93 + j*(-81) --86 + j*(119) -101 + j*(91) -65 + j*(-50) -4 + j*(-4) -80 + j*(-27) --8 + j*(-143) --153 + j*(-26) --38 + j*(117) -76 + j*(17) --6 + j*(-52) --33 + j*(6) --18 + j*(-1) --59 + j*(51) -66 + j*(141) -221 + j*(-31) -57 + j*(-251) --185 + j*(-149) --173 + j*(52) --64 + j*(115) -47 + j*(105) -112 + j*(-37) --73 + j*(-145) --216 + j*(90) -59 + j*(261) -247 + j*(-18) --3 + j*(-190) --117 + j*(4) -4 + j*(30) --83 + j*(-12) --57 + j*(210) -305 + j*(148) -264 + j*(-318) --233 + j*(-344) --327 + j*(86) --46 + j*(213) -59 + j*(112) -123 + j*(61) -132 + j*(-136) --174 + j*(-194) --283 + j*(185) -114 + j*(347) -311 + j*(16) -122 + j*(-151) -63 + j*(-121) --25 + j*(-228) --282 + j*(-91) --136 + j*(250) -212 + j*(86) --5 + j*(-243) --327 + j*(39) --32 + j*(371) -282 + j*(131) -129 + j*(-94) -45 + j*(4) -151 + j*(-32) -63 + j*(-173) --78 + j*(-105) --53 + j*(-16) --42 + j*(-6) --19 + j*(64) -116 + j*(46) -123 + j*(-122) --24 + j*(-168) --87 + j*(-91) --96 + j*(-54) --105 + j*(11) --15 + j*(45) -6 + j*(-69) --151 + j*(-69) --148 + j*(140) -89 + j*(154) -129 + j*(-83) --83 + j*(-156) --197 + j*(5) --127 + j*(157) -31 + j*(202) -190 + j*(87) -156 + j*(-146) --85 + j*(-204) --216 + j*(-30) --155 + j*(107) --95 + j*(154) --13 + j*(214) -136 + j*(175) -153 + j*(21) -40 + j*(-1) -65 + j*(89) -175 + j*(22) -105 + j*(-119) --43 + j*(-61) -13 + j*(91) -191 + j*(42) -188 + j*(-163) -1 + j*(-242) --140 + j*(-134) --145 + j*(11) --46 + j*(112) -123 + j*(88) -182 + j*(-113) --4 + j*(-250) --164 + j*(-119) --84 + j*(-23) --111 + j*(-127) --332 + j*(-11) --223 + j*(346) -188 + j*(330) -250 + j*(-14) -39 + j*(-63) -91 + j*(49) -187 + j*(-119) --20 + j*(-245) --148 + j*(-88) --70 + j*(-34) --145 + j*(-76) --208 + j*(101) -6 + j*(201) -101 + j*(0) --80 + j*(-46) --74 + j*(122) -69 + j*(79) --21 + j*(-8) --45 + j*(161) -223 + j*(167) -260 + j*(-165) --73 + j*(-249) --171 + j*(35) -70 + j*(114) -132 + j*(-117) --102 + j*(-209) --268 + j*(-11) --166 + j*(224) -73 + j*(252) -189 + j*(76) -90 + j*(-40) -28 + j*(37) -148 + j*(68) -208 + j*(-92) -79 + j*(-209) --41 + j*(-173) --88 + j*(-124) --132 + j*(-63) --104 + j*(26) --31 + j*(5) --103 + j*(-40) --168 + j*(113) -37 + j*(241) -228 + j*(40) -66 + j*(-176) --133 + j*(-46) --21 + j*(117) -107 + j*(22) -41 + j*(-64) -28 + j*(-28) -63 + j*(-115) --113 + j*(-202) --288 + j*(13) --102 + j*(262) -165 + j*(146) -112 + j*(-84) --59 + j*(-62) --39 + j*(65) -69 + j*(44) -68 + j*(-50) --1 + j*(-81) --45 + j*(-60) --72 + j*(-40) --107 + j*(0) --97 + j*(94) -23 + j*(130) -104 + j*(6) --19 + j*(-107) --163 + j*(2) --98 + j*(163) -32 + j*(159) -57 + j*(105) -67 + j*(107) -103 + j*(98) -129 + j*(96) -221 + j*(78) -284 + j*(-74) -160 + j*(-206) -58 + j*(-151) -107 + j*(-152) -34 + j*(-272) --140 + j*(-206) --98 + j*(-59) --9 + j*(-129) --130 + j*(-213) --245 + j*(-123) --288 + j*(-35) --350 + j*(134) --155 + j*(395) -218 + j*(272) -158 + j*(-80) --105 + j*(11) -93 + j*(211) -281 + j*(-88) --50 + j*(-284) --209 + j*(13) -38 + j*(69) --41 + j*(-163) --296 + j*(27) --74 + j*(295) -156 + j*(88) --33 + j*(-39) --42 + j*(158) -167 + j*(74) -14 + j*(-136) --183 + j*(77) -65 + j*(263) -221 + j*(14) --19 + j*(-74) --25 + j*(204) -338 + j*(187) -400 + j*(-231) -31 + j*(-421) --223 + j*(-202) --164 + j*(-1) --90 + j*(11) --108 + j*(50) --28 + j*(141) -110 + j*(79) -81 + j*(-49) -1 + j*(-29) -44 + j*(-4) -22 + j*(-83) --86 + j*(-19) -19 + j*(105) -155 + j*(-39) --16 + j*(-174) --126 + j*(8) -58 + j*(71) -61 + j*(-107) --94 + j*(-41) -53 + j*(81) -152 + j*(-152) --134 + j*(-249) --212 + j*(27) -13 + j*(31) --108 + j*(-165) --331 + j*(65) --63 + j*(331) -197 + j*(100) -23 + j*(-91) --70 + j*(56) -72 + j*(66) -44 + j*(-62) --47 + j*(-30) --16 + j*(-4) --71 + j*(-36) --115 + j*(84) -42 + j*(141) -95 + j*(-24) --60 + j*(-59) --73 + j*(71) -12 + j*(56) --54 + j*(25) --49 + j*(161) -138 + j*(169) -171 + j*(-16) -31 + j*(-37) -76 + j*(78) -231 + j*(-36) -105 + j*(-274) --192 + j*(-209) --205 + j*(77) -11 + j*(123) -16 + j*(-23) --105 + j*(62) -64 + j*(218) -275 + j*(9) -74 + j*(-238) --168 + j*(-60) --8 + j*(139) -133 + j*(-11) --16 + j*(-84) --25 + j*(78) -161 + j*(52) -138 + j*(-136) --6 + j*(-127) -21 + j*(-45) -83 + j*(-111) -18 + j*(-208) --103 + j*(-223) --221 + j*(-151) --252 + j*(-1) --166 + j*(93) --98 + j*(93) --58 + j*(98) --4 + j*(57) --63 + j*(-6) --138 + j*(103) -16 + j*(211) -146 + j*(52) -10 + j*(-53) --27 + j*(73) -110 + j*(28) --1 + j*(-129) --175 + j*(21) --14 + j*(196) -130 + j*(52) -11 + j*(-21) -27 + j*(103) -193 + j*(16) -107 + j*(-202) --131 + j*(-188) --225 + j*(0) --151 + j*(190) -72 + j*(253) -236 + j*(65) -118 + j*(-120) -0 + j*(-57) -58 + j*(-48) --39 + j*(-142) --183 + j*(23) -5 + j*(203) -180 + j*(36) -63 + j*(-68) -97 + j*(18) -214 + j*(-175) --72 + j*(-381) --351 + j*(-119) --185 + j*(129) --79 + j*(41) --179 + j*(95) --40 + j*(252) -127 + j*(124) -24 + j*(40) -58 + j*(175) -269 + j*(78) -195 + j*(-171) -1 + j*(-156) --3 + j*(-79) --44 + j*(-112) --129 + j*(-7) --21 + j*(110) -84 + j*(32) -48 + j*(-4) -119 + j*(15) -174 + j*(-157) --36 + j*(-284) --210 + j*(-117) --117 + j*(38) --27 + j*(-5) --57 + j*(-45) --81 + j*(-31) --107 + j*(-19) --129 + j*(36) --92 + j*(88) --56 + j*(98) --28 + j*(129) -60 + j*(140) -129 + j*(58) -108 + j*(-37) -47 + j*(-77) --11 + j*(-66) --13 + j*(-17) -44 + j*(-52) --26 + j*(-168) --223 + j*(-115) --238 + j*(111) --64 + j*(192) -21 + j*(105) --16 + j*(61) --45 + j*(96) --6 + j*(173) -145 + j*(181) -225 + j*(-13) -28 + j*(-133) --81 + j*(72) -163 + j*(156) -250 + j*(-125) --13 + j*(-226) --88 + j*(-43) -2 + j*(-64) --158 + j*(-110) --231 + j*(163) -66 + j*(300) -243 + j*(77) -145 + j*(-66) -91 + j*(-82) --3 + j*(-118) --97 + j*(46) -150 + j*(188) -357 + j*(-127) -28 + j*(-403) --263 + j*(-116) --34 + j*(139) -162 + j*(-49) -13 + j*(-190) --71 + j*(-94) --10 + j*(-69) --17 + j*(-113) --30 + j*(-117) --39 + j*(-168) --137 + j*(-205) --234 + j*(-144) --278 + j*(-71) --324 + j*(36) --268 + j*(194) --107 + j*(233) --40 + j*(147) -144 + j*(100) -114 + j*(-139) --59 + j*(-81) -41 + j*(-2) -23 + j*(-161) --189 + j*(-74) --52 + j*(148) -144 + j*(-46) --123 + j*(-207) --264 + j*(122) -91 + j*(254) -206 + j*(-91) --107 + j*(-187) --196 + j*(83) -6 + j*(176) -105 + j*(62) -81 + j*(-24) -15 + j*(-57) --35 + j*(6) -52 + j*(47) -86 + j*(-85) --80 + j*(-120) --107 + j*(52) -46 + j*(39) --36 + j*(-94) --171 + j*(52) -12 + j*(190) -124 + j*(6) --62 + j*(-54) --77 + j*(151) -130 + j*(168) -180 + j*(26) -166 + j*(-25) -178 + j*(-141) --4 + j*(-233) --127 + j*(-46) -69 + j*(38) -97 + j*(-207) --206 + j*(-209) --213 + j*(114) -80 + j*(118) -58 + j*(-122) --129 + j*(-64) --42 + j*(75) -59 + j*(-29) --37 + j*(-95) --54 + j*(-34) --23 + j*(-101) --174 + j*(-157) --306 + j*(5) --240 + j*(180) --135 + j*(243) --26 + j*(291) -132 + j*(257) -208 + j*(124) -208 + j*(8) -157 + j*(-139) --93 + j*(-210) --298 + j*(95) -19 + j*(426) -450 + j*(151) -264 + j*(-317) --165 + j*(-221) --127 + j*(117) -110 + j*(104) -114 + j*(-34) -76 + j*(-50) -64 + j*(-108) --61 + j*(-112) --74 + j*(44) -88 + j*(50) -76 + j*(-103) --59 + j*(-65) -11 + j*(50) -115 + j*(-42) -33 + j*(-141) --35 + j*(-100) --25 + j*(-98) --86 + j*(-113) --129 + j*(-36) --80 + j*(10) --71 + j*(-4) --76 + j*(33) --16 + j*(42) --2 + j*(-22) --56 + j*(-44) --93 + j*(-27) --144 + j*(9) --151 + j*(122) --30 + j*(186) -37 + j*(105) --25 + j*(115) -68 + j*(235) -293 + j*(144) -298 + j*(-127) -99 + j*(-245) --52 + j*(-191) --116 + j*(-89) --85 + j*(19) -25 + j*(21) -33 + j*(-80) --43 + j*(-100) --53 + j*(-90) --119 + j*(-156) --303 + j*(-93) --355 + j*(148) --214 + j*(329) --27 + j*(395) -199 + j*(349) -314 + j*(112) -151 + j*(-49) -52 + j*(86) -244 + j*(121) -284 + j*(-127) -49 + j*(-185) -27 + j*(2) -211 + j*(-42) -151 + j*(-265) --82 + j*(-264) --145 + j*(-88) --41 + j*(-4) -49 + j*(-73) --9 + j*(-200) --190 + j*(-180) --232 + j*(2) --119 + j*(68) --112 + j*(33) --122 + j*(126) -45 + j*(161) -108 + j*(-21) --56 + j*(-84) --106 + j*(52) --6 + j*(88) -16 + j*(47) -35 + j*(50) -67 + j*(-11) --2 + j*(-44) -1 + j*(21) -67 + j*(-56) --99 + j*(-135) --204 + j*(109) -81 + j*(243) -216 + j*(-44) --47 + j*(-130) --43 + j*(114) -233 + j*(11) -84 + j*(-315) --265 + j*(-170) --150 + j*(167) -147 + j*(76) -84 + j*(-208) --208 + j*(-217) --339 + j*(59) --137 + j*(312) -177 + j*(216) -168 + j*(-83) --66 + j*(-107) --75 + j*(45) --13 + j*(2) --144 + j*(21) --92 + j*(252) -191 + j*(226) -193 + j*(-28) -28 + j*(-5) -127 + j*(87) -182 + j*(-74) -2 + j*(-99) -33 + j*(83) -234 + j*(-5) -139 + j*(-223) --50 + j*(-148) -25 + j*(-31) -87 + j*(-139) --49 + j*(-194) --114 + j*(-74) --28 + j*(-21) -13 + j*(-83) --19 + j*(-139) --81 + j*(-182) --221 + j*(-189) --378 + j*(-21) --302 + j*(275) -32 + j*(345) -192 + j*(62) --36 + j*(-93) --155 + j*(137) -107 + j*(244) -225 + j*(-13) -21 + j*(-123) --39 + j*(11) -32 + j*(-8) --66 + j*(-26) --44 + j*(143) -177 + j*(104) -151 + j*(-119) --4 + j*(-110) -28 + j*(-82) --83 + j*(-192) --298 + j*(13) --53 + j*(310) -272 + j*(63) -35 + j*(-238) --210 + j*(-17) --16 + j*(141) -29 + j*(-34) --162 + j*(33) --40 + j*(267) -216 + j*(182) -217 + j*(-12) -163 + j*(-77) -107 + j*(-164) --49 + j*(-154) --57 + j*(-6) -54 + j*(-30) --21 + j*(-124) --98 + j*(-25) --4 + j*(8) --48 + j*(-83) --159 + j*(32) --23 + j*(166) -86 + j*(62) -21 + j*(54) -163 + j*(147) -370 + j*(-109) -130 + j*(-465) --307 + j*(-383) --434 + j*(-24) --293 + j*(241) --41 + j*(349) -219 + j*(228) -253 + j*(-38) -90 + j*(-149) -0 + j*(-105) --21 + j*(-91) --54 + j*(-76) --62 + j*(-71) --137 + j*(-81) --226 + j*(62) --79 + j*(230) -105 + j*(127) -32 + j*(-2) --16 + j*(91) -112 + j*(83) -72 + j*(-52) --34 + j*(34) -112 + j*(119) -197 + j*(-66) -29 + j*(-139) -23 + j*(-28) -93 + j*(-136) --129 + j*(-206) --209 + j*(88) -128 + j*(161) -176 + j*(-214) --231 + j*(-250) --276 + j*(163) -103 + j*(216) -162 + j*(-110) --103 + j*(-170) --168 + j*(8) --94 + j*(54) --115 + j*(67) --83 + j*(164) -49 + j*(171) -99 + j*(70) -49 + j*(5) --25 + j*(11) --71 + j*(113) -41 + j*(254) -279 + j*(206) -356 + j*(-46) -205 + j*(-207) -76 + j*(-194) -20 + j*(-175) --49 + j*(-140) --44 + j*(-54) -33 + j*(-76) --28 + j*(-177) --183 + j*(-119) --182 + j*(59) --43 + j*(129) -66 + j*(73) -86 + j*(-34) -5 + j*(-106) --82 + j*(-42) --15 + j*(33) -47 + j*(-59) --76 + j*(-122) --139 + j*(6) --29 + j*(49) --35 + j*(-45) --131 + j*(8) --66 + j*(96) --30 + j*(40) --101 + j*(95) -33 + j*(218) -203 + j*(63) -78 + j*(-99) -5 + j*(-5) -102 + j*(-70) --103 + j*(-209) --305 + j*(100) -66 + j*(353) -339 + j*(-42) --57 + j*(-307) --301 + j*(69) -21 + j*(284) -190 + j*(57) -82 + j*(-44) -60 + j*(-49) --45 + j*(-98) --144 + j*(104) -140 + j*(253) -336 + j*(-73) -31 + j*(-284) --132 + j*(-40) -67 + j*(16) -7 + j*(-181) --216 + j*(-55) --95 + j*(177) -87 + j*(103) -58 + j*(34) -124 + j*(73) -238 + j*(-86) -78 + j*(-296) --180 + j*(-224) --221 + j*(8) --57 + j*(126) -105 + j*(9) --1 + j*(-199) --282 + j*(-111) --247 + j*(228) -83 + j*(258) -134 + j*(0) --55 + j*(-5) -2 + j*(168) -202 + j*(102) -206 + j*(-102) -62 + j*(-202) --98 + j*(-160) --134 + j*(5) -27 + j*(59) -62 + j*(-136) --194 + j*(-168) --259 + j*(117) --12 + j*(205) -42 + j*(38) --71 + j*(74) -40 + j*(184) -169 + j*(58) -74 + j*(-47) -27 + j*(14) -86 + j*(18) -86 + j*(-35) -77 + j*(-62) -31 + j*(-113) --66 + j*(-48) -53 + j*(76) -242 + j*(-124) --1 + j*(-432) --417 + j*(-264) --421 + j*(142) --186 + j*(296) --6 + j*(315) -218 + j*(226) -247 + j*(-93) --90 + j*(-182) --182 + j*(164) -179 + j*(245) -259 + j*(-111) --62 + j*(-174) --81 + j*(103) -185 + j*(71) -134 + j*(-216) --175 + j*(-194) --214 + j*(105) -35 + j*(205) -169 + j*(27) -64 + j*(-98) --13 + j*(-45) -30 + j*(-47) --57 + j*(-122) --204 + j*(22) --45 + j*(244) -211 + j*(115) -117 + j*(-112) --33 + j*(-10) -135 + j*(69) -196 + j*(-180) --95 + j*(-271) --214 + j*(4) -13 + j*(116) -98 + j*(-71) --56 + j*(-140) --122 + j*(-34) --77 + j*(11) --88 + j*(7) --112 + j*(77) --31 + j*(173) -130 + j*(153) -206 + j*(-4) -139 + j*(-139) -52 + j*(-182) --37 + j*(-235) --233 + j*(-211) --333 + j*(33) --136 + j*(209) -6 + j*(76) --130 + j*(20) --127 + j*(216) -112 + j*(206) -97 + j*(-23) --114 + j*(33) --18 + j*(248) -208 + j*(163) -162 + j*(-18) -74 + j*(20) -156 + j*(33) -157 + j*(-88) -54 + j*(-106) -54 + j*(-64) -59 + j*(-120) --37 + j*(-133) --66 + j*(-51) --35 + j*(-43) --90 + j*(-32) --62 + j*(88) -112 + j*(53) -64 + j*(-175) --239 + j*(-116) --204 + j*(276) -263 + j*(312) -400 + j*(-181) --59 + j*(-414) --345 + j*(-23) --17 + j*(279) -287 + j*(-2) -54 + j*(-317) --267 + j*(-153) --187 + j*(132) -25 + j*(112) -10 + j*(-30) --101 + j*(14) --50 + j*(140) -96 + j*(128) -144 + j*(-4) -58 + j*(-91) --30 + j*(-45) --2 + j*(36) -90 + j*(21) -115 + j*(-74) -66 + j*(-150) --4 + j*(-198) --127 + j*(-223) --272 + j*(-129) --288 + j*(60) --172 + j*(156) --106 + j*(139) --111 + j*(180) --2 + j*(269) -180 + j*(195) -193 + j*(-4) -47 + j*(-75) --20 + j*(1) -14 + j*(30) --6 + j*(3) --56 + j*(64) -12 + j*(162) -153 + j*(139) -195 + j*(6) -124 + j*(-74) -64 + j*(-59) -65 + j*(-44) -59 + j*(-62) -30 + j*(-60) -30 + j*(-37) -40 + j*(-38) -44 + j*(-30) -95 + j*(-29) -142 + j*(-123) -58 + j*(-236) --76 + j*(-217) --99 + j*(-147) --112 + j*(-163) --206 + j*(-144) --247 + j*(-40) --233 + j*(20) --268 + j*(112) --160 + j*(294) -119 + j*(248) -119 + j*(-46) --166 + j*(-35) --129 + j*(279) -225 + j*(253) -252 + j*(-98) --35 + j*(-184) --156 + j*(-9) --127 + j*(107) --74 + j*(223) -131 + j*(286) -298 + j*(88) -164 + j*(-94) -57 + j*(7) -195 + j*(31) -187 + j*(-161) --21 + j*(-151) -23 + j*(42) -228 + j*(-50) -130 + j*(-291) --111 + j*(-240) --89 + j*(-58) -41 + j*(-115) --55 + j*(-274) --294 + j*(-221) --366 + j*(43) --172 + j*(231) -43 + j*(133) --14 + j*(-48) --181 + j*(25) --89 + j*(216) -122 + j*(141) -79 + j*(-52) --66 + j*(-21) --28 + j*(63) --8 + j*(-1) --116 + j*(37) --42 + j*(202) -159 + j*(124) -83 + j*(-76) --100 + j*(16) -22 + j*(194) -196 + j*(66) -77 + j*(-83) --19 + j*(47) -152 + j*(118) -251 + j*(-88) -80 + j*(-239) --86 + j*(-166) --109 + j*(-57) --93 + j*(1) --73 + j*(54) --21 + j*(100) -72 + j*(111) -172 + j*(20) -124 + j*(-136) --50 + j*(-129) --43 + j*(38) -132 + j*(0) -69 + j*(-211) --181 + j*(-151) --145 + j*(109) -105 + j*(105) -136 + j*(-108) --2 + j*(-182) --82 + j*(-158) --173 + j*(-144) --274 + j*(-18) --214 + j*(171) --36 + j*(211) -54 + j*(119) -42 + j*(52) -20 + j*(42) -28 + j*(47) -45 + j*(26) -29 + j*(4) -18 + j*(19) -47 + j*(9) -21 + j*(-30) --14 + j*(29) -117 + j*(64) -194 + j*(-156) --80 + j*(-331) --351 + j*(-86) --207 + j*(208) -8 + j*(154) --31 + j*(71) --18 + j*(165) -136 + j*(132) -124 + j*(-31) -2 + j*(-37) --8 + j*(30) -4 + j*(45) -24 + j*(95) -135 + j*(85) -139 + j*(-47) -35 + j*(-35) -120 + j*(34) -194 + j*(-156) --86 + j*(-270) --250 + j*(62) -107 + j*(274) -376 + j*(-83) -81 + j*(-404) --240 + j*(-239) --210 + j*(-13) --152 + j*(24) --155 + j*(121) -13 + j*(231) -222 + j*(92) -180 + j*(-144) -1 + j*(-199) --95 + j*(-138) --144 + j*(-87) --191 + j*(10) --120 + j*(147) -57 + j*(143) -117 + j*(-29) --23 + j*(-131) --144 + j*(-45) --124 + j*(57) --93 + j*(82) --83 + j*(140) -27 + j*(192) -135 + j*(89) -48 + j*(-26) --49 + j*(83) -102 + j*(208) -302 + j*(53) -222 + j*(-209) --25 + j*(-246) --151 + j*(-85) --100 + j*(69) -42 + j*(111) -156 + j*(-3) -81 + j*(-167) --112 + j*(-141) --125 + j*(42) -30 + j*(71) -41 + j*(-50) --55 + j*(-14) -54 + j*(79) -187 + j*(-110) --51 + j*(-331) --372 + j*(-107) --217 + j*(260) -122 + j*(160) -20 + j*(-132) --268 + j*(17) --103 + j*(351) -269 + j*(233) -226 + j*(-110) --33 + j*(-105) --6 + j*(63) -107 + j*(-15) --10 + j*(-103) --88 + j*(27) -31 + j*(91) -69 + j*(8) -44 + j*(25) -150 + j*(0) -107 + j*(-216) --198 + j*(-200) --223 + j*(147) -117 + j*(201) -166 + j*(-112) --123 + j*(-139) --135 + j*(134) -117 + j*(157) -165 + j*(-52) -25 + j*(-124) --57 + j*(-50) --33 + j*(39) -78 + j*(47) -110 + j*(-95) --59 + j*(-139) --91 + j*(61) -158 + j*(62) -148 + j*(-249) --190 + j*(-263) --224 + j*(35) --13 + j*(33) --105 + j*(-115) --235 + j*(47) --71 + j*(166) --21 + j*(40) --129 + j*(108) -42 + j*(244) -213 + j*(25) --16 + j*(-142) --153 + j*(88) -67 + j*(202) -175 + j*(26) -91 + j*(-64) -47 + j*(-93) --87 + j*(-119) --182 + j*(95) -90 + j*(248) -279 + j*(-56) --25 + j*(-264) --223 + j*(11) --1 + j*(165) -72 + j*(1) --47 + j*(19) -42 + j*(117) -108 + j*(-4) --17 + j*(0) -78 + j*(148) -271 + j*(-11) -112 + j*(-221) --30 + j*(-89) -124 + j*(-91) --13 + j*(-344) --397 + j*(-146) --210 + j*(320) -266 + j*(155) -98 + j*(-298) --337 + j*(-121) --184 + j*(305) -194 + j*(218) -178 + j*(-49) -65 + j*(-50) -132 + j*(-78) -56 + j*(-267) --237 + j*(-258) --377 + j*(42) --192 + j*(322) -141 + j*(327) -325 + j*(55) -189 + j*(-217) --54 + j*(-221) --131 + j*(-95) --144 + j*(-40) --175 + j*(66) --47 + j*(191) -121 + j*(77) -18 + j*(-81) --108 + j*(42) -54 + j*(137) -127 + j*(-64) --112 + j*(-124) --172 + j*(144) -100 + j*(218) -187 + j*(-15) -14 + j*(-90) --21 + j*(30) -62 + j*(21) -18 + j*(-42) --34 + j*(35) -68 + j*(101) -170 + j*(2) -119 + j*(-130) -6 + j*(-136) --16 + j*(-76) -10 + j*(-100) --74 + j*(-148) --179 + j*(-42) --91 + j*(98) -42 + j*(25) --37 + j*(-88) --147 + j*(-1) --86 + j*(103) --18 + j*(102) -36 + j*(106) -126 + j*(17) -11 + j*(-145) --206 + j*(-6) --47 + j*(245) -207 + j*(66) --15 + j*(-161) --214 + j*(128) -122 + j*(326) -318 + j*(7) -70 + j*(-118) -91 + j*(78) -311 + j*(-99) -57 + j*(-383) --241 + j*(-135) --14 + j*(94) -115 + j*(-156) --186 + j*(-227) --252 + j*(89) -21 + j*(159) -73 + j*(-37) --58 + j*(-59) --62 + j*(23) --24 + j*(32) -8 + j*(34) -42 + j*(-37) --79 + j*(-105) --193 + j*(67) -2 + j*(228) -190 + j*(57) -70 + j*(-106) --11 + j*(-27) -69 + j*(-54) --45 + j*(-185) --231 + j*(-43) --115 + j*(156) -37 + j*(57) --93 + j*(-25) --156 + j*(170) -78 + j*(279) -248 + j*(86) -146 + j*(-98) -6 + j*(-70) -16 + j*(18) -95 + j*(-5) -75 + j*(-119) --78 + j*(-141) --161 + j*(25) --20 + j*(162) -144 + j*(63) -93 + j*(-98) --44 + j*(-76) --37 + j*(32) -53 + j*(35) -81 + j*(-43) -35 + j*(-105) --49 + j*(-117) --122 + j*(-47) --89 + j*(52) --2 + j*(38) --39 + j*(-33) --122 + j*(45) --23 + j*(166) -119 + j*(76) -28 + j*(-49) --66 + j*(86) -141 + j*(190) -303 + j*(-67) -58 + j*(-293) --188 + j*(-107) --60 + j*(103) -87 + j*(5) --7 + j*(-75) --25 + j*(29) -105 + j*(-1) -59 + j*(-175) --141 + j*(-156) --177 + j*(27) --63 + j*(100) -4 + j*(71) -35 + j*(47) -62 + j*(-2) -26 + j*(-59) --28 + j*(-43) --9 + j*(-8) -21 + j*(-62) --70 + j*(-139) --241 + j*(-59) --252 + j*(199) -17 + j*(357) -298 + j*(173) -252 + j*(-141) -3 + j*(-206) --95 + j*(-69) --40 + j*(-15) --54 + j*(-54) --133 + j*(-16) --143 + j*(107) --35 + j*(205) -133 + j*(177) -202 + j*(1) -71 + j*(-123) --56 + j*(-41) -13 + j*(59) -94 + j*(-21) -19 + j*(-98) --47 + j*(-52) --40 + j*(-37) --110 + j*(-35) --149 + j*(111) -23 + j*(215) -165 + j*(74) -76 + j*(-56) --11 + j*(1) -30 + j*(45) -23 + j*(37) -51 + j*(127) -254 + j*(113) -326 + j*(-168) -64 + j*(-348) --156 + j*(-192) --112 + j*(-25) --44 + j*(-9) --15 + j*(15) -85 + j*(-18) -57 + j*(-182) --154 + j*(-184) --199 + j*(30) --31 + j*(102) -40 + j*(6) -31 + j*(-35) -49 + j*(-125) --118 + j*(-252) --381 + j*(-74) --271 + j*(275) -63 + j*(257) -85 + j*(16) --61 + j*(23) --1 + j*(112) -55 + j*(21) --43 + j*(4) --15 + j*(107) -101 + j*(37) --3 + j*(-95) --155 + j*(18) --65 + j*(187) -84 + j*(152) -90 + j*(71) -85 + j*(79) -158 + j*(64) -202 + j*(-56) -105 + j*(-194) --98 + j*(-185) --185 + j*(19) --22 + j*(162) -120 + j*(41) -18 + j*(-66) --49 + j*(47) -81 + j*(86) -91 + j*(-52) --56 + j*(-18) -25 + j*(170) -280 + j*(81) -242 + j*(-219) --45 + j*(-251) --104 + j*(-11) -115 + j*(41) -188 + j*(-203) --66 + j*(-356) --310 + j*(-163) --231 + j*(110) --1 + j*(123) -53 + j*(-40) --52 + j*(-109) --141 + j*(-64) --173 + j*(28) --115 + j*(134) -21 + j*(132) -54 + j*(7) --55 + j*(-27) --80 + j*(75) -13 + j*(101) -42 + j*(37) -21 + j*(30) -62 + j*(24) -64 + j*(-76) --80 + j*(-126) --209 + j*(16) --119 + j*(219) -111 + j*(224) -198 + j*(27) -74 + j*(-86) -3 + j*(-23) -49 + j*(-32) --34 + j*(-107) --163 + j*(16) --45 + j*(180) -108 + j*(92) -33 + j*(-2) -5 + j*(95) -135 + j*(96) -144 + j*(-18) -107 + j*(-13) -182 + j*(-74) -67 + j*(-247) --175 + j*(-125) --54 + j*(132) -190 + j*(-6) -40 + j*(-233) --161 + j*(-98) --61 + j*(39) --20 + j*(-42) --102 + j*(4) --11 + j*(105) -84 + j*(20) -41 + j*(-22) -104 + j*(-15) -120 + j*(-202) --148 + j*(-276) --279 + j*(-10) --69 + j*(116) --6 + j*(-48) --163 + j*(-61) --185 + j*(83) --119 + j*(146) --56 + j*(219) -141 + j*(226) -251 + j*(-26) -21 + j*(-221) --214 + j*(-74) --190 + j*(148) --60 + j*(253) -116 + j*(282) -306 + j*(153) -316 + j*(-95) -158 + j*(-246) --43 + j*(-279) --268 + j*(-133) --239 + j*(223) -180 + j*(308) -349 + j*(-122) --64 + j*(-347) --322 + j*(26) --8 + j*(297) -247 + j*(64) -94 + j*(-145) --49 + j*(-45) -32 + j*(45) -108 + j*(-38) -32 + j*(-130) --74 + j*(-74) --28 + j*(23) -49 + j*(-39) --59 + j*(-112) --149 + j*(50) -41 + j*(172) -185 + j*(-4) -66 + j*(-120) -44 + j*(-49) -133 + j*(-151) --36 + j*(-321) --262 + j*(-193) --228 + j*(-13) --184 + j*(-14) --239 + j*(48) --181 + j*(162) --107 + j*(170) --72 + j*(226) -110 + j*(231) -163 + j*(-16) --125 + j*(-67) --160 + j*(276) -224 + j*(334) -330 + j*(-10) -110 + j*(-105) -117 + j*(-16) -158 + j*(-151) --41 + j*(-218) --127 + j*(-69) --90 + j*(-40) --190 + j*(7) --132 + j*(233) -139 + j*(206) -105 + j*(-23) --70 + j*(91) -141 + j*(276) -378 + j*(51) -246 + j*(-183) -138 + j*(-158) -154 + j*(-242) --54 + j*(-347) --252 + j*(-144) --119 + j*(59) -10 + j*(-28) --83 + j*(-84) --122 + j*(31) --16 + j*(100) -103 + j*(54) -160 + j*(-99) -23 + j*(-279) --250 + j*(-215) --277 + j*(72) --40 + j*(152) -33 + j*(-25) --109 + j*(-80) --172 + j*(23) --148 + j*(94) --120 + j*(180) -33 + j*(251) -209 + j*(100) -108 + j*(-134) --139 + j*(-85) --134 + j*(147) -62 + j*(185) -126 + j*(57) -85 + j*(6) -94 + j*(-25) -28 + j*(-120) --146 + j*(-66) --144 + j*(151) -54 + j*(213) -146 + j*(105) -148 + j*(69) -239 + j*(5) -206 + j*(-204) --40 + j*(-253) --141 + j*(-56) --26 + j*(25) --9 + j*(-23) --25 + j*(31) -88 + j*(24) -68 + j*(-133) --115 + j*(-102) --71 + j*(83) -107 + j*(17) -22 + j*(-158) --146 + j*(-75) --86 + j*(59) --18 + j*(10) --89 + j*(6) --71 + j*(113) -38 + j*(118) -62 + j*(61) -79 + j*(71) -175 + j*(26) -182 + j*(-141) -27 + j*(-250) --154 + j*(-200) --242 + j*(-35) --169 + j*(148) -28 + j*(182) -119 + j*(23) --4 + j*(-71) --80 + j*(55) -78 + j*(136) -201 + j*(-40) -51 + j*(-215) --136 + j*(-129) --115 + j*(15) --48 + j*(14) --65 + j*(13) --32 + j*(52) -6 + j*(-6) --92 + j*(-28) --108 + j*(125) -95 + j*(154) -145 + j*(-75) --81 + j*(-149) --168 + j*(36) --63 + j*(98) --88 + j*(78) --85 + j*(232) -168 + j*(283) -300 + j*(21) -99 + j*(-140) --28 + j*(1) -87 + j*(86) -153 + j*(6) -146 + j*(-33) -196 + j*(-98) -144 + j*(-267) --88 + j*(-317) --242 + j*(-145) --199 + j*(22) --127 + j*(65) --105 + j*(106) --24 + j*(184) -145 + j*(170) -253 + j*(-1) -181 + j*(-197) -1 + j*(-265) --160 + j*(-197) --226 + j*(-42) --148 + j*(98) --10 + j*(91) -0 + j*(-11) --71 + j*(-3) --41 + j*(52) --11 + j*(0) --92 + j*(-5) --85 + j*(107) -28 + j*(93) --16 + j*(7) --84 + j*(111) -69 + j*(193) -167 + j*(37) -43 + j*(-35) -47 + j*(66) -161 + j*(-15) -35 + j*(-163) --132 + j*(-27) --15 + j*(130) -108 + j*(49) -64 + j*(-9) -86 + j*(22) -136 + j*(-57) -55 + j*(-124) -25 + j*(-78) -64 + j*(-126) --51 + j*(-210) --187 + j*(-104) --148 + j*(22) --120 + j*(35) --128 + j*(148) -94 + j*(257) -345 + j*(11) -172 + j*(-356) --223 + j*(-314) --296 + j*(6) --100 + j*(103) --70 + j*(-10) --178 + j*(45) --81 + j*(194) -84 + j*(86) --57 + j*(-71) --226 + j*(136) -33 + j*(346) -279 + j*(84) -23 + j*(-144) --164 + j*(141) -165 + j*(317) -367 + j*(-18) -89 + j*(-231) --88 + j*(-35) -35 + j*(93) -132 + j*(57) -219 + j*(1) -264 + j*(-218) --21 + j*(-406) --325 + j*(-150) --140 + j*(187) -168 + j*(58) -76 + j*(-210) --147 + j*(-161) --148 + j*(-8) --74 + j*(6) --89 + j*(-23) --144 + j*(18) --127 + j*(123) -2 + j*(157) -58 + j*(49) --41 + j*(27) --10 + j*(156) -165 + j*(92) -88 + j*(-93) --71 + j*(11) -91 + j*(141) -202 + j*(-65) --13 + j*(-148) --18 + j*(62) -214 + j*(-37) -35 + j*(-320) --281 + j*(-126) --102 + j*(167) -122 + j*(-16) --92 + j*(-170) --205 + j*(63) -10 + j*(156) -71 + j*(-11) --37 + j*(-30) --14 + j*(35) -26 + j*(-16) --26 + j*(-56) --78 + j*(-49) --167 + j*(5) --163 + j*(206) -111 + j*(287) -266 + j*(14) -36 + j*(-153) --81 + j*(48) -132 + j*(109) -180 + j*(-126) --32 + j*(-206) --134 + j*(-86) --135 + j*(-16) --150 + j*(71) --54 + j*(168) -60 + j*(118) -49 + j*(54) -72 + j*(72) -124 + j*(-14) -5 + j*(-96) --78 + j*(39) -68 + j*(103) -100 + j*(-56) --78 + j*(-47) --35 + j*(161) -194 + j*(110) -156 + j*(-115) --33 + j*(-79) -11 + j*(81) -156 + j*(53) -188 + j*(-41) -220 + j*(-119) -189 + j*(-305) --71 + j*(-407) --284 + j*(-194) --153 + j*(18) -1 + j*(-100) --168 + j*(-241) --371 + j*(-59) --262 + j*(197) --33 + j*(185) --1 + j*(25) --129 + j*(-14) --205 + j*(121) --92 + j*(288) -154 + j*(258) -230 + j*(4) -18 + j*(-135) --125 + j*(29) -9 + j*(150) -98 + j*(33) --13 + j*(-10) --10 + j*(112) -136 + j*(90) -122 + j*(-68) --18 + j*(-75) --45 + j*(35) -28 + j*(87) -118 + j*(69) -181 + j*(-52) -69 + j*(-202) --136 + j*(-134) --113 + j*(66) -42 + j*(57) -8 + j*(-47) --66 + j*(23) -25 + j*(87) -83 + j*(7) -42 + j*(-22) -74 + j*(-25) -54 + j*(-136) --122 + j*(-134) --162 + j*(60) -3 + j*(125) -60 + j*(15) --7 + j*(-12) --16 + j*(25) --18 + j*(44) -15 + j*(123) -188 + j*(107) -230 + j*(-129) --8 + j*(-223) --100 + j*(-18) -85 + j*(27) -83 + j*(-168) --118 + j*(-143) --72 + j*(44) -106 + j*(-39) -4 + j*(-240) --216 + j*(-181) --240 + j*(-13) --204 + j*(47) --207 + j*(129) --109 + j*(250) -64 + j*(228) -132 + j*(100) -86 + j*(10) -14 + j*(3) --6 + j*(80) -102 + j*(127) -205 + j*(6) -120 + j*(-132) -23 + j*(-95) -71 + j*(-92) -2 + j*(-221) --213 + j*(-148) --161 + j*(94) -59 + j*(23) --74 + j*(-202) --357 + j*(-33) --240 + j*(288) -18 + j*(272) -37 + j*(175) -105 + j*(233) -291 + j*(98) -181 + j*(-177) --100 + j*(-116) --73 + j*(117) -91 + j*(106) -87 + j*(23) -88 + j*(41) -129 + j*(-18) -35 + j*(-51) -51 + j*(93) -299 + j*(35) -273 + j*(-335) --156 + j*(-414) --351 + j*(-25) --69 + j*(227) -180 + j*(63) -119 + j*(-141) --9 + j*(-163) --68 + j*(-130) --117 + j*(-95) --148 + j*(-23) --117 + j*(53) --54 + j*(87) -18 + j*(79) -74 + j*(8) -27 + j*(-95) --106 + j*(-81) --122 + j*(64) -18 + j*(103) -67 + j*(-23) --38 + j*(-62) --52 + j*(15) --5 + j*(-18) --100 + j*(-43) --124 + j*(118) -87 + j*(151) -124 + j*(-83) --111 + j*(-116) --126 + j*(108) -68 + j*(95) -16 + j*(-65) --108 + j*(23) -4 + j*(105) -25 + j*(-23) --137 + j*(26) --43 + j*(242) -209 + j*(152) -157 + j*(-90) --29 + j*(-62) --1 + j*(57) -65 + j*(22) -33 + j*(-6) -37 + j*(25) -71 + j*(4) -57 + j*(-27) -45 + j*(-31) -33 + j*(-45) -14 + j*(-37) -20 + j*(-40) --26 + j*(-62) --83 + j*(25) -33 + j*(124) -168 + j*(6) -71 + j*(-131) --31 + j*(-49) -61 + j*(-3) -76 + j*(-119) --37 + j*(-129) --37 + j*(-59) --21 + j*(-105) --117 + j*(-103) --119 + j*(0) --52 + j*(-21) --143 + j*(-62) --216 + j*(88) --84 + j*(226) -62 + j*(204) -172 + j*(158) -307 + j*(4) -238 + j*(-293) --97 + j*(-386) --315 + j*(-170) --280 + j*(40) --205 + j*(124) --131 + j*(193) --19 + j*(206) -49 + j*(155) -71 + j*(120) -98 + j*(83) -88 + j*(44) -91 + j*(46) -132 + j*(-2) -78 + j*(-77) -6 + j*(-24) -94 + j*(13) -116 + j*(-141) --91 + j*(-177) --135 + j*(46) -101 + j*(64) -78 + j*(-226) --296 + j*(-205) --355 + j*(235) -74 + j*(406) -328 + j*(66) -108 + j*(-200) --114 + j*(-77) --45 + j*(81) -49 + j*(34) -9 + j*(-13) --10 + j*(21) -1 + j*(23) --32 + j*(61) -52 + j*(161) -234 + j*(83) -208 + j*(-136) -31 + j*(-148) -47 + j*(-47) -117 + j*(-138) --10 + j*(-226) --93 + j*(-142) --71 + j*(-156) --241 + j*(-191) --377 + j*(94) --81 + j*(344) -216 + j*(110) -48 + j*(-162) --172 + j*(-31) --73 + j*(142) -57 + j*(87) -47 + j*(13) -22 + j*(-12) --25 + j*(-16) --24 + j*(68) -117 + j*(53) -107 + j*(-164) --175 + j*(-194) --265 + j*(111) -1 + j*(253) -161 + j*(64) -62 + j*(-62) -4 + j*(-42) --28 + j*(-76) --167 + j*(-33) --160 + j*(195) -110 + j*(252) -217 + j*(-8) --30 + j*(-126) --147 + j*(141) -146 + j*(299) -387 + j*(37) -243 + j*(-246) -35 + j*(-247) --33 + j*(-213) --173 + j*(-204) --295 + j*(11) --115 + j*(234) -114 + j*(135) -74 + j*(-23) -9 + j*(18) -79 + j*(5) -8 + j*(-88) --105 + j*(53) -108 + j*(214) -368 + j*(-23) -211 + j*(-374) --131 + j*(-378) --259 + j*(-180) --253 + j*(-60) --255 + j*(34) --210 + j*(148) --110 + j*(215) -11 + j*(240) -160 + j*(177) -216 + j*(-8) -86 + j*(-150) --68 + j*(-105) --78 + j*(-5) --49 + j*(3) --88 + j*(13) --98 + j*(117) -33 + j*(196) -191 + j*(102) -180 + j*(-88) -23 + j*(-161) --81 + j*(-76) --59 + j*(-5) --49 + j*(-9) --93 + j*(25) --62 + j*(125) -76 + j*(147) -159 + j*(25) -98 + j*(-92) -0 + j*(-98) --47 + j*(-64) --97 + j*(-25) --108 + j*(90) -31 + j*(173) -175 + j*(49) -82 + j*(-114) --69 + j*(-41) --1 + j*(96) -131 + j*(36) -105 + j*(-78) -41 + j*(-94) -9 + j*(-105) --73 + j*(-95) --102 + j*(18) -3 + j*(81) -83 + j*(25) -106 + j*(-34) -129 + j*(-136) -4 + j*(-281) --235 + j*(-223) --278 + j*(6) --155 + j*(91) --127 + j*(73) --122 + j*(136) --34 + j*(174) -15 + j*(154) -86 + j*(183) -236 + j*(89) -199 + j*(-133) -11 + j*(-152) -20 + j*(-77) -4 + j*(-209) --286 + j*(-191) --341 + j*(189) -17 + j*(314) -130 + j*(55) --38 + j*(45) -91 + j*(190) -264 + j*(-47) --21 + j*(-260) --262 + j*(22) --18 + j*(275) -221 + j*(108) -154 + j*(-83) -52 + j*(-103) --15 + j*(-94) --64 + j*(-11) -44 + j*(52) -108 + j*(-109) --117 + j*(-198) --267 + j*(60) --30 + j*(270) -205 + j*(99) -99 + j*(-131) --123 + j*(-71) --119 + j*(173) -160 + j*(271) -397 + j*(8) -227 + j*(-342) --134 + j*(-293) --158 + j*(-21) -2 + j*(-22) --86 + j*(-103) --139 + j*(74) -104 + j*(113) -129 + j*(-175) --195 + j*(-192) --213 + j*(151) -124 + j*(177) -165 + j*(-131) --93 + j*(-189) --161 + j*(-6) --66 + j*(54) --33 + j*(25) --26 + j*(12) --36 + j*(-13) --82 + j*(9) --55 + j*(66) --14 + j*(37) --62 + j*(30) --41 + j*(111) -63 + j*(80) -17 + j*(-19) --72 + j*(60) -42 + j*(157) -161 + j*(45) -98 + j*(-74) -28 + j*(-83) --31 + j*(-104) --149 + j*(-33) --94 + j*(147) -101 + j*(103) -35 + j*(-83) --158 + j*(25) --26 + j*(250) -224 + j*(148) -187 + j*(-78) -29 + j*(-98) --18 + j*(-13) -12 + j*(62) -127 + j*(79) -210 + j*(-69) -71 + j*(-202) --48 + j*(-101) -40 + j*(-66) --28 + j*(-208) --261 + j*(-81) --141 + j*(224) -177 + j*(142) -123 + j*(-127) --58 + j*(-62) -45 + j*(30) -76 + j*(-122) --115 + j*(-110) --59 + j*(100) -177 + j*(4) -77 + j*(-275) --228 + j*(-226) --267 + j*(42) --95 + j*(151) -31 + j*(91) -57 + j*(-20) --27 + j*(-105) --147 + j*(-56) --144 + j*(71) --50 + j*(106) --7 + j*(58) --29 + j*(24) --67 + j*(45) --49 + j*(118) -65 + j*(116) -86 + j*(-36) --112 + j*(-77) --193 + j*(165) -64 + j*(317) -276 + j*(114) -177 + j*(-104) -25 + j*(-93) --6 + j*(-34) --25 + j*(0) -8 + j*(62) -98 + j*(21) -41 + j*(-95) --111 + j*(-27) --52 + j*(167) -162 + j*(155) -220 + j*(-29) -118 + j*(-123) -54 + j*(-117) -21 + j*(-127) --53 + j*(-118) --95 + j*(-32) --35 + j*(44) -45 + j*(13) -33 + j*(-52) --14 + j*(-35) -33 + j*(7) -99 + j*(-81) -2 + j*(-207) --172 + j*(-160) --208 + j*(-7) --146 + j*(72) --112 + j*(112) --35 + j*(176) -103 + j*(151) -158 + j*(18) -99 + j*(-81) -11 + j*(-106) --61 + j*(-59) --44 + j*(31) -65 + j*(18) -53 + j*(-113) --81 + j*(-117) --83 + j*(-16) --30 + j*(-77) --202 + j*(-127) --324 + j*(141) --44 + j*(362) -228 + j*(146) -90 + j*(-93) --62 + j*(8) -55 + j*(76) -70 + j*(-87) --134 + j*(-94) --181 + j*(119) --22 + j*(212) -74 + j*(162) -115 + j*(141) -197 + j*(92) -218 + j*(-27) -170 + j*(-106) -127 + j*(-173) -2 + j*(-251) --190 + j*(-165) --203 + j*(62) --20 + j*(153) -93 + j*(51) -58 + j*(-40) -6 + j*(-46) --22 + j*(-21) --3 + j*(30) -86 + j*(17) -95 + j*(-126) --79 + j*(-179) --173 + j*(-15) --42 + j*(74) --4 + j*(-47) --164 + j*(-27) --126 + j*(191) -116 + j*(171) -101 + j*(-45) --76 + j*(13) -52 + j*(183) -247 + j*(13) -79 + j*(-192) --83 + j*(-44) -78 + j*(41) -103 + j*(-173) --161 + j*(-172) --162 + j*(106) -95 + j*(105) -82 + j*(-119) --99 + j*(-95) --67 + j*(33) --4 + j*(-14) --74 + j*(-21) --40 + j*(69) -55 + j*(6) --31 + j*(-93) --138 + j*(-1) --71 + j*(106) -7 + j*(80) -4 + j*(54) -16 + j*(66) -38 + j*(67) -89 + j*(71) -165 + j*(-13) -92 + j*(-161) --76 + j*(-122) --33 + j*(4) -47 + j*(-105) --160 + j*(-189) --305 + j*(81) --49 + j*(291) -180 + j*(107) -85 + j*(-82) --24 + j*(-65) --71 + j*(-59) --182 + j*(24) --113 + j*(245) -162 + j*(235) -211 + j*(-2) -82 + j*(-57) -105 + j*(-40) -57 + j*(-190) --214 + j*(-143) --218 + j*(195) -119 + j*(257) -211 + j*(-23) --3 + j*(-104) --58 + j*(68) -81 + j*(122) -161 + j*(34) -153 + j*(-53) -96 + j*(-107) -34 + j*(-81) -81 + j*(-36) -146 + j*(-136) -33 + j*(-271) --147 + j*(-221) --185 + j*(-76) --133 + j*(-6) --98 + j*(9) --80 + j*(22) --57 + j*(44) -0 + j*(50) -52 + j*(-19) --2 + j*(-106) --92 + j*(-95) --130 + j*(-57) --187 + j*(-7) --173 + j*(144) -32 + j*(171) -71 + j*(-71) --226 + j*(-107) --287 + j*(241) -47 + j*(349) -146 + j*(107) -4 + j*(114) -156 + j*(236) -326 + j*(-4) -98 + j*(-211) --76 + j*(-43) -40 + j*(45) -30 + j*(-45) --41 + j*(55) -136 + j*(119) -220 + j*(-103) -8 + j*(-214) --111 + j*(-71) --53 + j*(21) --6 + j*(43) -85 + j*(30) -97 + j*(-129) --117 + j*(-163) --171 + j*(70) -44 + j*(124) -54 + j*(-39) --52 + j*(37) -140 + j*(110) -220 + j*(-192) --144 + j*(-316) --315 + j*(39) --25 + j*(219) -111 + j*(18) --19 + j*(-42) -4 + j*(44) -74 + j*(-40) --48 + j*(-110) --127 + j*(16) --18 + j*(100) -57 + j*(18) --7 + j*(-45) --74 + j*(11) --25 + j*(96) -80 + j*(71) -81 + j*(-37) --18 + j*(-50) --22 + j*(45) -85 + j*(44) -107 + j*(-78) --13 + j*(-150) --145 + j*(-63) --115 + j*(125) -119 + j*(172) -253 + j*(-79) -37 + j*(-286) --185 + j*(-141) --96 + j*(16) --42 + j*(-79) --195 + j*(-61) --161 + j*(144) -57 + j*(105) --1 + j*(-112) --246 + j*(-51) --245 + j*(218) --22 + j*(330) -162 + j*(235) -211 + j*(70) -119 + j*(-49) -3 + j*(-13) -25 + j*(96) -150 + j*(94) -206 + j*(-46) -86 + j*(-180) --112 + j*(-100) --64 + j*(151) -252 + j*(136) -301 + j*(-232) --54 + j*(-372) --244 + j*(-119) --134 + j*(26) --115 + j*(15) --107 + j*(129) -71 + j*(166) -145 + j*(18) -98 + j*(-38) -134 + j*(-103) --1 + j*(-272) --283 + j*(-120) --150 + j*(210) -165 + j*(83) -21 + j*(-183) --189 + j*(-12) --2 + j*(131) -64 + j*(-58) --126 + j*(-49) --59 + j*(136) -103 + j*(37) --17 + j*(-81) --87 + j*(56) -59 + j*(99) -103 + j*(-33) -22 + j*(-93) --52 + j*(-93) --134 + j*(-23) --73 + j*(110) -72 + j*(34) --58 + j*(-106) --211 + j*(92) -29 + j*(271) -210 + j*(41) -16 + j*(-95) --42 + j*(75) -119 + j*(57) -55 + j*(-96) --86 + j*(-13) --23 + j*(100) -32 + j*(108) -118 + j*(181) -371 + j*(95) -402 + j*(-281) -74 + j*(-475) --175 + j*(-357) --277 + j*(-229) --358 + j*(-48) --234 + j*(166) --27 + j*(107) --109 + j*(-28) --217 + j*(129) --30 + j*(271) -136 + j*(125) -71 + j*(-9) --1 + j*(-15) --70 + j*(-4) --133 + j*(132) -42 + j*(294) -303 + j*(142) -223 + j*(-158) --55 + j*(-142) --59 + j*(102) -181 + j*(112) -231 + j*(-144) --11 + j*(-252) --147 + j*(-62) -1 + j*(39) -33 + j*(-119) --177 + j*(-115) --193 + j*(136) -23 + j*(185) -57 + j*(69) -38 + j*(128) -215 + j*(129) -273 + j*(-96) -122 + j*(-198) -69 + j*(-190) --35 + j*(-276) --267 + j*(-134) --122 + j*(179) -229 + j*(28) -83 + j*(-345) --271 + j*(-250) --245 + j*(-14) --210 + j*(-30) --313 + j*(112) --86 + j*(327) -173 + j*(93) --69 + j*(-135) --255 + j*(141) -42 + j*(303) -182 + j*(20) --82 + j*(-75) --145 + j*(193) -121 + j*(270) -237 + j*(54) -108 + j*(-70) -25 + j*(-13) -55 + j*(12) -28 + j*(-23) --34 + j*(63) -120 + j*(189) -352 + j*(4) -215 + j*(-322) --115 + j*(-276) --127 + j*(-49) --33 + j*(-69) --134 + j*(-77) --108 + j*(78) -27 + j*(11) --137 + j*(-69) --186 + j*(235) -243 + j*(309) -369 + j*(-182) --112 + j*(-344) --274 + j*(80) -69 + j*(216) -162 + j*(-28) -27 + j*(-59) -87 + j*(-18) -86 + j*(-177) --136 + j*(-192) --197 + j*(26) --31 + j*(121) -74 + j*(19) -27 + j*(-87) --86 + j*(-85) --127 + j*(34) --18 + j*(105) -66 + j*(24) -24 + j*(-49) --16 + j*(-54) --59 + j*(-66) --125 + j*(-4) --54 + j*(88) -26 + j*(-8) --124 + j*(-73) --205 + j*(136) -11 + j*(251) -134 + j*(88) -36 + j*(11) -19 + j*(73) -58 + j*(71) -84 + j*(89) -207 + j*(41) -176 + j*(-191) --116 + j*(-194) --131 + j*(103) -144 + j*(100) -114 + j*(-139) --59 + j*(-81) -41 + j*(-2) -23 + j*(-161) --189 + j*(-74) --52 + j*(148) -144 + j*(-46) --123 + j*(-207) --264 + j*(122) -91 + j*(254) -206 + j*(-91) --107 + j*(-187) --196 + j*(83) -6 + j*(176) -105 + j*(62) -81 + j*(-24) -15 + j*(-57) --35 + j*(6) -52 + j*(47) -86 + j*(-85) --80 + j*(-120) --107 + j*(52) -46 + j*(39) --36 + j*(-94) --171 + j*(52) -12 + j*(190) -124 + j*(6) --62 + j*(-54) --77 + j*(151) -130 + j*(168) -180 + j*(26) -166 + j*(-25) -178 + j*(-141) --4 + j*(-233) --127 + j*(-46) -69 + j*(38) -97 + j*(-207) --206 + j*(-209) --213 + j*(114) -80 + j*(118) -58 + j*(-122) --129 + j*(-64) --42 + j*(75) -59 + j*(-29) --37 + j*(-95) --54 + j*(-34) --23 + j*(-101) --174 + j*(-157) --306 + j*(5) --240 + j*(180) --135 + j*(243) --26 + j*(291) -132 + j*(257) -208 + j*(124) -208 + j*(8) -157 + j*(-139) --93 + j*(-210) --298 + j*(95) -19 + j*(426) -450 + j*(151) -264 + j*(-317) --165 + j*(-221) --127 + j*(117) -110 + j*(104) -114 + j*(-34) -76 + j*(-50) -64 + j*(-108) --61 + j*(-112) --74 + j*(44) -88 + j*(50) -76 + j*(-103) --59 + j*(-65) -11 + j*(50) -115 + j*(-42) -33 + j*(-141) --35 + j*(-100) --25 + j*(-98) --86 + j*(-113) --129 + j*(-36) --80 + j*(10) --71 + j*(-4) --76 + j*(33) --16 + j*(42) --2 + j*(-22) --56 + j*(-44) --93 + j*(-27) --144 + j*(9) --151 + j*(122) --30 + j*(186) -37 + j*(105) --25 + j*(115) -68 + j*(235) -293 + j*(144) -298 + j*(-127) -99 + j*(-245) --52 + j*(-191) --116 + j*(-89) --85 + j*(19) -25 + j*(21) -33 + j*(-80) --43 + j*(-100) --53 + j*(-90) --119 + j*(-156) --303 + j*(-93) --355 + j*(148) --214 + j*(329) --27 + j*(395) -199 + j*(349) -314 + j*(112) -151 + j*(-49) -52 + j*(86) -244 + j*(121) -284 + j*(-127) -49 + j*(-185) -27 + j*(2) -211 + j*(-42) -151 + j*(-265) --82 + j*(-264) --145 + j*(-88) --41 + j*(-4) -49 + j*(-73) --9 + j*(-200) --190 + j*(-180) --232 + j*(2) --119 + j*(68) --112 + j*(33) --122 + j*(126) -45 + j*(161) -108 + j*(-21) --56 + j*(-84) --106 + j*(52) --6 + j*(88) -16 + j*(47) -35 + j*(50) -67 + j*(-11) --2 + j*(-44) -1 + j*(21) -67 + j*(-56) --99 + j*(-135) --204 + j*(109) -81 + j*(243) -216 + j*(-44) --47 + j*(-130) -64 + j*(-24) -41 + j*(-137) --82 + j*(-142) --141 + j*(-64) --153 + j*(28) --67 + j*(131) -93 + j*(62) -26 + j*(-125) --173 + j*(-42) --63 + j*(158) -138 + j*(8) --60 + j*(-206) --307 + j*(6) --136 + j*(267) -69 + j*(159) --29 + j*(66) --37 + j*(230) -202 + j*(243) -265 + j*(5) -98 + j*(-65) -90 + j*(48) -213 + j*(-6) -160 + j*(-149) -56 + j*(-121) -119 + j*(-106) -91 + j*(-280) --187 + j*(-302) --305 + j*(-4) --69 + j*(175) -116 + j*(18) -30 + j*(-141) --93 + j*(-135) --163 + j*(-81) --216 + j*(28) --139 + j*(171) -18 + j*(165) -49 + j*(78) -57 + j*(83) -155 + j*(21) -103 + j*(-164) --122 + j*(-168) --175 + j*(40) --28 + j*(109) -23 + j*(23) --23 + j*(6) --10 + j*(32) -2 + j*(1) --35 + j*(-1) --23 + j*(35) -13 + j*(-4) --66 + j*(-68) --210 + j*(28) --175 + j*(274) -111 + j*(379) -349 + j*(170) -293 + j*(-82) -161 + j*(-128) -151 + j*(-157) -40 + j*(-276) --187 + j*(-195) --172 + j*(47) -14 + j*(54) --13 + j*(-79) --132 + j*(-13) --64 + j*(110) -35 + j*(85) -52 + j*(49) -99 + j*(15) -79 + j*(-91) --39 + j*(-89) --27 + j*(5) -39 + j*(-52) --76 + j*(-105) --136 + j*(44) -11 + j*(106) -51 + j*(-4) --18 + j*(1) -37 + j*(23) -4 + j*(-74) --138 + j*(35) -53 + j*(249) -366 + j*(14) -157 + j*(-379) --248 + j*(-250) --188 + j*(83) -41 + j*(38) --22 + j*(-115) --141 + j*(-55) --129 + j*(31) --105 + j*(80) --28 + j*(122) -49 + j*(49) --32 + j*(-14) --62 + j*(99) -91 + j*(110) -94 + j*(-57) --52 + j*(-32) -41 + j*(77) -134 + j*(-120) --168 + j*(-247) --377 + j*(124) --13 + j*(419) -333 + j*(126) -125 + j*(-203) --144 + j*(-54) --21 + j*(157) -153 + j*(50) -77 + j*(-89) --10 + j*(-42) -33 + j*(-24) --8 + j*(-95) --121 + j*(-30) --54 + j*(96) -50 + j*(21) --81 + j*(-54) --167 + j*(165) -110 + j*(319) -340 + j*(62) -156 + j*(-168) -14 + j*(-24) -199 + j*(27) -245 + j*(-236) --26 + j*(-341) --163 + j*(-165) --98 + j*(-92) --140 + j*(-118) --202 + j*(-4) --97 + j*(97) --11 + j*(29) --64 + j*(-8) --75 + j*(61) -6 + j*(84) -62 + j*(32) -72 + j*(-46) -13 + j*(-127) --112 + j*(-111) --132 + j*(13) --25 + j*(25) --56 + j*(-96) --250 + j*(-49) --264 + j*(226) -14 + j*(361) -247 + j*(173) -189 + j*(-72) -2 + j*(-122) --89 + j*(-29) --75 + j*(69) --3 + j*(126) -95 + j*(119) -141 + j*(39) -118 + j*(-20) -115 + j*(-37) -116 + j*(-103) -31 + j*(-166) --64 + j*(-118) --65 + j*(-54) --66 + j*(-45) --90 + j*(16) -6 + j*(77) -94 + j*(-42) --61 + j*(-146) --194 + j*(41) -13 + j*(211) -212 + j*(1) -8 + j*(-216) --228 + j*(-27) --75 + j*(230) -174 + j*(141) -160 + j*(-45) -83 + j*(-62) -115 + j*(-94) -39 + j*(-226) --177 + j*(-192) --229 + j*(41) --44 + j*(156) -86 + j*(37) -6 + j*(-76) --101 + j*(-11) --45 + j*(110) -105 + j*(72) -92 + j*(-110) --130 + j*(-128) --197 + j*(137) -96 + j*(279) -316 + j*(0) -93 + j*(-269) --172 + j*(-113) --61 + j*(115) -125 + j*(30) -73 + j*(-115) -4 + j*(-102) -11 + j*(-150) --149 + j*(-238) --384 + j*(-59) --305 + j*(295) -54 + j*(376) -254 + j*(119) -124 + j*(-99) --45 + j*(-50) --22 + j*(57) -33 + j*(26) --25 + j*(24) -21 + j*(144) -226 + j*(79) -194 + j*(-200) --114 + j*(-233) --198 + j*(49) -19 + j*(156) -126 + j*(13) -56 + j*(-76) --11 + j*(-73) --66 + j*(-25) --28 + j*(86) -134 + j*(58) -122 + j*(-135) --61 + j*(-136) --48 + j*(8) -57 + j*(-56) --45 + j*(-141) --107 + j*(-39) --30 + j*(-52) --159 + j*(-131) --292 + j*(89) --57 + j*(279) -117 + j*(89) --38 + j*(10) -1 + j*(186) -231 + j*(69) -86 + j*(-197) --174 + j*(-53) --38 + j*(173) -136 + j*(46) -21 + j*(-68) --37 + j*(43) -69 + j*(60) -68 + j*(-39) --21 + j*(-29) --25 + j*(62) -76 + j*(116) -218 + j*(29) -185 + j*(-206) --100 + j*(-251) --214 + j*(39) -54 + j*(186) -209 + j*(-40) -37 + j*(-188) --83 + j*(-73) --18 + j*(6) -35 + j*(-20) -56 + j*(-64) -25 + j*(-142) --98 + j*(-144) --122 + j*(-19) --17 + j*(-11) --58 + j*(-113) --182 + j*(-39) --112 + j*(105) -23 + j*(50) --20 + j*(-59) --103 + j*(-37) --104 + j*(3) --135 + j*(6) --189 + j*(83) --144 + j*(216) -12 + j*(267) -136 + j*(172) -117 + j*(60) -77 + j*(79) -180 + j*(68) -186 + j*(-144) --102 + j*(-214) --239 + j*(102) -61 + j*(281) -254 + j*(25) -56 + j*(-141) --49 + j*(6) -57 + j*(30) --7 + j*(-59) --101 + j*(93) -103 + j*(225) -279 + j*(25) -134 + j*(-156) -2 + j*(-59) -90 + j*(11) -130 + j*(-89) -39 + j*(-122) -33 + j*(-61) -78 + j*(-105) --21 + j*(-170) --120 + j*(-28) -64 + j*(127) -313 + j*(-81) -153 + j*(-427) --210 + j*(-384) --231 + j*(-131) --118 + j*(-202) --387 + j*(-298) --633 + j*(100) --279 + j*(514) -172 + j*(310) -67 + j*(-50) --197 + j*(56) --66 + j*(297) -193 + j*(192) -164 + j*(-54) --28 + j*(-98) --116 + j*(18) --81 + j*(117) --19 + j*(151) -37 + j*(168) -129 + j*(162) -209 + j*(63) -163 + j*(-70) -45 + j*(-78) -25 + j*(6) -100 + j*(17) -131 + j*(-62) -88 + j*(-138) --5 + j*(-174) --111 + j*(-132) --146 + j*(-30) --123 + j*(44) --94 + j*(106) -11 + j*(177) -171 + j*(91) -123 + j*(-115) --89 + j*(-86) --54 + j*(130) -180 + j*(79) -123 + j*(-181) --157 + j*(-134) --135 + j*(154) -141 + j*(170) -193 + j*(-69) -15 + j*(-131) --30 + j*(-1) -87 + j*(23) -130 + j*(-98) -33 + j*(-192) --98 + j*(-163) --141 + j*(-40) --41 + j*(35) -35 + j*(-76) --122 + j*(-187) --322 + j*(-10) --206 + j*(290) -116 + j*(298) -231 + j*(49) -106 + j*(-91) -16 + j*(-54) -35 + j*(-28) -39 + j*(-62) -7 + j*(-80) --8 + j*(-82) --33 + j*(-113) --124 + j*(-127) --225 + j*(-24) --181 + j*(148) --6 + j*(187) -78 + j*(68) -18 + j*(-5) --16 + j*(27) -11 + j*(34) -21 + j*(15) -33 + j*(-19) --19 + j*(-102) --199 + j*(-66) --223 + j*(192) -48 + j*(288) -165 + j*(59) --33 + j*(-6) --26 + j*(218) -255 + j*(191) -272 + j*(-114) -8 + j*(-186) --96 + j*(-7) --14 + j*(115) -115 + j*(137) -253 + j*(25) -185 + j*(-202) --76 + j*(-175) --47 + j*(91) -243 + j*(33) -178 + j*(-313) --200 + j*(-301) --272 + j*(54) --1 + j*(194) -169 + j*(40) -136 + j*(-121) -37 + j*(-179) --43 + j*(-160) --63 + j*(-138) --114 + j*(-163) --235 + j*(-103) --231 + j*(80) --65 + j*(129) --11 + j*(6) --116 + j*(-33) --173 + j*(54) --153 + j*(148) --80 + j*(243) -95 + j*(272) -233 + j*(119) -171 + j*(-49) -55 + j*(-51) -62 + j*(1) -98 + j*(-42) -52 + j*(-112) --40 + j*(-102) --72 + j*(-16) -1 + j*(43) -81 + j*(-20) -53 + j*(-125) --43 + j*(-179) --188 + j*(-168) --325 + j*(2) --218 + j*(263) -74 + j*(243) -76 + j*(-13) --163 + j*(36) --66 + j*(303) -223 + j*(214) -158 + j*(-27) -11 + j*(62) -166 + j*(144) -234 + j*(-49) -67 + j*(-89) -112 + j*(40) -257 + j*(-106) -83 + j*(-316) --161 + j*(-204) --150 + j*(-12) --67 + j*(54) -35 + j*(88) -170 + j*(-28) -55 + j*(-238) --200 + j*(-151) --151 + j*(99) -42 + j*(74) -9 + j*(-31) --1 + j*(45) -143 + j*(-13) -63 + j*(-231) --192 + j*(-179) --185 + j*(47) --30 + j*(47) --66 + j*(-51) --162 + j*(28) --84 + j*(158) -79 + j*(127) -111 + j*(-55) --77 + j*(-161) --276 + j*(13) --178 + j*(303) -132 + j*(349) -320 + j*(135) -297 + j*(-108) -119 + j*(-267) --125 + j*(-216) --168 + j*(18) -16 + j*(81) -48 + j*(-74) --92 + j*(-81) --94 + j*(18) --81 + j*(-3) --179 + j*(80) --57 + j*(281) -202 + j*(188) -150 + j*(-26) -40 + j*(47) -203 + j*(78) -226 + j*(-163) -0 + j*(-209) --13 + j*(-86) -6 + j*(-194) --262 + j*(-181) --286 + j*(189) -80 + j*(265) -151 + j*(-21) --35 + j*(-16) -78 + j*(108) -181 + j*(-91) --48 + j*(-185) --113 + j*(24) -58 + j*(37) -21 + j*(-93) --57 + j*(-22) -38 + j*(-23) --54 + j*(-161) --253 + j*(-11) --105 + j*(243) -149 + j*(144) -117 + j*(-54) -15 + j*(-83) --57 + j*(-91) --180 + j*(6) --98 + j*(235) -189 + j*(204) -222 + j*(-64) -36 + j*(-125) --2 + j*(-39) -12 + j*(-47) --20 + j*(-14) -54 + j*(13) -81 + j*(-112) --78 + j*(-156) --151 + j*(-22) --98 + j*(49) --86 + j*(112) -76 + j*(211) -308 + j*(4) -122 + j*(-337) --262 + j*(-223) --233 + j*(119) -6 + j*(144) -40 + j*(33) -45 + j*(11) -43 + j*(-90) --130 + j*(-105) --162 + j*(110) -53 + j*(146) -67 + j*(-40) --78 + j*(-10) --3 + j*(91) -42 + j*(-25) --122 + j*(-4) --47 + j*(221) -228 + j*(124) -138 + j*(-163) --124 + j*(-83) --40 + j*(128) -112 + j*(25) --30 + j*(-65) --81 + j*(145) -210 + j*(213) -359 + j*(-129) -35 + j*(-382) --292 + j*(-139) --144 + j*(200) -153 + j*(124) -97 + j*(-101) --52 + j*(-10) -112 + j*(100) -239 + j*(-129) -11 + j*(-296) --152 + j*(-137) --54 + j*(-61) --98 + j*(-168) --269 + j*(-66) --192 + j*(139) --30 + j*(98) --91 + j*(12) --161 + j*(124) --47 + j*(248) -115 + j*(233) -236 + j*(119) -250 + j*(-72) -95 + j*(-197) --52 + j*(-136) --57 + j*(-49) --47 + j*(-37) --54 + j*(-12) --31 + j*(-16) --93 + j*(-37) --151 + j*(93) -11 + j*(206) -153 + j*(60) -35 + j*(-54) --14 + j*(54) -110 + j*(35) -32 + j*(-99) --103 + j*(47) -114 + j*(197) -316 + j*(-71) -65 + j*(-332) --214 + j*(-156) --134 + j*(71) --4 + j*(54) -1 + j*(30) -66 + j*(43) -121 + j*(-80) --9 + j*(-190) --156 + j*(-113) --150 + j*(11) --104 + j*(44) --106 + j*(69) --71 + j*(145) -52 + j*(167) -144 + j*(62) -97 + j*(-61) --7 + j*(-66) --28 + j*(-11) --20 + j*(-7) --63 + j*(14) --44 + j*(110) -88 + j*(124) -147 + j*(-8) -36 + j*(-94) --58 + j*(1) -39 + j*(115) -204 + j*(23) -161 + j*(-202) --83 + j*(-239) --188 + j*(-33) --38 + j*(81) -49 + j*(-44) --83 + j*(-132) --227 + j*(-7) --192 + j*(210) -33 + j*(340) -315 + j*(206) -324 + j*(-126) -49 + j*(-216) --6 + j*(-18) -190 + j*(-70) -64 + j*(-332) --242 + j*(-202) --119 + j*(66) -68 + j*(-121) --240 + j*(-272) --431 + j*(117) --62 + j*(359) -168 + j*(81) --14 + j*(-62) --42 + j*(56) -35 + j*(-28) --143 + j*(-83) --199 + j*(154) -36 + j*(207) -38 + j*(9) --150 + j*(108) -25 + j*(344) -317 + j*(180) -221 + j*(-98) -23 + j*(-40) -105 + j*(94) -245 + j*(-13) -183 + j*(-194) -4 + j*(-231) --112 + j*(-112) --64 + j*(18) -39 + j*(7) -29 + j*(-66) --8 + j*(-44) -40 + j*(-46) -14 + j*(-140) --119 + j*(-122) --127 + j*(6) --47 + j*(11) --90 + j*(-26) --123 + j*(74) --8 + j*(132) -60 + j*(39) --11 + j*(-6) --38 + j*(69) -47 + j*(123) -156 + j*(77) -216 + j*(-64) -124 + j*(-233) --90 + j*(-257) --214 + j*(-104) --177 + j*(40) --98 + j*(95) --26 + j*(106) -40 + j*(76) -68 + j*(6) -35 + j*(-67) --59 + j*(-93) --153 + j*(0) --78 + j*(149) -103 + j*(101) -69 + j*(-101) --152 + j*(-82) --163 + j*(154) -59 + j*(207) -144 + j*(28) -11 + j*(-62) --85 + j*(35) --25 + j*(155) -107 + j*(158) -172 + j*(62) -152 + j*(-12) -137 + j*(-38) -126 + j*(-89) -62 + j*(-109) -65 + j*(-64) -127 + j*(-144) --11 + j*(-286) --241 + j*(-156) --163 + j*(96) -54 + j*(46) --8 + j*(-119) --135 + j*(-46) --76 + j*(45) --47 + j*(12) --54 + j*(60) -71 + j*(45) -36 + j*(-161) --245 + j*(-125) --243 + j*(197) -57 + j*(221) -52 + j*(-16) --157 + j*(70) --7 + j*(316) -300 + j*(180) -240 + j*(-146) --49 + j*(-164) --121 + j*(78) -91 + j*(207) -287 + j*(41) -203 + j*(-204) --25 + j*(-200) --50 + j*(-33) -74 + j*(-29) -61 + j*(-146) --47 + j*(-156) --89 + j*(-97) --93 + j*(-52) --59 + j*(-19) --25 + j*(-72) --133 + j*(-123) --226 + j*(28) --69 + j*(151) -38 + j*(-12) --158 + j*(-95) --256 + j*(132) --58 + j*(262) -54 + j*(157) -24 + j*(139) -112 + j*(168) -187 + j*(37) -86 + j*(-59) -16 + j*(0) -59 + j*(20) -46 + j*(-21) --2 + j*(8) -18 + j*(72) -103 + j*(110) -242 + j*(49) -283 + j*(-177) -63 + j*(-349) --171 + j*(-238) --180 + j*(-73) --181 + j*(-31) --218 + j*(127) -13 + j*(308) -317 + j*(100) -180 + j*(-249) --138 + j*(-177) --78 + j*(81) -146 + j*(-2) -57 + j*(-236) --176 + j*(-192) --194 + j*(-18) --125 + j*(-6) --196 + j*(-15) --239 + j*(140) --93 + j*(263) -40 + j*(199) -26 + j*(161) -98 + j*(230) -284 + j*(135) -255 + j*(-117) -28 + j*(-158) --29 + j*(-4) -69 + j*(37) -98 + j*(-4) -141 + j*(-21) -175 + j*(-158) --8 + j*(-275) --180 + j*(-100) --18 + j*(64) -117 + j*(-118) --94 + j*(-255) --248 + j*(-61) --112 + j*(74) --43 + j*(-29) --158 + j*(-42) --182 + j*(93) --77 + j*(161) -21 + j*(132) -57 + j*(35) --44 + j*(-43) --165 + j*(81) --31 + j*(267) -203 + j*(157) -128 + j*(-79) --87 + j*(-9) --4 + j*(209) -245 + j*(149) -262 + j*(-107) -58 + j*(-215) --103 + j*(-107) --89 + j*(53) -44 + j*(110) -147 + j*(25) -136 + j*(-93) -44 + j*(-163) --94 + j*(-143) --162 + j*(35) -33 + j*(192) -276 + j*(1) -118 + j*(-319) --238 + j*(-221) --201 + j*(113) -76 + j*(107) -74 + j*(-97) --54 + j*(-91) --29 + j*(-59) --99 + j*(-143) --282 + j*(-12) --161 + j*(262) -140 + j*(199) -129 + j*(-60) --64 + j*(-62) --53 + j*(68) -25 + j*(51) -6 + j*(24) -28 + j*(52) -80 + j*(-8) -14 + j*(-88) --90 + j*(-59) --140 + j*(35) --114 + j*(186) -98 + j*(286) -330 + j*(91) -204 + j*(-202) --58 + j*(-122) -52 + j*(80) -236 + j*(-100) -20 + j*(-310) --190 + j*(-115) --12 + j*(36) -76 + j*(-176) --187 + j*(-270) --344 + j*(-37) --238 + j*(147) --126 + j*(180) --33 + j*(186) -35 + j*(103) --52 + j*(49) --85 + j*(202) -136 + j*(264) -256 + j*(45) -103 + j*(-90) -21 + j*(-9) -54 + j*(-2) --6 + j*(-4) -35 + j*(121) -237 + j*(49) -168 + j*(-221) --132 + j*(-182) --128 + j*(100) -96 + j*(123) -135 + j*(-8) -127 + j*(-30) -165 + j*(-132) -10 + j*(-247) --133 + j*(-87) -42 + j*(19) -100 + j*(-223) --222 + j*(-286) --333 + j*(62) --33 + j*(204) -95 + j*(-21) --64 + j*(-117) --130 + j*(-28) --133 + j*(-2) --188 + j*(76) --101 + j*(226) -95 + j*(206) -155 + j*(47) -94 + j*(-64) --34 + j*(-110) --178 + j*(15) --74 + j*(246) -210 + j*(184) -187 + j*(-86) --14 + j*(-54) -100 + j*(81) -223 + j*(-134) --47 + j*(-290) --216 + j*(-41) --10 + j*(69) --2 + j*(-136) --267 + j*(-77) --235 + j*(247) -64 + j*(313) -211 + j*(148) -238 + j*(6) -191 + j*(-171) --45 + j*(-252) --218 + j*(-37) --59 + j*(169) -144 + j*(66) -88 + j*(-122) --86 + j*(-115) --136 + j*(40) --5 + j*(144) -148 + j*(40) -75 + j*(-150) --138 + j*(-115) --154 + j*(91) --1 + j*(159) -87 + j*(103) -144 + j*(42) -158 + j*(-103) --23 + j*(-199) --171 + j*(-38) --54 + j*(110) -37 + j*(25) --58 + j*(23) -9 + j*(170) -218 + j*(90) -172 + j*(-133) --3 + j*(-113) -45 + j*(-8) -119 + j*(-112) --10 + j*(-196) --89 + j*(-106) --42 + j*(-93) --127 + j*(-153) --262 + j*(-16) --144 + j*(182) -47 + j*(115) --1 + j*(-23) --86 + j*(62) -46 + j*(127) -110 + j*(-31) --53 + j*(-82) --69 + j*(88) -113 + j*(64) -59 + j*(-134) --136 + j*(-60) --41 + j*(107) -82 + j*(-21) --89 + j*(-90) --97 + j*(122) -169 + j*(59) -45 + j*(-286) --397 + j*(-161) --355 + j*(334) -84 + j*(410) -231 + j*(128) -119 + j*(5) -63 + j*(3) -4 + j*(25) -30 + j*(139) -221 + j*(116) -240 + j*(-124) -23 + j*(-187) --40 + j*(-53) -13 + j*(-55) --84 + j*(-57) --74 + j*(125) -165 + j*(130) -197 + j*(-127) --37 + j*(-181) --86 + j*(2) -45 + j*(20) -16 + j*(-74) --71 + j*(1) -35 + j*(109) -179 + j*(11) -139 + j*(-147) -26 + j*(-174) --8 + j*(-152) --52 + j*(-191) --188 + j*(-172) --266 + j*(3) --136 + j*(168) -52 + j*(132) -100 + j*(-23) -17 + j*(-127) --110 + j*(-131) --202 + j*(-24) --151 + j*(117) --20 + j*(118) --13 + j*(30) --76 + j*(63) --2 + j*(139) -105 + j*(52) -33 + j*(-74) --95 + j*(-33) --92 + j*(82) --8 + j*(115) -42 + j*(70) -19 + j*(27) --23 + j*(67) -59 + j*(145) -216 + j*(42) -144 + j*(-204) --153 + j*(-209) --245 + j*(70) --40 + j*(204) -59 + j*(79) --44 + j*(63) -1 + j*(219) -226 + j*(186) -257 + j*(-53) -64 + j*(-124) -5 + j*(14) -122 + j*(37) -124 + j*(-71) -35 + j*(-55) -83 + j*(21) -177 + j*(-45) -146 + j*(-151) -92 + j*(-190) -26 + j*(-250) --139 + j*(-231) --185 + j*(-25) -24 + j*(56) -122 + j*(-159) --81 + j*(-301) --264 + j*(-180) --276 + j*(-36) --257 + j*(64) --177 + j*(170) --37 + j*(166) --4 + j*(84) --8 + j*(76) -38 + j*(30) --32 + j*(-66) --163 + j*(13) --101 + j*(153) -1 + j*(117) --42 + j*(90) --12 + j*(180) -119 + j*(151) -118 + j*(46) -96 + j*(48) -146 + j*(-9) -49 + j*(-115) --74 + j*(-1) -65 + j*(105) -148 + j*(-71) --60 + j*(-138) --116 + j*(88) -109 + j*(135) -158 + j*(-69) -0 + j*(-125) --55 + j*(-34) --37 + j*(9) --11 + j*(54) -79 + j*(37) -63 + j*(-92) --106 + j*(-74) --110 + j*(134) -105 + j*(196) -244 + j*(34) -192 + j*(-152) -17 + j*(-219) --125 + j*(-83) --1 + j*(95) -216 + j*(-44) -77 + j*(-322) --231 + j*(-233) --198 + j*(36) --13 + j*(4) --98 + j*(-134) --258 + j*(-17) --184 + j*(182) -8 + j*(197) -91 + j*(61) -1 + j*(-35) --86 + j*(46) -16 + j*(127) -89 + j*(-1) --80 + j*(-47) --95 + j*(187) -206 + j*(194) -231 + j*(-133) --62 + j*(-153) --21 + j*(76) -164 + j*(-67) --66 + j*(-256) --270 + j*(-5) --62 + j*(169) -6 + j*(22) --118 + j*(103) -91 + j*(258) -290 + j*(-17) -15 + j*(-226) --156 + j*(23) -66 + j*(129) -97 + j*(-69) --72 + j*(-26) -34 + j*(121) -175 + j*(-28) -25 + j*(-163) --91 + j*(-52) --42 + j*(16) --49 + j*(22) --19 + j*(124) -164 + j*(124) -243 + j*(-84) -98 + j*(-250) --100 + j*(-234) --218 + j*(-77) --147 + j*(123) -78 + j*(139) -161 + j*(-71) -4 + j*(-197) --129 + j*(-128) --143 + j*(-45) --141 + j*(2) --122 + j*(45) --107 + j*(54) --117 + j*(101) --40 + j*(161) -40 + j*(84) --67 + j*(37) --97 + j*(231) -188 + j*(313) -370 + j*(17) -158 + j*(-226) --66 + j*(-129) --54 + j*(23) -35 + j*(68) -139 + j*(27) -158 + j*(-143) --45 + j*(-235) --185 + j*(-54) --51 + j*(61) --35 + j*(-49) --178 + j*(45) --4 + j*(259) -267 + j*(54) -59 + j*(-241) --228 + j*(-37) --34 + j*(224) -180 + j*(54) -35 + j*(-87) --25 + j*(50) -119 + j*(49) -84 + j*(-80) -0 + j*(-6) -139 + j*(39) -206 + j*(-162) -13 + j*(-283) --124 + j*(-184) --116 + j*(-117) --155 + j*(-119) --226 + j*(-56) --247 + j*(66) --173 + j*(209) -42 + j*(250) -177 + j*(32) --29 + j*(-141) --209 + j*(83) -45 + j*(274) -258 + j*(11) -16 + j*(-204) --165 + j*(-1) --2 + j*(117) -32 + j*(-23) --111 + j*(28) --8 + j*(192) -165 + j*(91) -99 + j*(-37) -73 + j*(5) -147 + j*(-90) --31 + j*(-238) --258 + j*(-49) --117 + j*(214) -118 + j*(139) -89 + j*(-19) -11 + j*(0) -40 + j*(21) -35 + j*(-11) -9 + j*(13) -49 + j*(36) -94 + j*(3) -107 + j*(-69) -24 + j*(-164) --161 + j*(-100) --141 + j*(158) -157 + j*(201) -267 + j*(-76) -83 + j*(-209) -10 + j*(-151) --16 + j*(-212) --202 + j*(-191) --211 + j*(35) --29 + j*(13) --168 + j*(-146) --388 + j*(119) --94 + j*(441) -273 + j*(221) -144 + j*(-82) --36 + j*(16) -87 + j*(100) -141 + j*(-43) -18 + j*(-96) --24 + j*(-37) --25 + j*(-23) --53 + j*(13) --23 + j*(74) -40 + j*(106) -163 + j*(103) -291 + j*(-91) -100 + j*(-375) --272 + j*(-255) --221 + j*(100) -53 + j*(44) --82 + j*(-169) --295 + j*(35) --92 + j*(264) -97 + j*(131) -34 + j*(59) -103 + j*(104) -171 + j*(-62) --25 + j*(-145) --67 + j*(46) -138 + j*(-2) -1 + j*(-266) --345 + j*(-102) --222 + j*(293) -151 + j*(245) -151 + j*(-49) --62 + j*(-60) --69 + j*(107) -81 + j*(129) -144 + j*(-4) -32 + j*(-121) --141 + j*(-47) --134 + j*(176) -87 + j*(270) -281 + j*(137) -303 + j*(-72) -185 + j*(-235) --19 + j*(-260) --150 + j*(-108) --71 + j*(45) -59 + j*(11) -47 + j*(-105) --69 + j*(-129) --163 + j*(-31) --121 + j*(141) -97 + j*(195) -257 + j*(-18) -95 + j*(-258) --180 + j*(-167) --146 + j*(113) -137 + j*(120) -197 + j*(-177) --105 + j*(-314) --317 + j*(-47) --110 + j*(209) -154 + j*(55) -45 + j*(-206) --199 + j*(-161) --227 + j*(14) --176 + j*(76) --161 + j*(139) --66 + j*(207) -28 + j*(161) -32 + j*(127) -88 + j*(130) -134 + j*(21) -21 + j*(-32) -13 + j*(87) -168 + j*(25) -63 + j*(-192) --204 + j*(-83) --122 + j*(182) -84 + j*(126) -18 + j*(18) --4 + j*(131) -150 + j*(105) -93 + j*(-37) --3 + j*(91) -233 + j*(173) -367 + j*(-139) -78 + j*(-336) --112 + j*(-143) --4 + j*(-45) --9 + j*(-131) --103 + j*(-71) --32 + j*(-3) --30 + j*(-91) --170 + j*(-27) --76 + j*(189) -197 + j*(115) -184 + j*(-183) --89 + j*(-236) --194 + j*(-35) --69 + j*(81) -33 + j*(7) --21 + j*(-98) --161 + j*(-71) --204 + j*(107) --37 + j*(241) -161 + j*(144) -149 + j*(-46) -23 + j*(-83) --8 + j*(-36) --11 + j*(-44) --68 + j*(-16) --21 + j*(86) -132 + j*(37) -116 + j*(-173) --110 + j*(-238) --264 + j*(-83) --255 + j*(90) --177 + j*(215) --18 + j*(296) -179 + j*(214) -214 + j*(6) -68 + j*(-100) --61 + j*(-35) --76 + j*(94) -28 + j*(204) -221 + j*(187) -339 + j*(-5) -269 + j*(-218) -93 + j*(-317) --90 + j*(-290) --208 + j*(-153) --174 + j*(-4) --92 + j*(18) --100 + j*(8) --82 + j*(83) -41 + j*(72) -41 + j*(-76) --122 + j*(-94) --178 + j*(50) --107 + j*(134) --55 + j*(170) -46 + j*(211) -180 + j*(128) -154 + j*(-30) -33 + j*(-28) -62 + j*(72) -199 + j*(27) -215 + j*(-164) -37 + j*(-307) --204 + j*(-242) --288 + j*(-9) --171 + j*(158) --47 + j*(177) -31 + j*(182) -157 + j*(148) -211 + j*(-5) -117 + j*(-101) -71 + j*(-81) -66 + j*(-141) --81 + j*(-169) --163 + j*(18) -25 + j*(127) -137 + j*(-39) -8 + j*(-131) --37 + j*(-42) -28 + j*(-64) --48 + j*(-138) --127 + j*(-55) --64 + j*(-16) --105 + j*(-90) --244 + j*(19) --136 + j*(239) -115 + j*(183) -109 + j*(-37) --54 + j*(-30) --6 + j*(98) -125 + j*(0) --4 + j*(-169) --224 + j*(-39) --127 + j*(221) -142 + j*(183) -163 + j*(-52) -3 + j*(-110) --57 + j*(-47) --82 + j*(-33) --137 + j*(42) --74 + j*(148) -19 + j*(119) --8 + j*(95) -24 + j*(173) -148 + j*(144) -152 + j*(57) -177 + j*(71) -301 + j*(-57) -147 + j*(-323) --212 + j*(-216) --170 + j*(158) -158 + j*(166) -208 + j*(-74) -96 + j*(-134) -68 + j*(-169) --72 + j*(-209) --172 + j*(-21) -32 + j*(85) -112 + j*(-146) --152 + j*(-204) --201 + j*(76) -69 + j*(110) -78 + j*(-144) --173 + j*(-148) --206 + j*(94) -5 + j*(179) -146 + j*(25) -59 + j*(-169) --175 + j*(-153) --226 + j*(95) -10 + j*(196) -125 + j*(-16) --63 + j*(-127) --161 + j*(30) --50 + j*(101) --45 + j*(33) --116 + j*(107) -6 + j*(240) -213 + j*(154) -223 + j*(-80) -44 + j*(-195) --124 + j*(-118) --154 + j*(23) --95 + j*(109) --25 + j*(144) -65 + j*(130) -93 + j*(28) --23 + j*(3) --41 + j*(175) -191 + j*(228) -316 + j*(4) -185 + j*(-139) -129 + j*(-107) -139 + j*(-197) --44 + j*(-263) --156 + j*(-78) --8 + j*(11) -12 + j*(-128) --142 + j*(-95) --98 + j*(57) -14 + j*(12) --44 + j*(-38) --41 + j*(38) -37 + j*(-1) --17 + j*(-58) --8 + j*(2) -69 + j*(-117) --173 + j*(-255) --416 + j*(61) --106 + j*(380) -202 + j*(123) --37 + j*(-95) --159 + j*(194) -202 + j*(280) -305 + j*(-110) --48 + j*(-237) --175 + j*(40) -17 + j*(151) -99 + j*(49) -89 + j*(11) -108 + j*(-40) -42 + j*(-106) --22 + j*(-56) -32 + j*(-42) --19 + j*(-139) --181 + j*(-54) --98 + j*(169) -161 + j*(101) -119 + j*(-177) --168 + j*(-175) --224 + j*(81) --42 + j*(186) -69 + j*(107) -79 + j*(40) -71 + j*(-13) -8 + j*(-39) --18 + j*(30) -74 + j*(40) -71 + j*(-88) --93 + j*(-84) --103 + j*(117) -117 + j*(165) -234 + j*(-37) -115 + j*(-219) --88 + j*(-229) --228 + j*(-66) --147 + j*(160) -113 + j*(151) -153 + j*(-106) --80 + j*(-168) --131 + j*(13) --11 + j*(6) --115 + j*(-80) --220 + j*(122) -30 + j*(283) -231 + j*(51) -51 + j*(-148) --115 + j*(-27) --54 + j*(92) -1 + j*(101) -71 + j*(133) -204 + j*(47) -149 + j*(-150) --49 + j*(-141) --57 + j*(23) -74 + j*(31) -106 + j*(-79) -54 + j*(-171) --86 + j*(-245) --306 + j*(-141) --325 + j*(156) --70 + j*(288) -83 + j*(156) -46 + j*(88) -86 + j*(115) -158 + j*(23) -77 + j*(-86) --24 + j*(-36) -1 + j*(38) -54 + j*(31) -68 + j*(4) -74 + j*(-21) -71 + j*(-45) -72 + j*(-72) -45 + j*(-136) --73 + j*(-156) --146 + j*(-31) --47 + j*(54) -6 + j*(-28) --95 + j*(-40) --88 + j*(93) -56 + j*(94) -69 + j*(-23) -12 + j*(-25) -54 + j*(-30) -16 + j*(-139) --152 + j*(-108) --157 + j*(76) --4 + j*(113) -44 + j*(16) -5 + j*(-21) --18 + j*(-37) --75 + j*(-35) --98 + j*(37) --44 + j*(64) --59 + j*(38) --85 + j*(127) -62 + j*(199) -191 + j*(50) -99 + j*(-103) --20 + j*(-98) --95 + j*(-77) --221 + j*(28) --174 + j*(302) -161 + j*(393) -378 + j*(131) -269 + j*(-100) -143 + j*(-91) -175 + j*(-71) -202 + j*(-180) -83 + j*(-320) --159 + j*(-292) --243 + j*(-25) -6 + j*(103) -125 + j*(-158) --182 + j*(-278) --330 + j*(53) --28 + j*(209) -87 + j*(-44) --133 + j*(-98) --148 + j*(98) --8 + j*(100) --25 + j*(47) -15 + j*(103) -116 + j*(-4) --33 + j*(-134) --166 + j*(30) --9 + j*(145) -65 + j*(6) --54 + j*(-18) --39 + j*(66) --13 + j*(16) --127 + j*(62) --58 + j*(260) -182 + j*(251) -255 + j*(86) -262 + j*(12) -310 + j*(-136) -165 + j*(-339) --88 + j*(-323) --206 + j*(-184) --265 + j*(-32) --186 + j*(199) -124 + j*(227) -233 + j*(-72) -2 + j*(-201) --70 + j*(-66) --18 + j*(-109) --199 + j*(-134) --247 + j*(142) -52 + j*(219) -122 + j*(-47) --98 + j*(-73) --71 + j*(100) -48 + j*(25) --83 + j*(-39) --117 + j*(148) -96 + j*(191) -163 + j*(14) -69 + j*(-51) -52 + j*(-48) --1 + j*(-100) --112 + j*(-35) --72 + j*(105) -53 + j*(110) -95 + j*(47) -127 + j*(4) -151 + j*(-115) -1 + j*(-254) --248 + j*(-164) --279 + j*(143) --1 + j*(298) -228 + j*(104) -124 + j*(-119) --37 + j*(-70) -9 + j*(3) --1 + j*(-85) --151 + j*(-22) --82 + j*(185) -129 + j*(152) -133 + j*(8) -112 + j*(22) -209 + j*(-59) -104 + j*(-248) --107 + j*(-182) --71 + j*(-43) --45 + j*(-108) --172 + j*(-52) --74 + j*(115) -83 + j*(-25) --111 + j*(-149) --212 + j*(94) -50 + j*(164) -59 + j*(-96) --214 + j*(-33) --108 + j*(274) -221 + j*(184) -180 + j*(-109) --30 + j*(-104) --18 + j*(21) -74 + j*(-22) -15 + j*(-140) --161 + j*(-123) --222 + j*(91) --16 + j*(219) -119 + j*(31) --93 + j*(-53) --136 + j*(249) -267 + j*(321) -422 + j*(-106) -83 + j*(-326) --103 + j*(-133) --19 + j*(-66) --76 + j*(-122) --156 + j*(-10) --61 + j*(81) -4 + j*(31) --7 + j*(6) --9 + j*(-18) --76 + j*(-28) --103 + j*(77) -8 + j*(109) --6 + j*(26) --76 + j*(143) -158 + j*(265) -379 + j*(-24) -124 + j*(-326) --173 + j*(-161) --82 + j*(57) -29 + j*(-19) --76 + j*(-59) --96 + j*(74) -27 + j*(110) -71 + j*(33) -47 + j*(18) -88 + j*(33) -153 + j*(-46) -93 + j*(-183) --85 + j*(-192) --160 + j*(-37) --65 + j*(51) --23 + j*(8) --49 + j*(45) -68 + j*(91) -153 + j*(-83) --45 + j*(-222) --215 + j*(-39) --76 + j*(128) -57 + j*(24) --31 + j*(-62) --94 + j*(17) --35 + j*(77) -25 + j*(60) -62 + j*(13) -48 + j*(-77) --66 + j*(-117) --169 + j*(-25) --148 + j*(110) --46 + j*(175) -66 + j*(153) -118 + j*(61) -73 + j*(-13) -18 + j*(15) -72 + j*(76) -202 + j*(-4) -170 + j*(-243) --148 + j*(-337) --383 + j*(-37) --180 + j*(274) -90 + j*(170) -14 + j*(19) --11 + j*(147) -204 + j*(98) -129 + j*(-184) --167 + j*(-109) --95 + j*(139) -38 + j*(57) --108 + j*(78) -52 + j*(354) -470 + j*(147) -305 + j*(-340) --129 + j*(-233) --25 + j*(78) -165 + j*(-70) --12 + j*(-168) --20 + j*(11) -165 + j*(-69) -56 + j*(-277) --128 + j*(-223) --151 + j*(-162) --265 + j*(-139) --330 + j*(69) --180 + j*(206) --98 + j*(208) -23 + j*(308) -322 + j*(173) -234 + j*(-235) --176 + j*(-170) --61 + j*(183) -243 + j*(-21) --40 + j*(-298) --281 + j*(18) -28 + j*(190) -106 + j*(-104) --175 + j*(-97) --111 + j*(153) -73 + j*(53) --63 + j*(-48) --102 + j*(122) -65 + j*(134) -61 + j*(25) -47 + j*(66) -148 + j*(-6) -30 + j*(-163) --146 + j*(-35) --18 + j*(112) -71 + j*(-20) --81 + j*(-45) --62 + j*(141) -157 + j*(104) -135 + j*(-134) --111 + j*(-157) --197 + j*(73) --11 + j*(230) -194 + j*(111) -134 + j*(-102) --62 + j*(-59) --3 + j*(141) -239 + j*(83) -249 + j*(-192) -9 + j*(-319) --204 + j*(-199) --226 + j*(18) --57 + j*(117) -35 + j*(-24) --144 + j*(-77) --189 + j*(177) -117 + j*(246) -204 + j*(-59) --71 + j*(-129) --109 + j*(110) -74 + j*(128) -74 + j*(46) -125 + j*(105) -293 + j*(-47) -124 + j*(-316) --171 + j*(-190) --82 + j*(49) -76 + j*(-41) --20 + j*(-145) --95 + j*(-79) --88 + j*(-45) --96 + j*(4) --4 + j*(19) --30 + j*(-130) --269 + j*(-49) --153 + j*(281) -231 + j*(144) -61 + j*(-247) --316 + j*(-23) --40 + j*(334) -289 + j*(28) --18 + j*(-257) --237 + j*(28) -10 + j*(163) -55 + j*(-52) --143 + j*(-21) --86 + j*(154) -36 + j*(115) -16 + j*(90) -100 + j*(114) -154 + j*(-57) --74 + j*(-144) --199 + j*(110) -39 + j*(281) -238 + j*(115) -183 + j*(-55) -107 + j*(-86) -57 + j*(-136) --100 + j*(-133) --185 + j*(79) -18 + j*(264) -272 + j*(126) -228 + j*(-124) -57 + j*(-138) -52 + j*(-62) -74 + j*(-105) -11 + j*(-100) -70 + j*(-62) -100 + j*(-229) --173 + j*(-303) --309 + j*(14) --11 + j*(165) -88 + j*(-107) --182 + j*(-122) --108 + j*(158) -177 + j*(-9) --81 + j*(-312) --420 + j*(10) --87 + j*(375) -267 + j*(65) --15 + j*(-252) --297 + j*(1) --99 + j*(247) -85 + j*(129) -24 + j*(45) -37 + j*(105) -133 + j*(47) -86 + j*(-66) -2 + j*(-36) -59 + j*(-3) -82 + j*(-129) --110 + j*(-208) --272 + j*(-12) --133 + j*(203) -57 + j*(128) --1 + j*(5) --67 + j*(95) -56 + j*(132) -55 + j*(2) --104 + j*(74) -21 + j*(325) -397 + j*(245) -479 + j*(-168) -187 + j*(-424) --112 + j*(-354) --223 + j*(-171) --210 + j*(-34) --180 + j*(40) --151 + j*(127) --30 + j*(218) -151 + j*(151) -162 + j*(-45) --1 + j*(-98) --57 + j*(28) -45 + j*(92) -136 + j*(23) -131 + j*(-99) -6 + j*(-171) --126 + j*(-63) --30 + j*(97) -153 + j*(-6) -38 + j*(-223) --206 + j*(-115) --122 + j*(133) -104 + j*(64) -32 + j*(-139) --155 + j*(-63) --92 + j*(118) -71 + j*(85) -76 + j*(-45) -3 + j*(-83) --49 + j*(-84) --129 + j*(-49) --145 + j*(93) -30 + j*(165) -148 + j*(-16) --26 + j*(-164) --193 + j*(-4) --58 + j*(157) -66 + j*(52) --34 + j*(-5) --21 + j*(121) -144 + j*(62) -71 + j*(-129) --114 + j*(-54) --28 + j*(91) -74 + j*(-21) --74 + j*(-101) --159 + j*(49) --75 + j*(139) --42 + j*(163) -66 + j*(264) -320 + j*(168) -315 + j*(-167) -11 + j*(-255) --103 + j*(-51) -8 + j*(26) -26 + j*(-25) -5 + j*(4) -61 + j*(14) -71 + j*(-38) -62 + j*(-42) -102 + j*(-91) -30 + j*(-209) --154 + j*(-167) --170 + j*(28) --4 + j*(84) -75 + j*(-52) --42 + j*(-158) --196 + j*(-76) --167 + j*(122) -52 + j*(160) -147 + j*(-67) --71 + j*(-224) --288 + j*(-60) --233 + j*(160) --115 + j*(214) --53 + j*(279) -156 + j*(344) -403 + j*(129) -305 + j*(-223) --13 + j*(-255) --86 + j*(-47) -35 + j*(-33) --35 + j*(-149) --202 + j*(-40) --119 + j*(170) -86 + j*(138) -84 + j*(-18) --21 + j*(-8) -10 + j*(69) -79 + j*(35) -62 + j*(-9) -64 + j*(6) -117 + j*(-38) -78 + j*(-147) --62 + j*(-166) --147 + j*(-49) --96 + j*(75) -23 + j*(88) -79 + j*(8) -55 + j*(-57) -28 + j*(-82) --13 + j*(-128) --125 + j*(-137) --226 + j*(-23) --197 + j*(148) --41 + j*(251) -158 + j*(197) -228 + j*(-18) -69 + j*(-161) --68 + j*(-64) -13 + j*(20) -49 + j*(-93) --93 + j*(-119) --125 + j*(1) --74 + j*(-6) --194 + j*(5) --200 + j*(272) -164 + j*(381) -399 + j*(35) -170 + j*(-278) --124 + j*(-202) --181 + j*(1) --99 + j*(130) -40 + j*(155) -115 + j*(48) -47 + j*(-8) -49 + j*(64) -170 + j*(11) -112 + j*(-161) --74 + j*(-132) --78 + j*(27) -31 + j*(60) -92 + j*(13) -125 + j*(-69) -62 + j*(-180) --76 + j*(-174) --123 + j*(-94) --156 + j*(-50) --170 + j*(93) -50 + j*(170) -159 + j*(-115) --197 + j*(-238) --335 + j*(179) -103 + j*(320) -206 + j*(-99) --185 + j*(-123) --128 + j*(246) -194 + j*(129) -23 + j*(-105) --100 + j*(143) -235 + j*(190) -255 + j*(-187) --83 + j*(-195) --48 + j*(43) -90 + j*(-62) --66 + j*(-126) --54 + j*(26) -61 + j*(-91) --182 + j*(-188) --292 + j*(146) -59 + j*(268) -154 + j*(-42) --104 + j*(-69) --62 + j*(144) -95 + j*(56) --24 + j*(-26) --31 + j*(132) -156 + j*(95) -112 + j*(-81) --4 + j*(-31) -79 + j*(8) -69 + j*(-118) --75 + j*(-99) --64 + j*(18) --15 + j*(8) --44 + j*(33) -38 + j*(95) -130 + j*(-11) -35 + j*(-104) --21 + j*(-25) -64 + j*(-24) -41 + j*(-137) --82 + j*(-142) --141 + j*(-64) --153 + j*(28) --67 + j*(131) -93 + j*(62) -26 + j*(-125) --173 + j*(-42) --63 + j*(158) -138 + j*(8) --60 + j*(-206) --307 + j*(6) --136 + j*(267) -69 + j*(159) --29 + j*(66) --37 + j*(230) -202 + j*(243) -265 + j*(5) -98 + j*(-65) -90 + j*(48) -213 + j*(-6) -160 + j*(-149) -56 + j*(-121) -119 + j*(-106) -91 + j*(-280) --187 + j*(-302) --305 + j*(-4) --69 + j*(175) -116 + j*(18) -30 + j*(-141) --93 + j*(-135) --163 + j*(-81) --216 + j*(28) --139 + j*(171) -18 + j*(165) -49 + j*(78) -57 + j*(83) -155 + j*(21) -103 + j*(-164) --122 + j*(-168) --175 + j*(40) --28 + j*(109) -23 + j*(23) --23 + j*(6) --10 + j*(32) -2 + j*(1) --35 + j*(-1) --23 + j*(35) -13 + j*(-4) --66 + j*(-68) --210 + j*(28) --175 + j*(274) -111 + j*(379) -349 + j*(170) -293 + j*(-82) -161 + j*(-128) -151 + j*(-157) -40 + j*(-276) --187 + j*(-195) --172 + j*(47) -14 + j*(54) --13 + j*(-79) --132 + j*(-13) --64 + j*(110) -35 + j*(85) -52 + j*(49) -99 + j*(15) -79 + j*(-91) --39 + j*(-89) --27 + j*(5) -39 + j*(-52) --76 + j*(-105) --136 + j*(44) -11 + j*(106) -51 + j*(-4) --18 + j*(1) -37 + j*(23) -4 + j*(-74) --138 + j*(35) -53 + j*(249) -366 + j*(14) -157 + j*(-379) --248 + j*(-250) --188 + j*(83) -41 + j*(38) --22 + j*(-115) --141 + j*(-55) --129 + j*(31) --105 + j*(80) --28 + j*(122) -49 + j*(49) --32 + j*(-14) --62 + j*(99) -91 + j*(110) -94 + j*(-57) --52 + j*(-32) -41 + j*(77) -134 + j*(-120) --168 + j*(-247) --377 + j*(124) --13 + j*(419) -333 + j*(126) -125 + j*(-203) --144 + j*(-54) --21 + j*(157) -153 + j*(50) -77 + j*(-89) --10 + j*(-42) -33 + j*(-24) --8 + j*(-95) --121 + j*(-30) --54 + j*(96) -50 + j*(21) --81 + j*(-54) --167 + j*(165) -110 + j*(319) -340 + j*(62) -156 + j*(-168) -14 + j*(-24) -199 + j*(27) -245 + j*(-236) --26 + j*(-341) --163 + j*(-165) --98 + j*(-92) --140 + j*(-118) --202 + j*(-4) --97 + j*(97) --11 + j*(29) --64 + j*(-8) --75 + j*(61) -6 + j*(84) -62 + j*(32) -72 + j*(-46) -13 + j*(-127) --112 + j*(-111) --132 + j*(13) --25 + j*(25) --56 + j*(-96) --250 + j*(-49) --264 + j*(226) -14 + j*(361) -247 + j*(173) -189 + j*(-72) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -0 + j*(0) -]; From 087a97f606b673864d282ed027d6785ffbf62e78 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Sat, 6 Aug 2022 16:30:59 +0200 Subject: [PATCH 252/267] fix for 3-digit MNC in asn1_msg.c --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 1 - 1 file changed, 1 deletion(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 687784cafc..a4370f0a65 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -345,7 +345,6 @@ uint16_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier, gNB_RrcConfigurationReq *co if(configuration->mnc_digit_length[i] == 3) { asn1cSequenceAdd(nr_plmn->mnc.list, NR_MCC_MNC_Digit_t, mnc0); *mnc0=(configuration->mnc[i]/100)%10; - mnc/=10; } asn1cSequenceAdd(nr_plmn->mnc.list, NR_MCC_MNC_Digit_t, mnc1); *mnc1=(mnc/10)%10; From f75cdbcad75eb5e30d93a9ab5dacccde17f2ede3 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 25 Mar 2022 11:47:23 +0100 Subject: [PATCH 253/267] Use F1 DL RRC message transfer internally for RRCSetup --- cmake_targets/CMakeLists.txt | 3 + openair2/COMMON/f1ap_messages_types.h | 1 + openair2/F1AP/dummy_enb.c | 4 + openair2/F1AP/f1ap_cu_task.c | 1 + openair2/F1AP/f1ap_du_rrc_message_transfer.c | 11 ++ .../LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 131 +++++++++++++ .../LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h | 30 +++ openair2/RRC/NR/mac_rrc_dl.h | 34 ++++ openair2/RRC/NR/mac_rrc_dl_direct.c | 52 +++++ openair2/RRC/NR/mac_rrc_dl_f1ap.c | 44 +++++ openair2/RRC/NR/nr_rrc_defs.h | 8 + openair2/RRC/NR/rrc_gNB.c | 181 ++++-------------- 12 files changed, 357 insertions(+), 143 deletions(-) create mode 100644 openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c create mode 100644 openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h create mode 100644 openair2/RRC/NR/mac_rrc_dl.h create mode 100644 openair2/RRC/NR/mac_rrc_dl_direct.c create mode 100644 openair2/RRC/NR/mac_rrc_dl_f1ap.c diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 157ac1f6b3..b215e6ca4c 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1872,6 +1872,8 @@ set(L2_NR_SRC ${NR_RRC_DIR}/rrc_gNB.c ${NR_RRC_DIR}/nr_rrc_common.c ${NR_RRC_DIR}/L2_nr_interface.c + ${NR_RRC_DIR}/mac_rrc_dl_direct.c + ${NR_RRC_DIR}/mac_rrc_dl_f1ap.c ${NR_RRC_DIR}/nr_rrc_config.c ${NR_RRC_DIR}/rrc_gNB_nsa.c ${NR_RRC_DIR}/rrc_gNB_internode.c @@ -1950,6 +1952,7 @@ set (MAC_NR_SRC ${NR_GNB_MAC_DIR}/gNB_scheduler_uci.c ${NR_GNB_MAC_DIR}/gNB_scheduler_srs.c ${NR_GNB_MAC_DIR}/gNB_scheduler_RA.c + ${NR_GNB_MAC_DIR}/mac_rrc_dl_handler.c ) diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index ae050e2bc2..c19bdff9a2 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -23,6 +23,7 @@ #define F1AP_MESSAGES_TYPES_H_ #include "rlc.h" +#include "s1ap_messages_types.h" //-------------------------------------------------------------------------------------------// // Defines to access message fields. diff --git a/openair2/F1AP/dummy_enb.c b/openair2/F1AP/dummy_enb.c index 8e185c951d..22627c8d92 100644 --- a/openair2/F1AP/dummy_enb.c +++ b/openair2/F1AP/dummy_enb.c @@ -47,3 +47,7 @@ bool sdap_data_req(protocol_ctxt_t *ctxt_p, const int pdusession_id) { abort(); } + +int dl_rrc_message(module_id_t module_id, const f1ap_dl_rrc_message_t *dl_rrc) { + abort(); +} diff --git a/openair2/F1AP/f1ap_cu_task.c b/openair2/F1AP/f1ap_cu_task.c index efbc9f2c8b..b521d0c83d 100644 --- a/openair2/F1AP/f1ap_cu_task.c +++ b/openair2/F1AP/f1ap_cu_task.c @@ -172,6 +172,7 @@ void *F1AP_CU_task(void *arg) { LOG_I(F1AP, "CU Task Received F1AP_DL_RRC_MESSAGE\n"); CU_send_DL_RRC_MESSAGE_TRANSFER(ITTI_MSG_DESTINATION_INSTANCE(received_msg), &F1AP_DL_RRC_MESSAGE(received_msg)); + free(F1AP_DL_RRC_MESSAGE(received_msg).rrc_container); break; case F1AP_UE_CONTEXT_SETUP_REQ: // from rrc diff --git a/openair2/F1AP/f1ap_du_rrc_message_transfer.c b/openair2/F1AP/f1ap_du_rrc_message_transfer.c index e158e9519a..d896a2640b 100644 --- a/openair2/F1AP/f1ap_du_rrc_message_transfer.c +++ b/openair2/F1AP/f1ap_du_rrc_message_transfer.c @@ -56,6 +56,7 @@ #include "intertask_interface.h" #include "LAYER2/NR_MAC_gNB/mac_proto.h" +#include "openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h" int DU_handle_DL_NR_RRC_MESSAGE_TRANSFER(instance_t instance, uint32_t assoc_id, @@ -986,6 +987,16 @@ int DU_handle_DL_NR_RRC_MESSAGE_TRANSFER(instance_t instance, } } + f1ap_dl_rrc_message_t dl_rrc = { + .rrc_container_length = ie->value.choice.RRCContainer.size, + .rrc_container = ie->value.choice.RRCContainer.buf, + .rnti = f1ap_get_rnti_by_du_id(DUtype, instance, du_ue_f1ap_id), + .srb_id = srb_id + }; + int rc = dl_rrc_message(instance, &dl_rrc); + if (rc == 0) + return 0; /* has been handled, otherwise continue below */ + // decode RRC Container and act on the message type AssertFatal(srb_id<3,"illegal srb_id\n"); MessageDef *msg = itti_alloc_new_message(TASK_DU_F1, 0, NR_DU_RRC_DL_INDICATION); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c new file mode 100644 index 0000000000..578e4fb453 --- /dev/null +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -0,0 +1,131 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "mac_rrc_dl_handler.h" + +#include "mac_proto.h" +#include "openair2/RRC/NR/rrc_gNB_UE_context.h" + +#include "NR_RRCSetup.h" +#include "NR_DL-CCCH-Message.h" +#include "NR_CellGroupConfig.h" + +int dl_rrc_message_rrcSetup(module_id_t module_id, const f1ap_dl_rrc_message_t *dl_rrc, NR_RRCSetup_t *rrcSetup); + +int dl_rrc_message(module_id_t module_id, const f1ap_dl_rrc_message_t *dl_rrc) +{ + /* dispatch message to dl_rrc_message_rrcSetup() and others, similar to as is + * done in the DU (should be the same here) */ + + if (dl_rrc->srb_id == 0) { + + NR_DL_CCCH_Message_t *dl_ccch_msg = NULL; + asn_dec_rval_t dec_rval = uper_decode(NULL, + &asn_DEF_NR_DL_CCCH_Message, + (void **) &dl_ccch_msg, + dl_rrc->rrc_container, + dl_rrc->rrc_container_length, + 0, + 0); + AssertFatal(dec_rval.code == RC_OK, "could not decode F1AP message\n"); + + switch (dl_ccch_msg->message.choice.c1->present) { + case NR_DL_CCCH_MessageType__c1_PR_NOTHING: + LOG_W(NR_MAC, "Received NOTHING on DL-CCCH-Message\n"); + break; + case NR_DL_CCCH_MessageType__c1_PR_rrcReject: + LOG_D(NR_MAC, "DL-CCCH/SRB0, received rrcReject for RNTI %04x\n", dl_rrc->rnti); + AssertFatal(0, "rrcReject not implemented yet\n"); + break; + case NR_DL_CCCH_MessageType__c1_PR_rrcSetup: + LOG_I(NR_MAC, "DL-CCCH/SRB0, received rrcSetup for RNTI %04x\n", dl_rrc->rnti); + return dl_rrc_message_rrcSetup(module_id, dl_rrc, dl_ccch_msg->message.choice.c1->choice.rrcSetup); + break; + case NR_DL_CCCH_MessageType__c1_PR_spare2: + LOG_W(NR_MAC, "DL-CCCH/SRB0, received spare2\n"); + break; + case NR_DL_CCCH_MessageType__c1_PR_spare1: + LOG_W(NR_MAC, "DL-CCCH/SRB0, received spare1\n"); + break; + default: + AssertFatal(0 == 1, "Unknown DL-CCCH/SRB0 message %d\n", dl_ccch_msg->message.choice.c1->present); + break; + } + return 0; + } + + return -1; /* not handled yet */ +} + +int dl_rrc_message_rrcSetup(module_id_t module_id, const f1ap_dl_rrc_message_t *dl_rrc, NR_RRCSetup_t *rrcSetup) +{ + DevAssert(rrcSetup != NULL); + + NR_RRCSetup_IEs_t *rrcSetup_ies = rrcSetup->criticalExtensions.choice.rrcSetup; + AssertFatal(rrcSetup_ies->masterCellGroup.buf != NULL,"masterCellGroup is NULL\n"); + NR_CellGroupConfig_t *cellGroup = NULL; + asn_dec_rval_t dec_rval = uper_decode(NULL, + &asn_DEF_NR_CellGroupConfig, + (void **)&cellGroup, + rrcSetup_ies->masterCellGroup.buf, + rrcSetup_ies->masterCellGroup.size, + 0, + 0); + AssertFatal(dec_rval.code == RC_OK, "could not decode masterCellGroup\n"); + + /* there might be a memory leak for the cell group if we call this multiple + * times. Also, the first parameters of rrc_mac_config_req_gNB() are only + * relevant when setting the scc, which we don't do (and cannot do) here. */ + rrc_pdsch_AntennaPorts_t pap = {0}; + rrc_mac_config_req_gNB(module_id, + pap, /* only when scc != NULL */ + 0, /* only when scc != NULL */ + 0, /* only when scc != NULL */ + 0, /* only when scc != NULL */ + NULL, /* scc */ + NULL, /* mib */ + NULL, /* sib1 */ + 0, /* add_ue */ + dl_rrc->rnti, + cellGroup); + + /* TODO: drop the RRC context */ + gNB_RRC_INST *rrc = RC.nrrrc[module_id]; + struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_get_ue_context(rrc, dl_rrc->rnti); + gNB_RRC_UE_t *ue_p = &ue_context_p->ue_context; + ue_context_p->ue_context.SRB_configList = rrcSetup_ies->radioBearerConfig.srb_ToAddModList; + ue_context_p->ue_context.masterCellGroup = cellGroup; + + /* TODO: this should pass through RLC and NOT the RRC with a shared buffer */ + AssertFatal(ue_p->Srb0.Active == 1,"SRB0 is not active\n"); + memcpy(ue_p->Srb0.Tx_buffer.Payload, dl_rrc->rrc_container, dl_rrc->rrc_container_length); + ue_p->Srb0.Tx_buffer.payload_size = dl_rrc->rrc_container_length; + + protocol_ctxt_t ctxt = { .module_id = module_id, .rnti = dl_rrc->rnti }; + nr_rrc_rlc_config_asn1_req(&ctxt, + ue_context_p->ue_context.SRB_configList, + NULL, + NULL, + NULL, + cellGroup->rlc_BearerToAddModList); + + return 0; +} diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h new file mode 100644 index 0000000000..ecbc95eef0 --- /dev/null +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h @@ -0,0 +1,30 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef MAC_RRC_DL_HANDLER_H +#define MAC_RRC_DL_HANDLER_H + +#include "platform_types.h" +#include "f1ap_messages_types.h" + +int dl_rrc_message(module_id_t module_id, const f1ap_dl_rrc_message_t *dl_rrc); + +#endif /* MAC_RRC_DL_HANDLER_H */ diff --git a/openair2/RRC/NR/mac_rrc_dl.h b/openair2/RRC/NR/mac_rrc_dl.h new file mode 100644 index 0000000000..1943490cd6 --- /dev/null +++ b/openair2/RRC/NR/mac_rrc_dl.h @@ -0,0 +1,34 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * conmnc_digit_lengtht@openairinterface.org + */ + +#ifndef MAC_RRC_DL_H +#define MAC_RRC_DL_H + +#include "platform_types.h" +#include "f1ap_messages_types.h" + +typedef void (*dl_rrc_message_transfer_func_t)(module_id_t module_id, const f1ap_dl_rrc_message_t *dl_rrc); + +struct nr_mac_rrc_dl_if_s; +void mac_rrc_dl_direct_init(struct nr_mac_rrc_dl_if_s *mac_rrc); +void mac_rrc_dl_f1ap_init(struct nr_mac_rrc_dl_if_s *mac_rrc); + +#endif /* MAC_RRC_DL_H */ diff --git a/openair2/RRC/NR/mac_rrc_dl_direct.c b/openair2/RRC/NR/mac_rrc_dl_direct.c new file mode 100644 index 0000000000..b3ba7b9ee5 --- /dev/null +++ b/openair2/RRC/NR/mac_rrc_dl_direct.c @@ -0,0 +1,52 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * conmnc_digit_lengtht@openairinterface.org + */ + +#include "nr_rrc_defs.h" + +#include "mac_rrc_dl.h" +#include "openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h" + +static void dl_rrc_message_transfer_direct(module_id_t module_id, const f1ap_dl_rrc_message_t *dl_rrc) +{ +#ifdef ITTI_SIM + const int len = dl_rrc->rrc_container_length; + LOG_I(NR_RRC, + PROTOCOL_NR_RRC_CTXT_UE_FMT" [RAPROC] Logical Channel DL-CCCH, Generating RRCSetup (bytes %d)\n", + PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP), + len); + uint8_t *message_buffer; + message_buffer = itti_malloc(TASK_RRC_GNB, TASK_RRC_UE_SIM, len); + memcpy (message_buffer, dl_rrc->rrc_container, len); + message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, GNB_RRC_CCCH_DATA_IND); + GNB_RRC_CCCH_DATA_IND (message_p).sdu = message_buffer; + GNB_RRC_CCCH_DATA_IND (message_p).size = len; + itti_send_msg_to_task (TASK_RRC_UE_SIM, ctxt_pP->instance, message_p); +#else + /* TODO how to manage inter-thread communication? */ + + dl_rrc_message(module_id, dl_rrc); +#endif +} + +void mac_rrc_dl_direct_init(nr_mac_rrc_dl_if_t *mac_rrc) +{ + mac_rrc->dl_rrc_message_transfer = dl_rrc_message_transfer_direct; +} diff --git a/openair2/RRC/NR/mac_rrc_dl_f1ap.c b/openair2/RRC/NR/mac_rrc_dl_f1ap.c new file mode 100644 index 0000000000..40f3b4b6ea --- /dev/null +++ b/openair2/RRC/NR/mac_rrc_dl_f1ap.c @@ -0,0 +1,44 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * conmnc_digit_lengtht@openairinterface.org + */ + +#include "mac_rrc_dl.h" +#include "nr_rrc_defs.h" + +static void dl_rrc_message_transfer_f1ap(module_id_t module_id, const f1ap_dl_rrc_message_t *dl_rrc) +{ + /* TODO call F1AP function directly? no real-time constraint here */ + + MessageDef *message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, F1AP_DL_RRC_MESSAGE); + f1ap_dl_rrc_message_t *msg = &F1AP_DL_RRC_MESSAGE(message_p); + *msg = *dl_rrc; + if (dl_rrc->rrc_container) { + msg->rrc_container = malloc(dl_rrc->rrc_container_length); + AssertFatal(msg->rrc_container != NULL, "out of memory\n"); + msg->rrc_container_length = dl_rrc->rrc_container_length; + memcpy(msg->rrc_container, dl_rrc->rrc_container, dl_rrc->rrc_container_length); + } + itti_send_msg_to_task (TASK_CU_F1, module_id, message_p); +} + +void mac_rrc_dl_f1ap_init(nr_mac_rrc_dl_if_t *mac_rrc) +{ + mac_rrc->dl_rrc_message_transfer = dl_rrc_message_transfer_f1ap; +} diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index b6a92db7a8..c709a158da 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -42,6 +42,7 @@ #include "COMMON/platform_types.h" #include "RRC/LTE/rrc_defs.h" //#include "LAYER2/RLC/rlc.h" +#include "mac_rrc_dl.h" //#include "COMMON/mac_rrc_primitives.h" @@ -480,6 +481,11 @@ typedef struct { int do_drb_integrity; } nr_security_configuration_t; +typedef struct nr_mac_rrc_dl_if_s { + /* TODO add other message types as necessary */ + dl_rrc_message_transfer_func_t dl_rrc_message_transfer; +} nr_mac_rrc_dl_if_t; + //---NR---(completely change)--------------------- typedef struct gNB_RRC_INST_s { @@ -529,6 +535,8 @@ typedef struct gNB_RRC_INST_s { // security configuration (preferred algorithms) nr_security_configuration_t security; + + nr_mac_rrc_dl_if_t mac_rrc; } gNB_RRC_INST; #include "nr_rrc_proto.h" //should be put here otherwise compilation error diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 8c6c583289..4340bfa6bd 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -196,6 +196,26 @@ static void init_NR_SI(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration } } +static void rrc_gNB_mac_rrc_init(gNB_RRC_INST *rrc) +{ + switch (rrc->node_type) { + case ngran_gNB_CU: + mac_rrc_dl_f1ap_init(&rrc->mac_rrc); + break; + case ngran_gNB_DU: + /* silently drop this, as we currently still need the RRC at the DU. As + * soon as this is not the case anymore, we can add the AssertFatal() */ + //AssertFatal(1==0,"nothing to do for DU\n"); + break; + case ngran_gNB: + mac_rrc_dl_direct_init(&rrc->mac_rrc); + break; + default: + AssertFatal(0 == 1, "Unknown node type %d\n", rrc->node_type); + break; + } +} + char openair_rrc_gNB_configuration(const module_id_t gnb_mod_idP, gNB_RrcConfigurationReq *configuration) { protocol_ctxt_t ctxt = { 0 }; gNB_RRC_INST *rrc=RC.nrrrc[gnb_mod_idP]; @@ -203,13 +223,13 @@ char openair_rrc_gNB_configuration(const module_id_t gnb_mod_idP, gNB_RrcConfigu LOG_I(NR_RRC, PROTOCOL_NR_RRC_CTXT_FMT" Init...\n", PROTOCOL_NR_RRC_CTXT_ARGS(&ctxt)); - AssertFatal(rrc != NULL, "RC.nrrrc not initialized!"); AssertFatal(NUMBER_OF_UE_MAX < (module_id_t)0xFFFFFFFFFFFFFFFF, " variable overflow"); AssertFatal(configuration!=NULL,"configuration input is null\n"); rrc->module_id = gnb_mod_idP; rrc->Nb_ue = 0; rrc->carrier.Srb0.Active = 0; + rrc_gNB_mac_rrc_init(rrc); nr_uid_linear_allocator_init(&rrc->uid_allocator); RB_INIT(&rrc->rrc_ue_head); rrc->initial_id2_s1ap_ids = hashtable_create (NUMBER_OF_UE_MAX * 2, NULL, NULL); @@ -325,14 +345,14 @@ rrc_gNB_generate_RRCSetup( ) //----------------------------------------------------------------------------- { - LOG_D(NR_RRC, "rrc_gNB_generate_RRCSetup \n"); - MessageDef *message_p; + LOG_I(NR_RRC, "rrc_gNB_generate_RRCSetup for RNTI %04x\n", ctxt_pP->rnti); // T(T_GNB_RRC_SETUP, // T_INT(ctxt_pP->module_id), // T_INT(ctxt_pP->frame), // T_INT(ctxt_pP->subframe), // T_INT(ctxt_pP->rnti)); + gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; NR_ServingCellConfig_t *servingcellconfigdedicated = rrc->configuration.scd; @@ -351,87 +371,22 @@ rrc_gNB_generate_RRCSetup( ue_p->Srb0.Tx_buffer.payload_size, "[MSG] RRC Setup\n"); - switch (rrc->node_type) { - case ngran_gNB_CU: - // create an ITTI message - /* TODO: F1 IDs ar missing in RRC */ - nr_rrc_pdcp_config_asn1_req(ctxt_pP, - ue_context_pP->ue_context.SRB_configList, - NULL, - NULL, - 0, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, F1AP_DL_RRC_MESSAGE); - F1AP_DL_RRC_MESSAGE (message_p).rrc_container = (uint8_t *)ue_p->Srb0.Tx_buffer.Payload; - F1AP_DL_RRC_MESSAGE (message_p).rrc_container_length = ue_p->Srb0.Tx_buffer.payload_size; - F1AP_DL_RRC_MESSAGE (message_p).gNB_CU_ue_id = 0; - F1AP_DL_RRC_MESSAGE (message_p).gNB_DU_ue_id = 0; - F1AP_DL_RRC_MESSAGE (message_p).old_gNB_DU_ue_id = 0xFFFFFFFF; // unknown - F1AP_DL_RRC_MESSAGE (message_p).rnti = ue_p->rnti; - F1AP_DL_RRC_MESSAGE (message_p).srb_id = CCCH; - F1AP_DL_RRC_MESSAGE (message_p).execute_duplication = 1; - F1AP_DL_RRC_MESSAGE (message_p).RAT_frequency_priority_information.en_dc = 0; - itti_send_msg_to_task (TASK_CU_F1, ctxt_pP->module_id, message_p); - LOG_D(NR_RRC, "Send F1AP_DL_RRC_MESSAGE with ITTI\n"); + // activate release timer, if RRCSetupComplete not received after 100 frames, remove UE + ue_context_pP->ue_context.ue_release_timer = 1; + // remove UE after 10 frames after RRCConnectionRelease is triggered + ue_context_pP->ue_context.ue_release_timer_thres = 1000; - break; + /* TODO: this should go through the E1 interface */ + apply_pdcp_config(ue_context_pP,ctxt_pP); - case ngran_gNB_DU: - // nothing to do for DU - AssertFatal(1==0,"nothing to do for DU\n"); - break; - - case ngran_gNB: - { - // rrc_mac_config_req_gNB - -#ifdef ITTI_SIM - LOG_I(NR_RRC, - PROTOCOL_NR_RRC_CTXT_UE_FMT" [RAPROC] Logical Channel DL-CCCH, Generating RRCSetup (bytes %d)\n", - PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP), - ue_p->Srb0.Tx_buffer.payload_size); - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_GNB, TASK_RRC_UE_SIM, - ue_p->Srb0.Tx_buffer.payload_size); - memcpy (message_buffer, (uint8_t*)ue_p->Srb0.Tx_buffer.Payload, ue_p->Srb0.Tx_buffer.payload_size); - message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, GNB_RRC_CCCH_DATA_IND); - GNB_RRC_CCCH_DATA_IND (message_p).sdu = message_buffer; - GNB_RRC_CCCH_DATA_IND (message_p).size = ue_p->Srb0.Tx_buffer.payload_size; - itti_send_msg_to_task (TASK_RRC_UE_SIM, ctxt_pP->instance, message_p); -#else - LOG_D(NR_RRC, - PROTOCOL_NR_RRC_CTXT_UE_FMT" RRC_gNB --- MAC_CONFIG_REQ (SRB1) ---> MAC_gNB\n", - PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP)); - LOG_I(NR_RRC, - PROTOCOL_NR_RRC_CTXT_UE_FMT" [RAPROC] Logical Channel DL-CCCH, Generating RRCSetup (bytes %d)\n", - PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP), - ue_p->Srb0.Tx_buffer.payload_size); - // activate release timer, if RRCSetupComplete not received after 100 frames, remove UE - ue_context_pP->ue_context.ue_release_timer = 1; - // remove UE after 10 frames after RRCConnectionRelease is triggered - ue_context_pP->ue_context.ue_release_timer_thres = 1000; - /* init timers */ - // ue_context_pP->ue_context.ue_rrc_inactivity_timer = 0; - - // configure MAC - - apply_macrlc_config(rrc,ue_context_pP,ctxt_pP); - - apply_pdcp_config(ue_context_pP,ctxt_pP); -#endif - } - break; - - default: - LOG_W(NR_RRC, "Unknown node type %d\n", rrc->node_type); - break; - } + f1ap_dl_rrc_message_t dl_rrc = { + .old_gNB_DU_ue_id = 0xFFFFFF, + .rrc_container = (uint8_t *)ue_p->Srb0.Tx_buffer.Payload, + .rrc_container_length = ue_p->Srb0.Tx_buffer.payload_size, + .rnti = ue_p->rnti, + .srb_id = CCCH + }; + rrc->mac_rrc.dl_rrc_message_transfer(ctxt_pP->module_id, &dl_rrc); } //----------------------------------------------------------------------------- @@ -3041,67 +2996,7 @@ static int rrc_process_DU_DL(MessageDef *msg_p, const char *msg_name, instance_ rrc_gNB_get_ue_context(rrc, ctxt.rnti); if (req->srb_id == 0) { - NR_DL_CCCH_Message_t *dl_ccch_msg=NULL; - asn_dec_rval_t dec_rval; - dec_rval = uper_decode(NULL, - &asn_DEF_NR_DL_CCCH_Message, - (void **)&dl_ccch_msg, - req->buf->data, - req->buf->size,0,0); - AssertFatal(dec_rval.code == RC_OK, "could not decode F1AP message\n"); - - switch (dl_ccch_msg->message.choice.c1->present) { - case NR_DL_CCCH_MessageType__c1_PR_NOTHING: - LOG_I(F1AP,"Received PR_NOTHING on DL-CCCH-Message\n"); - break; - - case NR_DL_CCCH_MessageType__c1_PR_rrcReject: - LOG_I(F1AP,"Logical Channel DL-CCCH (SRB0), Received RRCReject\n"); - break; - - case NR_DL_CCCH_MessageType__c1_PR_rrcSetup: { - LOG_I(F1AP, "Logical Channel DL-CCCH (SRB0), Received RRCSetup RNTI %x\n", - req->rnti); - // Get configuration - NR_RRCSetup_t *rrcSetup = dl_ccch_msg->message.choice.c1->choice.rrcSetup; - AssertFatal(rrcSetup!=NULL, "rrcSetup is null\n"); - NR_RRCSetup_IEs_t *rrcSetup_ies = rrcSetup->criticalExtensions.choice.rrcSetup; - ue_context_p->ue_context.SRB_configList = rrcSetup_ies->radioBearerConfig.srb_ToAddModList; - AssertFatal(rrcSetup_ies->masterCellGroup.buf!=NULL,"masterCellGroup is null\n"); - asn_dec_rval_t dec_rval; - dec_rval = uper_decode(NULL, - &asn_DEF_NR_CellGroupConfig, - (void **)&ue_context_p->ue_context.masterCellGroup, - rrcSetup_ies->masterCellGroup.buf, - rrcSetup_ies->masterCellGroup.size,0,0); - AssertFatal(dec_rval.code == RC_OK, "could not decode masterCellGroup\n"); - apply_macrlc_config(rrc,ue_context_p,&ctxt); - gNB_RRC_UE_t *ue_p = &ue_context_p->ue_context; - AssertFatal(ue_p->Srb0.Active == 1,"SRB0 is not active\n"); - memcpy((void *)ue_p->Srb0.Tx_buffer.Payload, - (void *)req->buf->data, - req->buf->size); // ie->value.choice.RRCContainer.size - ue_p->Srb0.Tx_buffer.payload_size = req->buf->size; - break; - } // case - - case NR_DL_CCCH_MessageType__c1_PR_spare2: - LOG_I(F1AP, - "Logical Channel DL-CCCH (SRB0), Received spare2\n"); - break; - - case NR_DL_CCCH_MessageType__c1_PR_spare1: - LOG_I(F1AP, - "Logical Channel DL-CCCH (SRB0), Received spare1\n"); - break; - - default: - AssertFatal(1==0, - "Unknown message\n"); - break; - }// switch case - - return(0); + AssertFatal(0 == 1, "should pass through dl_rrc_message()\n"); } else if (req->srb_id == 1) { NR_DL_DCCH_Message_t *dl_dcch_msg=NULL; asn_dec_rval_t dec_rval; From f52809a8fbf51ae060cc5e94dd22f5602b5ee101 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 2 May 2022 12:35:58 +0200 Subject: [PATCH 254/267] Add MAC-RRC UL stubs for F1AP and direct --- cmake_targets/CMakeLists.txt | 2 ++ openair1/SIMULATION/NR_PHY/dlsim.c | 2 +- openair1/SIMULATION/NR_PHY/ulsim.c | 2 +- openair2/GNB_APP/gnb_config.c | 30 +++++++--------- openair2/LAYER2/NR_MAC_gNB/config.c | 1 - openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 2 +- openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul.h | 34 ++++++++++++++++++ .../LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c | 35 +++++++++++++++++++ openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c | 35 +++++++++++++++++++ openair2/LAYER2/NR_MAC_gNB/main.c | 21 ++++++++++- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 8 +++++ 11 files changed, 150 insertions(+), 22 deletions(-) create mode 100644 openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul.h create mode 100644 openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c create mode 100644 openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index b215e6ca4c..f8bcb2b548 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1953,6 +1953,8 @@ set (MAC_NR_SRC ${NR_GNB_MAC_DIR}/gNB_scheduler_srs.c ${NR_GNB_MAC_DIR}/gNB_scheduler_RA.c ${NR_GNB_MAC_DIR}/mac_rrc_dl_handler.c + ${NR_GNB_MAC_DIR}/mac_rrc_ul_direct.c + ${NR_GNB_MAC_DIR}/mac_rrc_ul_f1ap.c ) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 0fe5315d4e..b9d7cd460b 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -759,7 +759,7 @@ int main(int argc, char **argv) RC.nb_nr_mac_CC = (int*)malloc(RC.nb_nr_macrlc_inst*sizeof(int)); for (i = 0; i < RC.nb_nr_macrlc_inst; i++) RC.nb_nr_mac_CC[i] = 1; - mac_top_init_gNB(); + mac_top_init_gNB(ngran_gNB); gNB_mac = RC.nrmac[0]; gNB_RRC_INST rrc; memset((void*)&rrc,0,sizeof(rrc)); diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 5df89283a8..9b8f7e533a 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -770,7 +770,7 @@ int main(int argc, char **argv) RC.nb_nr_mac_CC = (int*)malloc(RC.nb_nr_macrlc_inst*sizeof(int)); for (i = 0; i < RC.nb_nr_macrlc_inst; i++) RC.nb_nr_mac_CC[i] = 1; - mac_top_init_gNB(); + mac_top_init_gNB(ngran_gNB); //gNB_MAC_INST* gNB_mac = RC.nrmac[0]; gNB_RRC_INST rrc; memset((void*)&rrc,0,sizeof(rrc)); diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 225daec37b..6e22a1e94c 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -85,7 +85,8 @@ extern uint16_t sf_ahead; int macrlc_has_f1 = 0; -extern ngran_node_t node_type; + +static ngran_node_t get_node_type(void); extern int config_check_band_frequencies(int ind, int16_t band, uint64_t downlink_frequency, int32_t uplink_frequency_offset, uint32_t frame_type); @@ -795,6 +796,7 @@ void RCconfig_nr_macrlc() { paramdef_t GNBParams[] = GNBPARAMS_DESC; paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0}; + ngran_node_t node_type = get_node_type(); config_get( GNBSParams,sizeof(GNBSParams)/sizeof(paramdef_t),NULL); int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; @@ -825,7 +827,7 @@ void RCconfig_nr_macrlc() { if ( MacRLC_ParamList.numelt > 0) { RC.nb_nr_macrlc_inst=MacRLC_ParamList.numelt; - mac_top_init_gNB(); + mac_top_init_gNB(node_type); RC.nb_nr_mac_CC = (int*)malloc(RC.nb_nr_macrlc_inst*sizeof(int)); for (j=0;j 0) { RC.nb_nr_macrlc_inst = MacRLC_ParamList.numelt; - for (j=0;jinitial_ul_rrc_message_transfer = initial_ul_rrc_message_transfer_direct; +} diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c new file mode 100644 index 0000000000..ed67fb9119 --- /dev/null +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c @@ -0,0 +1,35 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * conmnc_digit_lengtht@openairinterface.org + */ + +#include "nr_mac_gNB.h" + +#include "mac_rrc_ul.h" + +static void initial_ul_rrc_message_transfer_f1ap(module_id_t module_id, const f1ap_initial_ul_rrc_message_t *ul_rrc) +{ + AssertFatal(0 == 1, "not implemented\n"); +} + +void mac_rrc_ul_f1ap_init(struct nr_mac_rrc_ul_if_s *mac_rrc) +{ + mac_rrc->initial_ul_rrc_message_transfer = initial_ul_rrc_message_transfer_f1ap; +} + diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 12c9846037..0694f7d757 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -173,8 +173,25 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset return output - begin; } +static void mac_rrc_init(gNB_MAC_INST *mac, ngran_node_t node_type) +{ + switch (node_type) { + case ngran_gNB_CU: + AssertFatal(1 == 0, "nothing to do for CU\n"); + break; + case ngran_gNB_DU: + mac_rrc_ul_f1ap_init(&mac->mac_rrc); + break; + case ngran_gNB: + mac_rrc_ul_direct_init(&mac->mac_rrc); + break; + default: + AssertFatal(0 == 1, "Unknown node type %d\n", node_type); + break; + } +} -void mac_top_init_gNB(void) +void mac_top_init_gNB(ngran_node_t node_type) { module_id_t i; gNB_MAC_INST *nrmac; @@ -221,6 +238,8 @@ void mac_top_init_gNB(void) } if (!IS_SOFTMODEM_NOSTATS_BIT) pthread_create(&RC.nrmac[i]->stats_thread, NULL, nrmac_stats_thread, (void*)RC.nrmac[i]); + + mac_rrc_init(RC.nrmac[i], node_type); }//END for (i = 0; i < RC.nb_nr_macrlc_inst; i++) AssertFatal(rlc_module_init(1) == 0,"Could not initialize RLC layer\n"); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 67da0035bf..3c3ea4dfc8 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -60,6 +60,7 @@ /* Interface */ #include "nfapi_nr_interface_scf.h" #include "NR_PHY_INTERFACE/NR_IF_Module.h" +#include "mac_rrc_ul.h" /* MAC */ #include "LAYER2/MAC/mac.h" @@ -685,6 +686,11 @@ typedef struct NR_bler_options { uint8_t harq_round_max; } NR_bler_options_t; +typedef struct nr_mac_rrc_ul_if_s { + /* TODO add other message types as necessary */ + initial_ul_rrc_message_transfer_func_t initial_ul_rrc_message_transfer; +} nr_mac_rrc_ul_if_t; + /*! \brief UE list used by gNB to order UEs/CC for scheduling*/ typedef struct { rnti_t rnti; @@ -838,6 +844,8 @@ typedef struct gNB_MAC_INST_s { NR_bler_options_t ul_bler; uint8_t min_grant_prb; uint8_t min_grant_mcs; + + nr_mac_rrc_ul_if_t mac_rrc; } gNB_MAC_INST; #endif /*__LAYER2_NR_MAC_GNB_H__ */ From 0c9006ec6697f0cf190106d53352d28160d9e80b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 2 May 2022 12:36:14 +0200 Subject: [PATCH 255/267] Do not initialize MAC multiple times --- openair2/GNB_APP/gnb_config.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 6e22a1e94c..f8a4e495a8 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -759,8 +759,6 @@ void RCconfig_NR_L1(void) { LOG_I(PHY,"%s() NFAPI PNF mode - RC.nb_nr_CC[0]=%d for init_gNB_afterRU()\n", __FUNCTION__, RC.nb_nr_CC[0]); LOG_I(PHY,"%s() NFAPI PNF mode - RC.nb_nr_macrlc_inst:%d because used by mac_top_init_gNB()\n", __FUNCTION__, RC.nb_nr_macrlc_inst); - mac_top_init_gNB(); - configure_nr_nfapi_pnf(RC.gNB[j]->eth_params_n.remote_addr, RC.gNB[j]->eth_params_n.remote_portc, RC.gNB[j]->eth_params_n.my_addr, From 52dbc6fe75e14d2d8c91188f5bd5086bd2884f9a Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 3 May 2022 11:45:54 +0200 Subject: [PATCH 256/267] Refactor linear allocator from LTE/NR; separate LTE/NR headers --- common/utils/collection/linear_alloc.h | 71 +++++++++++++++++++++++ openair2/RRC/LTE/rrc_defs.h | 19 +------ openair2/RRC/LTE/rrc_eNB_UE_context.c | 62 +------------------- openair2/RRC/LTE/rrc_eNB_UE_context.h | 21 ------- openair2/RRC/NR/nr_rrc_defs.h | 34 ++++------- openair2/RRC/NR/rrc_gNB.c | 2 +- openair2/RRC/NR/rrc_gNB_UE_context.c | 79 ++++---------------------- openair2/RRC/NR/rrc_gNB_UE_context.h | 21 ------- openair2/RRC/NR_UE/L2_interface_ue.c | 1 + 9 files changed, 100 insertions(+), 210 deletions(-) create mode 100644 common/utils/collection/linear_alloc.h diff --git a/common/utils/collection/linear_alloc.h b/common/utils/collection/linear_alloc.h new file mode 100644 index 0000000000..ac8a305ff6 --- /dev/null +++ b/common/utils/collection/linear_alloc.h @@ -0,0 +1,71 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef LINEAR_ALLOC_H +#define LINEAR_ALLOC_H + +#include + +typedef unsigned int uid_t; +#define UID_LINEAR_ALLOCATOR_SIZE 1024 +#define UID_LINEAR_ALLOCATOR_BITMAP_SIZE (((UID_LINEAR_ALLOCATOR_SIZE/8)/sizeof(unsigned int)) + 1) +typedef struct uid_linear_allocator_s { + unsigned int bitmap[UID_LINEAR_ALLOCATOR_BITMAP_SIZE]; +} uid_allocator_t; + +static inline void uid_linear_allocator_init(uid_allocator_t *uia) { + memset(uia, 0, sizeof(uid_allocator_t)); +} + +static inline uid_t uid_linear_allocator_new(uid_allocator_t *uia) { + unsigned int bit_index = 1; + uid_t uid = 0; + + for (unsigned int i = 0; i < UID_LINEAR_ALLOCATOR_BITMAP_SIZE; i++) { + if (uia->bitmap[i] != UINT_MAX) { + bit_index = 1; + uid = 0; + + while ((uia->bitmap[i] & bit_index) == bit_index) { + bit_index = bit_index << 1; + uid += 1; + } + + uia->bitmap[i] |= bit_index; + return uid + (i*sizeof(unsigned int)*8); + } + } + + return UINT_MAX; +} + + +static inline void uid_linear_allocator_free(uid_allocator_t *uia, uid_t uid) { + const unsigned int i = uid/sizeof(unsigned int)/8; + const unsigned int bit = uid % (sizeof(unsigned int) * 8); + const unsigned int value = ~(1 << bit); + + if (i < UID_LINEAR_ALLOCATOR_BITMAP_SIZE) { + uia->bitmap[i] &= value; + } +} + +#endif /* LINEAR_ALLOC_H */ diff --git a/openair2/RRC/LTE/rrc_defs.h b/openair2/RRC/LTE/rrc_defs.h index 22c8a14863..f5841b09f8 100644 --- a/openair2/RRC/LTE/rrc_defs.h +++ b/openair2/RRC/LTE/rrc_defs.h @@ -36,11 +36,11 @@ #include #include "collection/tree.h" +#include "collection/linear_alloc.h" #include "common/ngran_types.h" #include "rrc_types.h" //#include "PHY/phy_defs.h" #include "LAYER2/RLC/rlc.h" -#include "RRC/NR/nr_rrc_types.h" #include "NR_UE-MRDC-Capability.h" #include "NR_UE-NR-Capability.h" @@ -219,17 +219,6 @@ void *send_UE_status_notification(void *); #include "commonDef.h" -//-------- -typedef unsigned int uid_t; -#define UID_LINEAR_ALLOCATOR_BITMAP_SIZE (((MAX_MOBILES_PER_ENB/8)/sizeof(unsigned int)) + 1) -typedef struct uid_linear_allocator_s { - unsigned int bitmap[UID_LINEAR_ALLOCATOR_BITMAP_SIZE]; -} uid_allocator_t; - -//-------- - - - #define PROTOCOL_RRC_CTXT_UE_FMT PROTOCOL_CTXT_FMT #define PROTOCOL_RRC_CTXT_UE_ARGS(CTXT_Pp) PROTOCOL_CTXT_ARGS(CTXT_Pp) @@ -668,8 +657,6 @@ typedef struct eNB_RRC_UE_s { int nr_capabilities_requested; } eNB_RRC_UE_t; -typedef uid_t ue_uid_t; - typedef struct rrc_eNB_ue_context_s { /* Tree related data */ RB_ENTRY(rrc_eNB_ue_context_s) entries; @@ -680,7 +667,7 @@ typedef struct rrc_eNB_ue_context_s { rnti_t ue_id_rnti; // another key for protocol layers but should not be used as a key for RB tree - ue_uid_t local_uid; + uid_t local_uid; /* UE id for initial connection to S1AP */ struct eNB_RRC_UE_s ue_context; @@ -762,7 +749,7 @@ typedef struct eNB_RRC_INST_s { char *node_name; uint32_t node_id; rrc_eNB_carrier_data_t carrier[MAX_NUM_CCs]; - uid_allocator_t uid_allocator; // for rrc_ue_head + uid_allocator_t uid_allocator; RB_HEAD(rrc_ue_tree_s, rrc_eNB_ue_context_s) rrc_ue_head; // ue_context tree key search by rnti uint8_t HO_flag; uint8_t Nb_ue; diff --git a/openair2/RRC/LTE/rrc_eNB_UE_context.c b/openair2/RRC/LTE/rrc_eNB_UE_context.c index 0d262064b5..c9077bfb24 100644 --- a/openair2/RRC/LTE/rrc_eNB_UE_context.c +++ b/openair2/RRC/LTE/rrc_eNB_UE_context.c @@ -37,64 +37,6 @@ #include "rrc_eNB_UE_context.h" -//------------------------------------------------------------------------------ -void -uid_linear_allocator_init( - uid_allocator_t *const uid_pP -) -//------------------------------------------------------------------------------ -{ - memset(uid_pP, 0, sizeof(uid_allocator_t)); -} - -//------------------------------------------------------------------------------ -uid_t -uid_linear_allocator_new( - eNB_RRC_INST *const rrc_instance_pP -) -//------------------------------------------------------------------------------ -{ - unsigned int i; - unsigned int bit_index = 1; - uid_t uid = 0; - uid_allocator_t *uia_p = &rrc_instance_pP->uid_allocator; - - for (i=0; i < UID_LINEAR_ALLOCATOR_BITMAP_SIZE; i++) { - if (uia_p->bitmap[i] != UINT_MAX) { - bit_index = 1; - uid = 0; - - while ((uia_p->bitmap[i] & bit_index) == bit_index) { - bit_index = bit_index << 1; - uid += 1; - } - - uia_p->bitmap[i] |= bit_index; - return uid + (i*sizeof(unsigned int)*8); - } - } - - return UINT_MAX; -} - - -//------------------------------------------------------------------------------ -void -uid_linear_allocator_free( - eNB_RRC_INST *rrc_instance_pP, - uid_t uidP -) -//------------------------------------------------------------------------------ -{ - unsigned int i = uidP/sizeof(unsigned int)/8; - unsigned int bit = uidP % (sizeof(unsigned int) * 8); - unsigned int value = ~(0x00000001 << bit); - - if (i < UID_LINEAR_ALLOCATOR_BITMAP_SIZE) { - rrc_instance_pP->uid_allocator.bitmap[i] &= value; - } -} - //------------------------------------------------------------------------------ int rrc_eNB_compare_ue_rnti_id( @@ -134,7 +76,7 @@ rrc_eNB_allocate_new_UE_context( } memset(new_p, 0, sizeof(struct rrc_eNB_ue_context_s)); - new_p->local_uid = uid_linear_allocator_new(rrc_instance_pP); + new_p->local_uid = uid_linear_allocator_new(&rrc_instance_pP->uid_allocator); for(int i = 0; i < NB_RB_MAX; i++) { new_p->ue_context.e_rab[i].xid = -1; @@ -210,7 +152,7 @@ void rrc_eNB_remove_ue_context( RB_REMOVE(rrc_ue_tree_s, &rrc_instance_pP->rrc_ue_head, ue_context_pP); rrc_eNB_free_mem_UE_context(ctxt_pP, ue_context_pP); - uid_linear_allocator_free(rrc_instance_pP, ue_context_pP->local_uid); + uid_linear_allocator_free(&rrc_instance_pP->uid_allocator, ue_context_pP->local_uid); free(ue_context_pP); rrc_instance_pP->Nb_ue --; LOG_I(RRC, diff --git a/openair2/RRC/LTE/rrc_eNB_UE_context.h b/openair2/RRC/LTE/rrc_eNB_UE_context.h index c6420ca936..89469529df 100644 --- a/openair2/RRC/LTE/rrc_eNB_UE_context.h +++ b/openair2/RRC/LTE/rrc_eNB_UE_context.h @@ -34,27 +34,6 @@ #include "COMMON/platform_types.h" #include "rrc_defs.h" - -void -uid_linear_allocator_init( - uid_allocator_t* const uid_pP -); - -uid_t -uid_linear_allocator_new( - eNB_RRC_INST* rrc_instance_pP -); - - -void -uid_linear_allocator_free( - eNB_RRC_INST* rrc_instance_pP, - uid_t uidP -); - - - - int rrc_eNB_compare_ue_rnti_id( struct rrc_eNB_ue_context_s* c1_pP, struct rrc_eNB_ue_context_s* c2_pP diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index c709a158da..e9d9766f41 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -36,12 +36,12 @@ #include #include "collection/tree.h" +#include "collection/linear_alloc.h" #include "nr_rrc_types.h" +#include "common/ngran_types.h" #include "COMMON/platform_constants.h" #include "COMMON/platform_types.h" -#include "RRC/LTE/rrc_defs.h" -//#include "LAYER2/RLC/rlc.h" #include "mac_rrc_dl.h" //#include "COMMON/mac_rrc_primitives.h" @@ -80,17 +80,6 @@ #include "commonDef.h" - -/*I will change the name of the structure for compile purposes--> hope not to undo this process*/ - -typedef unsigned int uid_nr_t; -#define NR_UID_LINEAR_ALLOCATOR_BITMAP_SIZE (((MAX_MOBILES_PER_GNB/8)/sizeof(unsigned int)) + 1) - -typedef struct nr_uid_linear_allocator_s { - unsigned int bitmap[NR_UID_LINEAR_ALLOCATOR_BITMAP_SIZE]; -} nr_uid_allocator_t; - - #define PROTOCOL_NR_RRC_CTXT_UE_FMT PROTOCOL_CTXT_FMT #define PROTOCOL_NR_RRC_CTXT_UE_ARGS(CTXT_Pp) PROTOCOL_NR_CTXT_ARGS(CTXT_Pp) @@ -283,12 +272,11 @@ typedef struct pdu_session_param_s { typedef struct gNB_RRC_UE_s { uint8_t primaryCC_id; - LTE_SCellToAddMod_r10_t sCell_config[2]; NR_SRB_ToAddModList_t *SRB_configList; - NR_SRB_ToAddModList_t *SRB_configList2[RRC_TRANSACTION_IDENTIFIER_NUMBER]; + NR_SRB_ToAddModList_t *SRB_configList2[NR_RRC_TRANSACTION_IDENTIFIER_NUMBER]; NR_DRB_ToAddModList_t *DRB_configList; - NR_DRB_ToAddModList_t *DRB_configList2[RRC_TRANSACTION_IDENTIFIER_NUMBER]; - NR_DRB_ToReleaseList_t *DRB_Release_configList2[RRC_TRANSACTION_IDENTIFIER_NUMBER]; + NR_DRB_ToAddModList_t *DRB_configList2[NR_RRC_TRANSACTION_IDENTIFIER_NUMBER]; + NR_DRB_ToReleaseList_t *DRB_Release_configList2[NR_RRC_TRANSACTION_IDENTIFIER_NUMBER]; uint8_t DRB_active[8]; NR_SRB_INFO SI; @@ -296,7 +284,7 @@ typedef struct gNB_RRC_UE_s { NR_SRB_INFO_TABLE_ENTRY Srb1; NR_SRB_INFO_TABLE_ENTRY Srb2; NR_MeasConfig_t *measConfig; - HANDOVER_INFO *handover_info; + NR_HANDOVER_INFO *handover_info; NR_MeasResults_t *measResults; @@ -353,7 +341,7 @@ typedef struct gNB_RRC_UE_s { /* Number of e_rab to be modified in the list */ uint8_t nb_of_modify_e_rabs; uint8_t nb_of_failed_e_rabs; - e_rab_param_t modify_e_rab[NB_RB_MAX];//[S1AP_MAX_E_RAB]; + nr_e_rab_param_t modify_e_rab[NB_RB_MAX];//[S1AP_MAX_E_RAB]; /* Total number of pdu session already setup in the list */ uint8_t setup_pdu_sessions; /* Number of pdu session to be setup in the list */ @@ -364,7 +352,7 @@ typedef struct gNB_RRC_UE_s { pdu_session_param_t modify_pdusession[NR_NB_RB_MAX]; /* list of e_rab to be setup by RRC layers */ /* list of pdu session to be setup by RRC layers */ - e_rab_param_t e_rab[NB_RB_MAX];//[S1AP_MAX_E_RAB]; + nr_e_rab_param_t e_rab[NB_RB_MAX];//[S1AP_MAX_E_RAB]; pdu_session_param_t pduSession[NR_NB_RB_MAX];//[NGAP_MAX_PDU_SESSION]; //release e_rabs uint8_t nb_release_of_e_rabs; @@ -411,8 +399,6 @@ typedef struct gNB_RRC_UE_s { } gNB_RRC_UE_t; -typedef uid_t ue_uid_t; - typedef struct rrc_gNB_ue_context_s { /* Tree related data */ RB_ENTRY(rrc_gNB_ue_context_s) entries; @@ -423,7 +409,7 @@ typedef struct rrc_gNB_ue_context_s { rnti_t ue_id_rnti; // another key for protocol layers but should not be used as a key for RB tree - ue_uid_t local_uid; + uid_t local_uid; /* UE id for initial connection to S1AP */ struct gNB_RRC_UE_s ue_context; @@ -495,7 +481,7 @@ typedef struct gNB_RRC_INST_s { int module_id; eth_params_t eth_params_s; rrc_gNB_carrier_data_t carrier; - nr_uid_allocator_t uid_allocator; // for rrc_ue_head + uid_allocator_t uid_allocator; RB_HEAD(rrc_nr_ue_tree_s, rrc_gNB_ue_context_s) rrc_ue_head; // ue_context tree key search by rnti int Nb_ue; hash_table_t *initial_id2_s1ap_ids; // key is content is rrc_ue_s1ap_ids_t diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 4340bfa6bd..bf122514ce 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -230,7 +230,7 @@ char openair_rrc_gNB_configuration(const module_id_t gnb_mod_idP, gNB_RrcConfigu rrc->Nb_ue = 0; rrc->carrier.Srb0.Active = 0; rrc_gNB_mac_rrc_init(rrc); - nr_uid_linear_allocator_init(&rrc->uid_allocator); + uid_linear_allocator_init(&rrc->uid_allocator); RB_INIT(&rrc->rrc_ue_head); rrc->initial_id2_s1ap_ids = hashtable_create (NUMBER_OF_UE_MAX * 2, NULL, NULL); rrc->s1ap_id2_s1ap_ids = hashtable_create (NUMBER_OF_UE_MAX * 2, NULL, NULL); diff --git a/openair2/RRC/NR/rrc_gNB_UE_context.c b/openair2/RRC/NR/rrc_gNB_UE_context.c index b8ff19b749..540ac5d075 100644 --- a/openair2/RRC/NR/rrc_gNB_UE_context.c +++ b/openair2/RRC/NR/rrc_gNB_UE_context.c @@ -37,61 +37,6 @@ #include "rrc_gNB_UE_context.h" -//------------------------------------------------------------------------------ -void nr_uid_linear_allocator_init( - nr_uid_allocator_t *const uid_pP -) -//------------------------------------------------------------------------------ -{ - memset(uid_pP, 0, sizeof(nr_uid_allocator_t)); -} - -//------------------------------------------------------------------------------ -uid_nr_t nr_uid_linear_allocator_new(gNB_RRC_INST *const rrc_instance_pP) -//------------------------------------------------------------------------------ -{ - unsigned int i; - unsigned int bit_index = 1; - uid_nr_t uid = 0; - nr_uid_allocator_t *uia_p = &rrc_instance_pP->uid_allocator; - - for (i=0; i < UID_LINEAR_ALLOCATOR_BITMAP_SIZE; i++) { - if (uia_p->bitmap[i] != UINT_MAX) { - bit_index = 1; - uid = 0; - - while ((uia_p->bitmap[i] & bit_index) == bit_index) { - bit_index = bit_index << 1; - uid += 1; - } - - uia_p->bitmap[i] |= bit_index; - return uid + (i*sizeof(unsigned int)*8); - } - } - - return UINT_MAX; -} - - -//------------------------------------------------------------------------------ -void -nr_uid_linear_allocator_free( - gNB_RRC_INST *rrc_instance_pP, - uid_nr_t uidP -) -//------------------------------------------------------------------------------ -{ - unsigned int i = uidP/sizeof(unsigned int)/8; - unsigned int bit = uidP % (sizeof(unsigned int) * 8); - unsigned int value = ~(0x00000001 << bit); - - if (i < UID_LINEAR_ALLOCATOR_BITMAP_SIZE) { - rrc_instance_pP->uid_allocator.bitmap[i] &= value; - } -} - - //------------------------------------------------------------------------------ int rrc_gNB_compare_ue_rnti_id( struct rrc_gNB_ue_context_s *c1_pP, struct rrc_gNB_ue_context_s *c2_pP) @@ -130,7 +75,7 @@ rrc_gNB_allocate_new_UE_context( } memset(new_p, 0, sizeof(struct rrc_gNB_ue_context_s)); - new_p->local_uid = nr_uid_linear_allocator_new(rrc_instance_pP); + new_p->local_uid = uid_linear_allocator_new(&rrc_instance_pP->uid_allocator); for(int i = 0; i < NB_RB_MAX; i++) { new_p->ue_context.e_rab[i].xid = -1; @@ -177,12 +122,12 @@ void rrc_gNB_free_mem_UE_context( { LOG_T(RRC, - PROTOCOL_RRC_CTXT_UE_FMT" Clearing UE context 0x%p (free internal structs)\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + PROTOCOL_NR_RRC_CTXT_UE_FMT" Clearing UE context 0x%p (free internal structs)\n", + PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP), ue_context_pP); - ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_LTE_SCellToAddMod_r10, &ue_context_pP->ue_context.sCell_config[0]); - ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_LTE_SCellToAddMod_r10, &ue_context_pP->ue_context.sCell_config[1]); + //ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_LTE_SCellToAddMod_r10, &ue_context_pP->ue_context.sCell_config[0]); + //ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_LTE_SCellToAddMod_r10, &ue_context_pP->ue_context.sCell_config[1]); // empty the internal fields of the UE context here } @@ -195,25 +140,25 @@ void rrc_gNB_remove_ue_context( //------------------------------------------------------------------------------ { if (rrc_instance_pP == NULL) { - LOG_E(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Bad RRC instance\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + LOG_E(RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" Bad RRC instance\n", + PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP)); return; } if (ue_context_pP == NULL) { - LOG_E(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Trying to free a NULL UE context\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + LOG_E(RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" Trying to free a NULL UE context\n", + PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP)); return; } RB_REMOVE(rrc_nr_ue_tree_s, &rrc_instance_pP->rrc_ue_head, ue_context_pP); rrc_gNB_free_mem_UE_context(ctxt_pP, ue_context_pP); - nr_uid_linear_allocator_free(rrc_instance_pP, ue_context_pP->local_uid); + uid_linear_allocator_free(&rrc_instance_pP->uid_allocator, ue_context_pP->local_uid); free(ue_context_pP); rrc_instance_pP->Nb_ue --; LOG_I(RRC, - PROTOCOL_RRC_CTXT_UE_FMT" Removed UE context\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + PROTOCOL_NR_RRC_CTXT_UE_FMT" Removed UE context\n", + PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP)); } //----------------------------------------------------------------------------- diff --git a/openair2/RRC/NR/rrc_gNB_UE_context.h b/openair2/RRC/NR/rrc_gNB_UE_context.h index 73bd93e737..4009f2617f 100644 --- a/openair2/RRC/NR/rrc_gNB_UE_context.h +++ b/openair2/RRC/NR/rrc_gNB_UE_context.h @@ -34,27 +34,6 @@ #include "COMMON/platform_types.h" #include "nr_rrc_defs.h" - -void -nr_uid_linear_allocator_init( - nr_uid_allocator_t* const uid_pP -); - -uid_t -nr_uid_linear_allocator_new( - gNB_RRC_INST* rrc_instance_pP -); - - -void -nr_uid_linear_allocator_free( - gNB_RRC_INST* rrc_instance_pP, - uid_t uidP -); - - - - int rrc_gNB_compare_ue_rnti_id( struct rrc_gNB_ue_context_s* c1_pP, struct rrc_gNB_ue_context_s* c2_pP diff --git a/openair2/RRC/NR_UE/L2_interface_ue.c b/openair2/RRC/NR_UE/L2_interface_ue.c index b4508e2627..8907ff315a 100644 --- a/openair2/RRC/NR_UE/L2_interface_ue.c +++ b/openair2/RRC/NR_UE/L2_interface_ue.c @@ -34,6 +34,7 @@ #include "rrc_proto.h" #include "assertions.h" #include "rrc_vars.h" +#include "MAC/mac.h" typedef uint32_t channel_t; From a126cd122099fa59bcb93450ea6db0d20a949b09 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 3 May 2022 14:42:49 +0200 Subject: [PATCH 257/267] Delete ITTI-SIM --- cmake_targets/CMakeLists.txt | 47 +- cmake_targets/build_oai | 10 - common/utils/ocp_itti/all_msg.h | 3 - common/utils/ocp_itti/intertask_interface.h | 4 - doc/ITTISIM.md | 48 -- openair2/COMMON/itti_sim_messages_def.h | 36 - openair2/COMMON/itti_sim_messages_types.h | 51 -- openair2/F1AP/f1ap_cu_ue_context_management.c | 3 - openair2/RRC/LTE/defs_NB_IoT.h | 3 - openair2/RRC/NR/mac_rrc_dl_direct.c | 15 - openair2/RRC/NR/rrc_gNB.c | 133 +--- openair2/RRC/NR/rrc_gNB_NGAP.c | 12 - openair2/RRC/NR_UE/rrc_UE.c | 105 --- openair2/SIMULATION/NR_RRC/itti_sim.c | 664 ------------------ openair3/NGAP/ngap_gNB_nas_procedures.c | 9 - 15 files changed, 3 insertions(+), 1140 deletions(-) delete mode 100755 doc/ITTISIM.md delete mode 100644 openair2/COMMON/itti_sim_messages_def.h delete mode 100644 openair2/COMMON/itti_sim_messages_types.h delete mode 100644 openair2/SIMULATION/NR_RRC/itti_sim.c diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index f8bcb2b548..9914d4abfa 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -845,7 +845,6 @@ add_boolean_option(UE_EXPANSION False "enable UE_EXPANSION w add_boolean_option(PHY_TX_THREAD False "enable UE_EXPANSION with max 256 UE") add_boolean_option(PRE_SCD_THREAD False "enable UE_EXPANSION with max 256 UE") add_boolean_option(UESIM_EXPANSION False "enable UESIM_EXPANSION with max 256 UE") -add_boolean_option(ITTI_SIM False "enable itti simulator") ######################## # Include order @@ -3034,7 +3033,7 @@ if (${T_TRACER}) foreach(i #all "add_executable" definitions (except tests, rb_tool, updatefw) lte-softmodem lte-uesoftmodem nr-softmodem - nr-uesoftmodem dlsim dlsim_tm4 dlsim_tm7 nr-ittisim + nr-uesoftmodem dlsim dlsim_tm4 dlsim_tm7 ulsim pbchsim scansim mbmssim pdcchsim pucchsim prachsim syncsim nr_ulsim nr_dlsim nr_dlschsim nr_pbchsim nr_pucchsim nr_ulschsim ldpctest polartest smallblocktest cu_test du_test @@ -3120,50 +3119,6 @@ add_executable(rb_tool ) target_include_directories(rb_tool PRIVATE ${OPENAIR2_DIR}/NETWORK_DRIVER/MESH/) -# nr-ittisim -################################################### - -add_executable(nr-ittisim - ${rrc_h} - ${nr_rrc_h} - ${OPENAIR2_DIR}/GNB_APP/gnb_app.c - ${OPENAIR2_DIR}/GNB_APP/gnb_config.c - ${OPENAIR_DIR}/executables/nr-gnb.c - ${OPENAIR_DIR}/executables/nr-ru.c - ${OPENAIR2_DIR}/SIMULATION/NR_RRC/itti_sim.c - ${OPENAIR_DIR}/executables/softmodem-common.c - ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c - ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c - ${OPENAIR_TARGETS}/ARCH/COMMON/record_player.c - ${OPENAIR2_DIR}/RRC/NAS/nas_config.c - ${OPENAIR2_DIR}/RRC/NAS/rb_config.c - ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c - ${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c - ${OPENAIR_DIR}/common/utils/nr/nr_common.c - ${OPENAIR_DIR}/common/utils/lte/ue_power.c - ${OPENAIR_DIR}/common/utils/lte/prach_utils.c - ${OPENAIR2_DIR}/ENB_APP/flexran_agent_ran_api_to_fix.c - ${XFORMSINTERFACE_SOURCE} - ${T_SOURCE} - ${SHLIB_LOADER_SOURCES} - ) - -target_link_libraries (nr-ittisim - -Wl,--start-group - UTIL HASHTABLE SCTP_CLIENT SCHED_LIB SCHED_RU_LIB SCHED_NR_LIB PHY_NR PHY PHY_COMMON PHY_NR_COMMON PHY_RU GTPV1U SECU_CN SECU_OSA - ITTI ${FLPT_MSG_LIB} ${FLEXRAN_AGENT_LIB} ${RAL_LIB} ${NAS_SIM_LIB} RRC_LIB NR_RRC_LIB - NGAP_LIB NGAP_GNB S1AP_LIB S1AP_ENB L2_LTE_NR L2_NR MAC_NR_COMMON NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB - X2AP_LIB X2AP_ENB F1AP_LIB F1AP M2AP_LIB M2AP_ENB M3AP_LIB M3AP_ENB ${FSPT_MSG_LIB} - PHY_NR_UE SCHED_NR_UE_LIB NR_L2_UE - -Wl,--end-group z dl) - -target_link_libraries (nr-ittisim ${LIBXML2_LIBRARIES}) -target_link_libraries (nr-ittisim pthread m CONFIG_LIB rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${XFORMS_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES} ${ATLAS_LIBRARIES}) -target_link_libraries (nr-ittisim ${LIB_LMS_LIBRARIES}) -target_link_libraries (nr-ittisim ${T_LIB}) - -add_dependencies( nr-ittisim ldpc_orig ldpc_optim ldpc_optim8seg ldpc ) - # ??? #################### list(APPEND oai_nw_drv_src device.c common.c ioctl.c classifier.c tool.c) diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 16a0d559dd..09029c285a 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -177,8 +177,6 @@ Options: Enable the address sanitizer on all targets --sanitize-undefined | -fsanitize=undefined Enable the undefined behavior sanitizer on all targets ---ittiSIM - Makes the itti simulator -h | --help Print this help @@ -465,11 +463,6 @@ function main() { --sanitize-undefined | -fundefined=address) CMAKE_CMD="$CMAKE_CMD -DSANITIZE_UNDEFINED=True" shift;; - --ittiSIM) - ittiSIM=1 - CMAKE_CMD="$CMAKE_CMD -DITTI_SIM=True" - echo_info "Will compile itti simulator" - shift;; -h | --help) print_help exit 1;; @@ -623,9 +616,6 @@ function main() { if [ "$nrUE" = 1 ] ; then execlist="$execlist nr-uesoftmodem" fi - if [ "$ittiSIM" = "1" ] ; then - execlist="$execlist nr-ittisim" - fi if [[ "$execlist" == "" && "$SIMUS_PHY" != "1" ]]; then echo_success "installing dependencies successful" diff --git a/common/utils/ocp_itti/all_msg.h b/common/utils/ocp_itti/all_msg.h index 8f7f48ed5a..c4bedc2cf6 100644 --- a/common/utils/ocp_itti/all_msg.h +++ b/common/utils/ocp_itti/all_msg.h @@ -17,7 +17,4 @@ #include "openair2/COMMON/flexran_messages_def.h" #include "openair2/COMMON/f1ap_messages_def.h" #include "openair2/COMMON/ngap_messages_def.h" -#if ITTI_SIM -#include "openair2/COMMON/itti_sim_messages_def.h" -#endif diff --git a/common/utils/ocp_itti/intertask_interface.h b/common/utils/ocp_itti/intertask_interface.h index e595311b26..636d305c13 100644 --- a/common/utils/ocp_itti/intertask_interface.h +++ b/common/utils/ocp_itti/intertask_interface.h @@ -262,10 +262,6 @@ void *rrc_enb_process_itti_msg(void *); #include #include -#ifdef ITTI_SIM - #include -#endif - /* static const char *const messages_definition_xml = { #include diff --git a/doc/ITTISIM.md b/doc/ITTISIM.md deleted file mode 100755 index 13fdd90846..0000000000 --- a/doc/ITTISIM.md +++ /dev/null @@ -1,48 +0,0 @@ - - - - - -
- - - - - - Running L3 ITTI simulator -
- -This page is valid on the following branches: - -- `develop` starting from tag `2020.w48` - -# 1. Building the ITTI simulator. - -The ITTI simulator is available directly from the standard build. - -```bash -$ source oaienv -$ cd cmake_targets -$ sudo ./build_oai -x -w None -c -ittiSIM -``` - -# 2. Running the ITTI simulator. - -The ITTI simulator establishes ITTI-threaded communication between the gNB RRC task and the UE RRC task. - -This allows to test the sequence of NGAP/RRC/NAS messages. - -The main limitations are: - -- NAS is a simple stub that just sends and receives messages -- only initial Attach sequence - -## 2.1. Starting the ITTI simulator - -The ITTI simulator is able to run with a connected 5GC or without any. -The develop branch tag `2020.w48` only works RRC without 5GC connection. - -```bash -$ sudo -E ./ran_build/build/nr-ittisim -O gnb.conf -``` - diff --git a/openair2/COMMON/itti_sim_messages_def.h b/openair2/COMMON/itti_sim_messages_def.h deleted file mode 100644 index 681fc932dd..0000000000 --- a/openair2/COMMON/itti_sim_messages_def.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file itti_sim_messages_def.h - * \brief itti message for itti simulator - * \author Yoshio INOUE, Masayuki HARADA - * \email yoshio.inoue@fujitsu.com,masayuki.harada@fujitsu.com - * \date 2020 - * \version 0.1 - */ - - - -MESSAGE_DEF(GNB_RRC_BCCH_DATA_IND, MESSAGE_PRIORITY_MED, itti_sim_rrc_ch_t, GNBBCCHind) -MESSAGE_DEF(GNB_RRC_CCCH_DATA_IND, MESSAGE_PRIORITY_MED, itti_sim_rrc_ch_t, GNBCCCHind) -MESSAGE_DEF(GNB_RRC_DCCH_DATA_IND, MESSAGE_PRIORITY_MED, itti_sim_rrc_ch_t, GNBDCCHind) -MESSAGE_DEF(UE_RRC_CCCH_DATA_IND, MESSAGE_PRIORITY_MED, itti_sim_rrc_ch_t, UECCCHind) -MESSAGE_DEF(UE_RRC_DCCH_DATA_IND, MESSAGE_PRIORITY_MED, itti_sim_rrc_ch_t, UEDCCHind) diff --git a/openair2/COMMON/itti_sim_messages_types.h b/openair2/COMMON/itti_sim_messages_types.h deleted file mode 100644 index 2e29e8f508..0000000000 --- a/openair2/COMMON/itti_sim_messages_types.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file itti_sim_messages_types.h - * \brief itti message for itti simulator - * \author Yoshio INOUE, Masayuki HARADA - * \email yoshio.inoue@fujitsu.com,masayuki.harada@fujitsu.com - * \date 2020 - * \version 0.1 - */ - -#ifndef ITTI_SIM_MESSAGES_TYPES_H_ -#define ITTI_SIM_MESSAGES_TYPES_H_ - -#include "LTE_asn_constant.h" - - - -#define GNB_RRC_BCCH_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.GNBBCCHind -#define GNB_RRC_CCCH_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.GNBCCCHind -#define GNB_RRC_DCCH_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.GNBDCCHind -#define UE_RRC_CCCH_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.UECCCHind -#define UE_RRC_DCCH_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.UEDCCHind - - - -typedef struct itti_sim_rrc_ch_s { - rb_id_t rbid; - uint8_t *sdu; - int size; -} itti_sim_rrc_ch_t; - -#endif /* ITTI_SIM_MESSAGES_TYPES_H_ */ diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index 0f3959d4ad..cf8d4ce260 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -973,9 +973,6 @@ int CU_handle_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, LOG_E(F1AP, "could not find ue_context of UE RNTI %x\n", rnti); } -#ifdef ITTI_SIM - return 0; -#endif } else { struct rrc_eNB_ue_context_s *ue_context_p = rrc_eNB_get_ue_context(RC.rrc[instance], rnti); diff --git a/openair2/RRC/LTE/defs_NB_IoT.h b/openair2/RRC/LTE/defs_NB_IoT.h index b98dbe22cc..17ef77ff17 100644 --- a/openair2/RRC/LTE/defs_NB_IoT.h +++ b/openair2/RRC/LTE/defs_NB_IoT.h @@ -37,9 +37,6 @@ #include "COMMON/s1ap_messages_types.h" #include "COMMON/rrc_messages_types.h" -#if ITTI_SIM -#include "COMMON/itti_sim_messages_types.h" -#endif #include "collection/tree.h" #include "rrc_types_NB_IoT.h" diff --git a/openair2/RRC/NR/mac_rrc_dl_direct.c b/openair2/RRC/NR/mac_rrc_dl_direct.c index b3ba7b9ee5..5c8d9d9d5b 100644 --- a/openair2/RRC/NR/mac_rrc_dl_direct.c +++ b/openair2/RRC/NR/mac_rrc_dl_direct.c @@ -26,24 +26,9 @@ static void dl_rrc_message_transfer_direct(module_id_t module_id, const f1ap_dl_rrc_message_t *dl_rrc) { -#ifdef ITTI_SIM - const int len = dl_rrc->rrc_container_length; - LOG_I(NR_RRC, - PROTOCOL_NR_RRC_CTXT_UE_FMT" [RAPROC] Logical Channel DL-CCCH, Generating RRCSetup (bytes %d)\n", - PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP), - len); - uint8_t *message_buffer; - message_buffer = itti_malloc(TASK_RRC_GNB, TASK_RRC_UE_SIM, len); - memcpy (message_buffer, dl_rrc->rrc_container, len); - message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, GNB_RRC_CCCH_DATA_IND); - GNB_RRC_CCCH_DATA_IND (message_p).sdu = message_buffer; - GNB_RRC_CCCH_DATA_IND (message_p).size = len; - itti_send_msg_to_task (TASK_RRC_UE_SIM, ctxt_pP->instance, message_p); -#else /* TODO how to manage inter-thread communication? */ dl_rrc_message(module_id, dl_rrc); -#endif } void mac_rrc_dl_direct_init(nr_mac_rrc_dl_if_t *mac_rrc) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index bf122514ce..1cacc1abb3 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -447,17 +447,6 @@ rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest( ue_context_pP->ue_context.ue_release_timer_thres = 1000; /* init timers */ // ue_context_pP->ue_context.ue_rrc_inactivity_timer = 0; -#ifdef ITTI_SIM - MessageDef *message_p; - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_GNB, TASK_RRC_UE_SIM, - ue_p->Srb0.Tx_buffer.payload_size); - memcpy (message_buffer, (uint8_t*)ue_p->Srb0.Tx_buffer.Payload, ue_p->Srb0.Tx_buffer.payload_size); - message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, GNB_RRC_CCCH_DATA_IND); - GNB_RRC_CCCH_DATA_IND (message_p).sdu = message_buffer; - GNB_RRC_CCCH_DATA_IND (message_p).size = ue_p->Srb0.Tx_buffer.payload_size; - itti_send_msg_to_task (TASK_RRC_UE_SIM, ctxt_pP->instance, message_p); -#endif } void @@ -507,16 +496,8 @@ rrc_gNB_generate_RRCReject( case ngran_gNB: { -#ifdef ITTI_SIM - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_GNB, TASK_RRC_UE_SIM, - ue_p->Srb0.Tx_buffer.payload_size); - memcpy (message_buffer, (uint8_t*)ue_p->Srb0.Tx_buffer.Payload, ue_p->Srb0.Tx_buffer.payload_size); - message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, GNB_RRC_CCCH_DATA_IND); - GNB_RRC_CCCH_DATA_IND (message_p).sdu = message_buffer; - GNB_RRC_CCCH_DATA_IND (message_p).size = ue_p->Srb0.Tx_buffer.payload_size; - itti_send_msg_to_task (TASK_RRC_UE_SIM, ctxt_pP->instance, message_p); -#endif + // NOTE: there was ITTI_SIM which has been removed. This case is maybe + // not necessary anymore // rrc_mac_config_req_gNB } break; @@ -724,17 +705,6 @@ rrc_gNB_generate_defaultRRCReconfiguration( case ngran_gNB: { -#ifdef ITTI_SIM - MessageDef *message_p; - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_GNB, TASK_RRC_UE_SIM, size); - memcpy (message_buffer, buffer, size); - message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, GNB_RRC_DCCH_DATA_IND); - GNB_RRC_DCCH_DATA_IND (message_p).rbid = DCCH; - GNB_RRC_DCCH_DATA_IND (message_p).sdu = message_buffer; - GNB_RRC_DCCH_DATA_IND (message_p).size = size; - itti_send_msg_to_task (TASK_RRC_UE_SIM, ctxt_pP->instance, message_p); -#else LOG_D(NR_RRC, "[FRAME %05d][RRC_gNB][MOD %u][][--- PDCP_DATA_REQ/%d Bytes (rrcReconfiguration to UE %x MUI %d) --->][PDCP][MOD %u][RB %u]\n", ctxt_pP->frame, ctxt_pP->module_id, @@ -751,7 +721,6 @@ rrc_gNB_generate_defaultRRCReconfiguration( buffer, PDCP_TRANSMISSION_MODE_CONTROL); // rrc_pdcp_config_asn1_req -#endif // rrc_rlc_config_asn1_req } break; @@ -1014,17 +983,6 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( "[FRAME %05d][RRC_gNB][MOD %u][][--- PDCP_DATA_REQ/%d Bytes (rrcReconfiguration to UE %x MUI %d) --->][PDCP][MOD %u][RB %u]\n", ctxt_pP->frame, ctxt_pP->module_id, size, ue_context_pP->ue_context.rnti, rrc_gNB_mui, ctxt_pP->module_id, DCCH); -#ifdef ITTI_SIM - MessageDef *message_p; - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_GNB_SIM, TASK_RRC_UE_SIM, size); - memcpy (message_buffer, buffer, size); - message_p = itti_alloc_new_message (TASK_RRC_GNB_SIM, 0, GNB_RRC_DCCH_DATA_IND); - GNB_RRC_DCCH_DATA_IND (message_p).rbid = DCCH; - GNB_RRC_DCCH_DATA_IND (message_p).sdu = message_buffer; - GNB_RRC_DCCH_DATA_IND (message_p).size = size; - itti_send_msg_to_task (TASK_RRC_UE_SIM, ctxt_pP->instance, message_p); -#else nr_rrc_data_req( ctxt_pP, DCCH, @@ -1033,7 +991,6 @@ rrc_gNB_generate_dedicatedRRCReconfiguration( size, buffer, PDCP_TRANSMISSION_MODE_CONTROL); -#endif if (NODE_IS_DU(rrc->node_type) || NODE_IS_MONOLITHIC(rrc->node_type)) { rrc_mac_config_req_gNB(rrc->module_id, @@ -1212,17 +1169,6 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( "[FRAME %05d][RRC_gNB][MOD %u][][--- PDCP_DATA_REQ/%d Bytes (rrcReconfiguration to UE %x MUI %d) --->][PDCP][MOD %u][RB %u]\n", ctxt_pP->frame, ctxt_pP->module_id, size, ue_context_pP->ue_context.rnti, rrc_gNB_mui, ctxt_pP->module_id, DCCH); -#ifdef ITTI_SIM - MessageDef *message_p; - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_GNB_SIM, TASK_RRC_UE_SIM, size); - memcpy (message_buffer, buffer, size); - message_p = itti_alloc_new_message (TASK_RRC_GNB_SIM, 0, GNB_RRC_DCCH_DATA_IND); - GNB_RRC_DCCH_DATA_IND (message_p).rbid = DCCH; - GNB_RRC_DCCH_DATA_IND (message_p).sdu = message_buffer; - GNB_RRC_DCCH_DATA_IND (message_p).size = size; - itti_send_msg_to_task (TASK_RRC_UE_SIM, ctxt_pP->instance, message_p); -#else nr_rrc_data_req( ctxt_pP, DCCH, @@ -1231,7 +1177,6 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( size, buffer, PDCP_TRANSMISSION_MODE_CONTROL); -#endif if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && @@ -1325,17 +1270,6 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( LOG_D(NR_RRC, "[FRAME %05d][RRC_gNB][MOD %u][][--- PDCP_DATA_REQ/%d Bytes (rrcReconfiguration to UE %x MUI %d) --->][PDCP][MOD %u][RB %u]\n", ctxt_pP->frame, ctxt_pP->module_id, size, ue_context_pP->ue_context.rnti, rrc_gNB_mui, ctxt_pP->module_id, DCCH); -#ifdef ITTI_SIM - MessageDef *message_p; - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_GNB, TASK_RRC_UE_SIM, size); - memcpy (message_buffer, buffer, size); - message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, GNB_RRC_DCCH_DATA_IND); - GNB_RRC_DCCH_DATA_IND (message_p).rbid = DCCH; - GNB_RRC_DCCH_DATA_IND (message_p).sdu = message_buffer; - GNB_RRC_DCCH_DATA_IND (message_p).size = size; - itti_send_msg_to_task (TASK_RRC_UE_SIM, ctxt_pP->instance, message_p); -#else nr_rrc_data_req( ctxt_pP, DCCH, @@ -1344,7 +1278,6 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( size, buffer, PDCP_TRANSMISSION_MODE_CONTROL); -#endif if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { uint32_t delay_ms = ue_context_pP->ue_context.masterCellGroup && @@ -1402,7 +1335,6 @@ rrc_gNB_process_RRCReconfigurationComplete( &kRRCint); /* Refresh SRBs/DRBs */ -#ifndef ITTI_SIM LOG_D(NR_RRC,"Configuring PDCP DRBs/SRBs for UE %x\n",ue_context_pP->ue_context.rnti); nr_rrc_pdcp_config_asn1_req(ctxt_pP, @@ -1428,7 +1360,6 @@ rrc_gNB_process_RRCReconfigurationComplete( NULL, get_softmodem_params()->sa ? ue_context_pP->ue_context.masterCellGroup->rlc_BearerToAddModList : NULL); } -#endif /* Set the SRB active in UE context */ if (SRB_configList != NULL) { @@ -1590,18 +1521,6 @@ rrc_gNB_generate_RRCReestablishment( rnti); } #endif -#ifdef ITTI_SIM - MessageDef *message_p; - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_GNB, TASK_RRC_UE_SIM, ue_context->Srb0.Tx_buffer.payload_size); - memcpy (message_buffer, (uint8_t *) ue_context->Srb0.Tx_buffer.Payload, ue_context->Srb0.Tx_buffer.payload_size); - message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, GNB_RRC_DCCH_DATA_IND); - GNB_RRC_DCCH_DATA_IND (message_p).rbid = DCCH; - GNB_RRC_DCCH_DATA_IND (message_p).sdu = message_buffer; - GNB_RRC_DCCH_DATA_IND (message_p).size = ue_context->Srb0.Tx_buffer.payload_size; - itti_send_msg_to_task (TASK_RRC_UE_SIM, ctxt_pP->instance, message_p); -#endif - } //----------------------------------------------------------------------------- @@ -1839,17 +1758,6 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete( LOG_D(NR_RRC, "[FRAME %05d][RRC_gNB][MOD %u][][--- PDCP_DATA_REQ/%d Bytes (rrcConnectionReconfiguration to UE %x MUI %d) --->][PDCP][MOD %u][RB %u]\n", ctxt_pP->frame, ctxt_pP->module_id, size, ue_context_pP->ue_context.rnti, rrc_gNB_mui, ctxt_pP->module_id, DCCH); -#ifdef ITTI_SIM - MessageDef *message_p; - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_GNB, TASK_RRC_UE_SIM, size); - memcpy (message_buffer, buffer, size); - message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, GNB_RRC_DCCH_DATA_IND); - GNB_RRC_DCCH_DATA_IND (message_p).rbid = DCCH; - GNB_RRC_DCCH_DATA_IND (message_p).sdu = message_buffer; - GNB_RRC_DCCH_DATA_IND (message_p).size = size; - itti_send_msg_to_task (TASK_RRC_UE_SIM, ctxt_pP->instance, message_p); -#else nr_rrc_data_req( ctxt_pP, DCCH, @@ -1858,7 +1766,6 @@ rrc_gNB_process_RRCConnectionReestablishmentComplete( size, buffer, PDCP_TRANSMISSION_MODE_CONTROL); -#endif } if (NODE_IS_DU(RC.nrrrc[ctxt_pP->module_id]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[ctxt_pP->module_id]->node_type)) { @@ -4210,17 +4117,6 @@ rrc_gNB_generate_SecurityModeCommand( size, rrc_gNB_mui, DCCH); -#ifdef ITTI_SIM - MessageDef *message_p; - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_GNB, TASK_RRC_UE_SIM,size); - memcpy (message_buffer, buffer, size); - message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, GNB_RRC_DCCH_DATA_IND); - GNB_RRC_DCCH_DATA_IND (message_p).rbid = DCCH; - GNB_RRC_DCCH_DATA_IND (message_p).sdu = message_buffer; - GNB_RRC_DCCH_DATA_IND (message_p).size = size; - itti_send_msg_to_task (TASK_RRC_UE_SIM, ctxt_pP->instance, message_p); -#else LOG_D(NR_RRC,"calling rrc_data_req :securityModeCommand\n"); nr_rrc_data_req(ctxt_pP, DCCH, @@ -4229,7 +4125,6 @@ rrc_gNB_generate_SecurityModeCommand( size, buffer, PDCP_TRANSMISSION_MODE_CONTROL); -#endif break; default : @@ -4282,17 +4177,6 @@ rrc_gNB_generate_UECapabilityEnquiry( size, rrc_gNB_mui, DCCH); -#ifdef ITTI_SIM - MessageDef *message_p; - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_GNB, TASK_RRC_UE_SIM, size); - memcpy (message_buffer, buffer, size); - message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, GNB_RRC_DCCH_DATA_IND); - GNB_RRC_DCCH_DATA_IND (message_p).rbid = DCCH; - GNB_RRC_DCCH_DATA_IND (message_p).sdu = message_buffer; - GNB_RRC_DCCH_DATA_IND (message_p).size = size; - itti_send_msg_to_task (TASK_RRC_UE_SIM, ctxt_pP->instance, message_p); -#else nr_rrc_data_req(ctxt_pP, DCCH, rrc_gNB_mui++, @@ -4300,7 +4184,6 @@ rrc_gNB_generate_UECapabilityEnquiry( size, buffer, PDCP_TRANSMISSION_MODE_CONTROL); -#endif break; default : @@ -4342,17 +4225,6 @@ rrc_gNB_generate_RRCRelease( rrc_gNB_mui, DCCH); -#ifdef ITTI_SIM - MessageDef *message_p; - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_GNB, TASK_RRC_UE_SIM, size); - memcpy (message_buffer, buffer, size); - message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, GNB_RRC_DCCH_DATA_IND); - GNB_RRC_DCCH_DATA_IND (message_p).rbid = DCCH; - GNB_RRC_DCCH_DATA_IND (message_p).sdu = message_buffer; - GNB_RRC_DCCH_DATA_IND (message_p).size = size; - itti_send_msg_to_task (TASK_RRC_UE_SIM, ctxt_pP->instance, message_p); -#else if (NODE_IS_CU(RC.nrrrc[ctxt_pP->module_id]->node_type)) { uint8_t *message_buffer = itti_malloc (TASK_RRC_GNB, TASK_CU_F1, size); memcpy (message_buffer, buffer, size); @@ -4375,7 +4247,6 @@ rrc_gNB_generate_RRCRelease( rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(ctxt_pP->instance, ue_context_pP->ue_context.gNB_ue_ngap_id); ue_context_pP->ue_context.ue_release_timer_rrc = 1; } -#endif } void nr_rrc_trigger(protocol_ctxt_t *ctxt, int CC_id, int frame, int subframe) { diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 8e1975ea11..8f391417e0 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -824,17 +824,6 @@ rrc_gNB_process_NGAP_DOWNLINK_NAS( case ngran_gNB: { // rrc_mac_config_req_gNB -#ifdef ITTI_SIM - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_GNB, TASK_RRC_UE_SIM, length); - memcpy (message_buffer, buffer, length); - MessageDef *message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, GNB_RRC_DCCH_DATA_IND); - GNB_RRC_DCCH_DATA_IND (message_p).rbid = DCCH; - GNB_RRC_DCCH_DATA_IND (message_p).sdu = message_buffer; - GNB_RRC_DCCH_DATA_IND (message_p).size = length; - itti_send_msg_to_task (TASK_RRC_UE_SIM, instance, message_p); - LOG_I(NR_RRC, "Send DL NAS message \n"); -#else /* Transfer data to PDCP */ nr_rrc_data_req ( &ctxt, @@ -844,7 +833,6 @@ rrc_gNB_process_NGAP_DOWNLINK_NAS( length, buffer, PDCP_TRANSMISSION_MODE_CONTROL); -#endif } break; diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 53817af48e..bf4f053ba6 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -1342,12 +1342,6 @@ static void rrc_ue_generate_RRCSetupComplete( int nas_msg_length; if (AMF_MODE_ENABLED) { -#if defined(ITTI_SIM) - as_nas_info_t initialNasMsg; - generateRegistrationRequest(&initialNasMsg, ctxt_pP->module_id); - nas_msg = (char*)initialNasMsg.data; - nas_msg_length = initialNasMsg.length; -#else if (get_softmodem_params()->sa) { as_nas_info_t initialNasMsg; generateRegistrationRequest(&initialNasMsg, ctxt_pP->module_id); @@ -1357,7 +1351,6 @@ static void rrc_ue_generate_RRCSetupComplete( nas_msg = (char *) NR_UE_rrc_inst[ctxt_pP->module_id].initialNasMsg.data; nas_msg_length = NR_UE_rrc_inst[ctxt_pP->module_id].initialNasMsg.length; } -#endif } else { nas_msg = nr_nas_attach_req_imsi; nas_msg_length = sizeof(nr_nas_attach_req_imsi); @@ -1381,18 +1374,6 @@ static void rrc_ue_generate_RRCSetupComplete( size, buffer, PDCP_TRANSMISSION_MODE_CONTROL); - -#ifdef ITTI_SIM - MessageDef *message_p; - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_NRUE, TASK_RRC_GNB_SIM, size); - memcpy (message_buffer, buffer, size); - message_p = itti_alloc_new_message (TASK_RRC_NRUE, 0, UE_RRC_DCCH_DATA_IND); - UE_RRC_DCCH_DATA_IND (message_p).rbid = 1; - UE_RRC_DCCH_DATA_IND (message_p).sdu = message_buffer; - UE_RRC_DCCH_DATA_IND (message_p).size = size; - itti_send_msg_to_task (TASK_RRC_GNB_SIM, ctxt_pP->instance, message_p); -#endif } int8_t nr_rrc_ue_decode_ccch( const protocol_ctxt_t *const ctxt_pP, const NR_SRB_INFO *const Srb_info, const uint8_t gNB_index ){ @@ -1711,19 +1692,6 @@ int8_t nr_rrc_ue_decode_ccch( const protocol_ctxt_t *const ctxt_pP, const NR_SRB } LOG_T(NR_RRC, "\n"); - #ifdef ITTI_SIM - MessageDef *message_p; - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_NRUE,TASK_RRC_GNB_SIM, - (enc_rval.encoded + 7) / 8); - memcpy (message_buffer, buffer, (enc_rval.encoded + 7) / 8); - - message_p = itti_alloc_new_message (TASK_RRC_NRUE, 0, UE_RRC_DCCH_DATA_IND); - GNB_RRC_DCCH_DATA_IND (message_p).rbid = DCCH; - GNB_RRC_DCCH_DATA_IND (message_p).sdu = message_buffer; - GNB_RRC_DCCH_DATA_IND (message_p).size = (enc_rval.encoded + 7) / 8; - itti_send_msg_to_task (TASK_RRC_GNB_SIM, ctxt_pP->instance, message_p); - #else rrc_data_req_nr_ue (ctxt_pP, DCCH, nr_rrc_mui++, @@ -1731,7 +1699,6 @@ int8_t nr_rrc_ue_decode_ccch( const protocol_ctxt_t *const ctxt_pP, const NR_SRB (enc_rval.encoded + 7) / 8, buffer, PDCP_TRANSMISSION_MODE_CONTROL); - #endif } else LOG_W(NR_RRC,"securityModeCommand->criticalExtensions.present (%d) != NR_SecurityModeCommand__criticalExtensions_PR_securityModeCommand\n", securityModeCommand->criticalExtensions.present); @@ -1777,19 +1744,6 @@ int8_t nr_rrc_ue_decode_ccch( const protocol_ctxt_t *const ctxt_pP, const NR_SRB //printf("\n"); /*UE_rrc_inst[ue_mod_idP].Srb0[Idx].Tx_buffer.Payload[i] = taus()&0xff; UE_rrc_inst[ue_mod_idP].Srb0[Idx].Tx_buffer.payload_size =i; */ - -#ifdef ITTI_SIM - MessageDef *message_p; - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_NRUE,TASK_RRC_GNB_SIM, - NR_UE_rrc_inst[module_id].Srb0[gNB_index].Tx_buffer.payload_size); - memcpy (message_buffer, (uint8_t*)NR_UE_rrc_inst[module_id].Srb0[gNB_index].Tx_buffer.Payload, - NR_UE_rrc_inst[module_id].Srb0[gNB_index].Tx_buffer.payload_size); - message_p = itti_alloc_new_message (TASK_RRC_NRUE, 0, UE_RRC_CCCH_DATA_IND); - GNB_RRC_CCCH_DATA_IND (message_p).sdu = message_buffer; - GNB_RRC_CCCH_DATA_IND (message_p).size = NR_UE_rrc_inst[module_id].Srb0[gNB_index].Tx_buffer.payload_size; - itti_send_msg_to_task (TASK_RRC_GNB_SIM, gNB_index, message_p); -#endif } } @@ -2254,19 +2208,6 @@ nr_rrc_ue_establish_srb2( nr_rrc_mui, UE_MODULE_ID_TO_INSTANCE(ctxt_pP->module_id), DCCH); - #ifdef ITTI_SIM - MessageDef *message_p; - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_NRUE,TASK_RRC_GNB_SIM,size); - memcpy (message_buffer, buffer, size); - - message_p = itti_alloc_new_message (TASK_RRC_NRUE, 0, UE_RRC_DCCH_DATA_IND); - UE_RRC_DCCH_DATA_IND (message_p).rbid = DCCH; - UE_RRC_DCCH_DATA_IND (message_p).sdu = message_buffer; - UE_RRC_DCCH_DATA_IND (message_p).size = size; - itti_send_msg_to_task (TASK_RRC_GNB_SIM, ctxt_pP->instance, message_p); - - #else rrc_data_req_nr_ue ( ctxt_pP, DCCH, @@ -2275,8 +2216,6 @@ nr_rrc_ue_establish_srb2( size, buffer, PDCP_TRANSMISSION_MODE_CONTROL); - #endif - } // from NR SRB1 @@ -2523,22 +2462,6 @@ nr_rrc_ue_establish_srb2( length = do_NR_ULInformationTransfer(&buffer, NAS_UPLINK_DATA_REQ (msg_p).nasMsg.length, NAS_UPLINK_DATA_REQ (msg_p).nasMsg.data); /* Transfer data to PDCP */ PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, ue_mod_id, GNB_FLAG_NO, NR_UE_rrc_inst[ue_mod_id].Info[0].rnti, 0, 0,0); -#ifdef ITTI_SIM - MessageDef *message_p; - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_NRUE,TASK_RRC_GNB_SIM,length); - memcpy (message_buffer, buffer, length); - - message_p = itti_alloc_new_message (TASK_RRC_NRUE, 0, UE_RRC_DCCH_DATA_IND); - if(NR_UE_rrc_inst[ue_mod_id].SRB2_config[0] == NULL) - UE_RRC_DCCH_DATA_IND (message_p).rbid = DCCH; - else - UE_RRC_DCCH_DATA_IND (message_p).rbid = DCCH1; - UE_RRC_DCCH_DATA_IND (message_p).sdu = message_buffer; - UE_RRC_DCCH_DATA_IND (message_p).size = length; - itti_send_msg_to_task (TASK_RRC_GNB_SIM, ctxt.instance, message_p); - -#else // check if SRB2 is created, if yes request data_req on DCCH1 (SRB2) if(NR_UE_rrc_inst[ue_mod_id].SRB2_config[0] == NULL) { rrc_data_req_nr_ue (&ctxt, @@ -2555,7 +2478,6 @@ nr_rrc_ue_establish_srb2( length, buffer, PDCP_TRANSMISSION_MODE_CONTROL); } -#endif break; } @@ -2699,19 +2621,6 @@ nr_rrc_ue_process_ueCapabilityEnquiry( } LOG_I(NR_RRC, "UECapabilityInformation Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); -#ifdef ITTI_SIM - MessageDef *message_p; - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_NRUE,TASK_RRC_GNB_SIM, - (enc_rval.encoded + 7) / 8); - memcpy (message_buffer, buffer, (enc_rval.encoded + 7) / 8); - - message_p = itti_alloc_new_message (TASK_RRC_NRUE, 0, UE_RRC_DCCH_DATA_IND); - GNB_RRC_DCCH_DATA_IND (message_p).rbid = DCCH; - GNB_RRC_DCCH_DATA_IND (message_p).sdu = message_buffer; - GNB_RRC_DCCH_DATA_IND (message_p).size = (enc_rval.encoded + 7) / 8; - itti_send_msg_to_task (TASK_RRC_GNB_SIM, ctxt_pP->instance, message_p); -#else rrc_data_req_nr_ue ( ctxt_pP, DCCH, @@ -2720,7 +2629,6 @@ nr_rrc_ue_process_ueCapabilityEnquiry( (enc_rval.encoded + 7) / 8, buffer, PDCP_TRANSMISSION_MODE_CONTROL); -#endif } } } @@ -2739,19 +2647,6 @@ nr_rrc_ue_generate_rrcReestablishmentComplete( rrcReestablishment->rrc_TransactionIdentifier); LOG_I(NR_RRC,"[UE %d][RAPROC] Frame %d : Logical Channel UL-DCCH (SRB1), Generating RRCReestablishmentComplete (bytes%d, gNB %d)\n", ctxt_pP->module_id,ctxt_pP->frame, length, gNB_index); -#ifdef ITTI_SIM - MessageDef *message_p; - uint8_t *message_buffer; - message_buffer = itti_malloc (TASK_RRC_NRUE,TASK_RRC_GNB_SIM,length); - memcpy (message_buffer, buffer, length); - - message_p = itti_alloc_new_message (TASK_RRC_NRUE, 0, UE_RRC_DCCH_DATA_IND); - UE_RRC_DCCH_DATA_IND (message_p).rbid = DCCH; - UE_RRC_DCCH_DATA_IND (message_p).sdu = message_buffer; - UE_RRC_DCCH_DATA_IND (message_p).size = length; - itti_send_msg_to_task (TASK_RRC_GNB_SIM, ctxt_pP->instance, message_p); - -#endif } void *recv_msgs_from_lte_ue(void *args_p) diff --git a/openair2/SIMULATION/NR_RRC/itti_sim.c b/openair2/SIMULATION/NR_RRC/itti_sim.c deleted file mode 100644 index a6ac444e45..0000000000 --- a/openair2/SIMULATION/NR_RRC/itti_sim.c +++ /dev/null @@ -1,664 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file itti_sim.c - * \brief simulator for itti message from node to UE - * \author Yoshio INOUE, Masayuki HARADA - * \email yoshio.inoue@fujitsu.com,masayuki.harada@fujitsu.com - * \date 2020 - * \version 0.1 - */ - - -#include - - -#include "T.h" - -#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all -#include - -#include "common/ran_context.h" - -#include "common/config/config_userapi.h" -#include "common/utils/load_module_shlib.h" -#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all - -#include "PHY/phy_vars.h" -#include "SCHED/sched_common_vars.h" -#include "LAYER2/MAC/mac_vars.h" -#include "RRC/LTE/rrc_vars.h" -#include "gnb_config.h" -#include "SIMULATION/TOOLS/sim.h" - -#ifdef SMBV -#include "PHY/TOOLS/smbv.h" -unsigned short config_frames[4] = {2,9,11,13}; -#endif - -#include "common/utils/LOG/log.h" -#include "common/utils/LOG/vcd_signal_dumper.h" -#include "UTIL/OPT/opt.h" - -#include "intertask_interface.h" - - -#include "system.h" -#include -#include "PHY/TOOLS/phy_scope_interface.h" -#include "PHY/TOOLS/nr_phy_scope.h" -#include "stats.h" -#include "nr-softmodem.h" -#include "executables/softmodem-common.h" -#include "executables/thread-common.h" -#include "NB_IoT_interface.h" -#include "x2ap_eNB.h" -#include "ngap_gNB.h" -#include "RRC/NR_UE/rrc_proto.h" -#include "RRC/NR_UE/rrc_vars.h" -#include "openair3/NAS/UE/nas_ue_task.h" -#include -#include -#if ITTI_SIM -#include "nr_nas_msg_sim.h" -#endif - -pthread_cond_t nfapi_sync_cond; -pthread_mutex_t nfapi_sync_mutex; -int nfapi_sync_var=-1; //!< protected by mutex \ref nfapi_sync_mutex - -uint32_t timing_advance = 0; -uint64_t num_missed_slots=0; - -int split73=0; -void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen, int r_offset) { - AssertFatal(false, "Must not be called in this context\n"); -} -void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask, uint16_t rnti, int32_t stat) { - AssertFatal(false, "Must not be called in this context\n"); -} - -nrUE_params_t nrUE_params; -nrUE_params_t *get_nrUE_params(void) { - return &nrUE_params; -} - -void processSlotTX(void *arg) {} - -THREAD_STRUCT thread_struct; -pthread_cond_t sync_cond; -pthread_mutex_t sync_mutex; -int sync_var=-1; //!< protected by mutex \ref sync_mutex. -int config_sync_var=-1; - -openair0_config_t openair0_cfg[MAX_CARDS]; - -//volatile int start_gNB = 0; -volatile int oai_exit = 0; - -//static int wait_for_sync = 0; - -unsigned int mmapped_dma=0; -int single_thread_flag=1; - -int8_t threequarter_fs=0; - -uint64_t downlink_frequency[MAX_NUM_CCs][4]; -int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; - -//Temp fix for inexistent NR upper layer -unsigned char NB_gNB_INST = 1; - - -int UE_scan = 1; -int UE_scan_carrier = 0; -runmode_t mode = normal_txrx; -static double snr_dB=20; - -FILE *input_fd=NULL; - -int chain_offset=0; - - -uint8_t dci_Format = 0; -uint8_t agregation_Level =0xFF; - -uint8_t nb_antenna_tx = 1; -uint8_t nb_antenna_rx = 1; - -char ref[128] = "internal"; -char channels[128] = "0"; - -int otg_enabled; - -extern void *udp_eNB_task(void *args_p); - -int transmission_mode=1; -int emulate_rf = 0; -int numerology = 0; - - -double cpuf; - -extern char uecap_xer[1024]; -char uecap_xer_in=0; - -/* see file openair2/LAYER2/MAC/main.c for why abstraction_flag is needed - * this is very hackish - find a proper solution - */ -uint8_t abstraction_flag=0; - -/* forward declarations */ -void set_default_frame_parms(nfapi_nr_config_request_scf_t *config[MAX_NUM_CCs], NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]); - -/*---------------------BMC: timespec helpers -----------------------------*/ - -struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; -struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; - -struct timespec clock_difftime(struct timespec start, struct timespec end) { - struct timespec temp; - - if ((end.tv_nsec-start.tv_nsec)<0) { - temp.tv_sec = end.tv_sec-start.tv_sec-1; - temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; - } else { - temp.tv_sec = end.tv_sec-start.tv_sec; - temp.tv_nsec = end.tv_nsec-start.tv_nsec; - } - - return temp; -} - - - -#define KNRM "\x1B[0m" -#define KRED "\x1B[31m" -#define KGRN "\x1B[32m" -#define KBLU "\x1B[34m" -#define RESET "\033[0m" - - -void exit_function(const char *file, const char *function, const int line, const char *s) { - int ru_id; - - if (s != NULL) { - printf("%s:%d %s() Exiting OAI softmodem: %s\n",file,line, function, s); - } - - oai_exit = 1; - - if (RC.ru == NULL) - exit(-1); // likely init not completed, prevent crash or hang, exit now... - - for (ru_id=0; ru_idrfdevice.trx_end_func) { - RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice); - RC.ru[ru_id]->rfdevice.trx_end_func = NULL; - } - - if (RC.ru[ru_id] && RC.ru[ru_id]->ifdevice.trx_end_func) { - RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice); - RC.ru[ru_id]->ifdevice.trx_end_func = NULL; - } - } - - sleep(1); //allow lte-softmodem threads to exit first - exit(1); -} - -void wait_gNBs(void) { - int i; - int waiting=1; - - while (waiting==1) { - printf("Waiting for gNB L1 instances to all get configured ... sleeping 50ms (nb_nr_sL1_inst %d)\n",RC.nb_nr_L1_inst); - usleep(50*1000); - waiting=0; - - for (i=0; iconfigured==0) { - waiting=1; - break; - } - } - } - - printf("gNB L1 are configured\n"); -} - -void wait_RUs(void) { - LOG_I(PHY,"Waiting for RUs to be configured ... RC.ru_mask:%02lx\n", RC.ru_mask); - // wait for all RUs to be configured over fronthaul - pthread_mutex_lock(&RC.ru_mutex); - - while (RC.ru_mask>0) { - pthread_cond_wait(&RC.ru_cond,&RC.ru_mutex); - printf("RC.ru_mask:%02lx\n", RC.ru_mask); - } - - pthread_mutex_unlock(&RC.ru_mutex); - LOG_I(PHY,"RUs configured\n"); -} - - -int stop_L1L2(module_id_t gnb_id) { - return 0; -} - -int restart_L1L2(module_id_t gnb_id) { - return 0; -} - -int create_gNB_tasks(uint32_t gnb_nb) { - LOG_D(GNB_APP, "%s(gnb_nb:%d)\n", __FUNCTION__, gnb_nb); - itti_wait_ready(1); - - - if (gnb_nb > 0) { - if(itti_create_task(TASK_SCTP, sctp_eNB_task, NULL) < 0){ - LOG_E(SCTP, "Create task for SCTP failed\n"); - return -1; - } - if (is_x2ap_enabled()) { - if(itti_create_task(TASK_X2AP, x2ap_task, NULL) < 0){ - LOG_E(X2AP, "Create task for X2AP failed\n"); - } - } - else { - LOG_I(X2AP, "X2AP is disabled.\n"); - } - } - - if (AMF_MODE_ENABLED && (get_softmodem_params()->phy_test==0 && get_softmodem_params()->do_ra==0 && get_softmodem_params()->sa==0)) { - if (gnb_nb > 0) { - if (itti_create_task (TASK_NGAP, ngap_gNB_task, NULL) < 0) { - LOG_E(S1AP, "Create task for NGAP failed\n"); - return -1; - } - - - if(!emulate_rf){ - if (itti_create_task (TASK_UDP, udp_eNB_task, NULL) < 0) { - LOG_E(UDP_, "Create task for UDP failed\n"); - return -1; - } - } - - if (itti_create_task (TASK_GTPV1_U, &nr_gtpv1u_gNB_task, NULL) < 0) { - LOG_E(GTPU, "Create task for GTPV1U failed\n"); - return -1; - } - } - } - - - if (gnb_nb > 0) { - if (itti_create_task (TASK_GNB_APP, gNB_app_task, NULL) < 0) { - LOG_E(GNB_APP, "Create task for gNB APP failed\n"); - return -1; - } - LOG_I(NR_RRC,"Creating NR RRC gNB Task\n"); - - if (itti_create_task (TASK_RRC_GNB, rrc_gnb_task, NULL) < 0) { - LOG_E(NR_RRC, "Create task for NR RRC gNB failed\n"); - return -1; - } - } - - return 0; -} - - -static void get_options(void) { - - - paramdef_t cmdline_params[] = CMDLINE_PARAMS_DESC_GNB ; - - CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP); - get_common_options(SOFTMODEM_GNB_BIT ); - config_process_cmdline( cmdline_params,sizeof(cmdline_params)/sizeof(paramdef_t),NULL); - CONFIG_CLEARRTFLAG(CONFIG_NOEXITONHELP); - - - - - if ( !(CONFIG_ISFLAGSET(CONFIG_ABORT)) ) { - memset((void *)&RC,0,sizeof(RC)); - /* Read RC configuration file */ - NRRCConfig(); - NB_gNB_INST = RC.nb_nr_inst; - NB_RU = RC.nb_RU; - printf("Configuration: nb_rrc_inst %d, nb_nr_L1_inst %d, nb_ru %hhu\n",NB_gNB_INST,RC.nb_nr_L1_inst,NB_RU); - } - -} - - -void set_default_frame_parms(nfapi_nr_config_request_scf_t *config[MAX_NUM_CCs], - NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) -{ - for (int CC_id=0; CC_idssb_config.scs_common.value = 1; - config[CC_id]->cell_config.frame_duplex_type.value = 1; //FDD - config[CC_id]->carrier_config.dl_grid_size[1].value = 106; - config[CC_id]->carrier_config.ul_grid_size[1].value = 106; - config[CC_id]->cell_config.phy_cell_id.value = 0; - } -} - -/* - * helper function to terminate a certain ITTI task - */ -void terminate_task(task_id_t task_id, module_id_t mod_id) { - LOG_I(GNB_APP, "sending TERMINATE_MESSAGE to task %s (%d)\n", itti_get_task_name(task_id), task_id); - MessageDef *msg; - msg = itti_alloc_new_message (ENB_APP, 0, TERMINATE_MESSAGE); - itti_send_msg_to_task (task_id, ENB_MODULE_ID_TO_INSTANCE(mod_id), msg); -} - -//extern void free_transport(PHY_VARS_gNB *); -extern void nr_phy_free_RU(RU_t *); - -statis void init_pdcp(void) { - //if (!NODE_IS_DU(RC.rrc[0]->node_type)) { - pdcp_layer_init(); - uint32_t pdcp_initmask = (IS_SOFTMODEM_NOS1) ? - (PDCP_USE_NETLINK_BIT | LINK_ENB_PDCP_TO_IP_DRIVER_BIT) : LINK_ENB_PDCP_TO_GTPV1U_BIT; - - if (IS_SOFTMODEM_NOS1) { - printf("IS_SOFTMODEM_NOS1 option enabled \n"); - pdcp_initmask = pdcp_initmask | ENB_NAS_USE_TUN_BIT | SOFTMODEM_NOKRNMOD_BIT ; - } - - pdcp_module_init(pdcp_initmask, 0); - - pdcp_set_rlc_data_req_func(rlc_data_req); - pdcp_set_pdcp_data_ind_func(pdcp_data_ind); -} - - -int create_tasks_nrue(uint32_t ue_nb) { - LOG_D(ENB_APP, "%s(ue_nb:%d)\n", __FUNCTION__, ue_nb); - itti_wait_ready(1); - - if (ue_nb > 0) { - LOG_D(NR_RRC, "create TASK_RRC_NRUE\n"); - if (itti_create_task (TASK_RRC_NRUE, rrc_nrue_task, NULL) < 0) { - LOG_E(NR_RRC, "Create task for RRC UE failed\n"); - return -1; - } - - LOG_D(NR_RRC,"create TASK_NAS_NRUE\n"); - if (itti_create_task (TASK_NAS_NRUE, nas_nrue_task, NULL) < 0) { - LOG_E(NR_RRC, "Create task for NAS UE failed\n"); - return -1; - } - } - - - itti_wait_ready(0); - return 0; -} - - -void *itti_sim_ue_rrc_task( void *args_p) { - MessageDef *msg_p, *message_p; - instance_t instance; - unsigned int ue_mod_id; - int result; - itti_mark_task_ready (TASK_RRC_UE_SIM); - - while(1) { - // Wait for a message - itti_receive_msg (TASK_RRC_UE_SIM, &msg_p); - instance = ITTI_MSG_DESTINATION_INSTANCE (msg_p); - ue_mod_id = UE_INSTANCE_TO_MODULE_ID(instance); - - switch (ITTI_MSG_ID(msg_p)) { - case TERMINATE_MESSAGE: - LOG_W(NR_RRC, " *** Exiting RRC thread\n"); - itti_exit_task (); - break; - - case MESSAGE_TEST: - LOG_D(NR_RRC, "[UE %d] Received %s\n", ue_mod_id, ITTI_MSG_NAME (msg_p)); - break; - case GNB_RRC_BCCH_DATA_IND: - message_p = itti_alloc_new_message (TASK_RRC_UE_SIM, 0, NR_RRC_MAC_BCCH_DATA_IND); - memset (NR_RRC_MAC_BCCH_DATA_IND (message_p).sdu, 0, BCCH_SDU_SIZE); - NR_RRC_MAC_BCCH_DATA_IND (message_p).sdu_size = GNB_RRC_BCCH_DATA_IND(msg_p).size; - memcpy (NR_RRC_MAC_BCCH_DATA_IND (message_p).sdu, GNB_RRC_BCCH_DATA_IND(msg_p).sdu, GNB_RRC_BCCH_DATA_IND(msg_p).size); - itti_send_msg_to_task (TASK_RRC_NRUE, instance, message_p); - break; - case GNB_RRC_CCCH_DATA_IND: - message_p = itti_alloc_new_message (TASK_RRC_UE_SIM, 0, NR_RRC_MAC_CCCH_DATA_IND); - printf("receive GNB_RRC_CCCH_DATA_IND\n"); - memset (NR_RRC_MAC_CCCH_DATA_IND (message_p).sdu, 0, CCCH_SDU_SIZE); - memcpy (NR_RRC_MAC_CCCH_DATA_IND (message_p).sdu, GNB_RRC_CCCH_DATA_IND(msg_p).sdu, GNB_RRC_CCCH_DATA_IND(msg_p).size); - NR_RRC_MAC_CCCH_DATA_IND (message_p).sdu_size = GNB_RRC_CCCH_DATA_IND(msg_p).size; - itti_send_msg_to_task (TASK_RRC_NRUE, instance, message_p); - break; - case GNB_RRC_DCCH_DATA_IND: - printf("receive GNB_RRC_DCCH_DATA_IND\n"); - message_p = itti_alloc_new_message (TASK_RRC_UE_SIM, 0, NR_RRC_DCCH_DATA_IND); - NR_RRC_DCCH_DATA_IND (message_p).dcch_index = GNB_RRC_DCCH_DATA_IND(msg_p).rbid; - NR_RRC_DCCH_DATA_IND (message_p).sdu_size = GNB_RRC_DCCH_DATA_IND(msg_p).size; - NR_RRC_DCCH_DATA_IND (message_p).sdu_p = GNB_RRC_DCCH_DATA_IND(msg_p).sdu; - itti_send_msg_to_task (TASK_RRC_NRUE, instance, message_p); - break; - default: - LOG_E(NR_RRC, "[UE %d] Received unexpected message %s\n", ue_mod_id, ITTI_MSG_NAME (msg_p)); - break; - } - - result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p); - AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); - msg_p = NULL; - } -} - - -void *itti_sim_gnb_rrc_task( void *args_p) { - MessageDef *msg_p, *message_p; - instance_t instance; - unsigned int ue_mod_id; - int result; - itti_mark_task_ready (TASK_RRC_GNB_SIM); - - while(1) { - // Wait for a message - itti_receive_msg (TASK_RRC_GNB_SIM, &msg_p); - instance = ITTI_MSG_DESTINATION_INSTANCE (msg_p); - ue_mod_id = UE_INSTANCE_TO_MODULE_ID(instance); - - switch (ITTI_MSG_ID(msg_p)) { - case TERMINATE_MESSAGE: - LOG_W(NR_RRC, " *** Exiting RRC thread\n"); - itti_exit_task (); - break; - - case MESSAGE_TEST: - LOG_D(NR_RRC, "[UE %d] Received %s\n", ue_mod_id, ITTI_MSG_NAME (msg_p)); - break; - case UE_RRC_CCCH_DATA_IND: - message_p = itti_alloc_new_message (TASK_RRC_GNB_SIM, 0, NR_RRC_MAC_CCCH_DATA_IND); - NR_RRC_MAC_CCCH_DATA_IND (message_p).sdu_size = UE_RRC_CCCH_DATA_IND(msg_p).size; - memset (NR_RRC_MAC_CCCH_DATA_IND (message_p).sdu, 0, CCCH_SDU_SIZE); - memcpy (NR_RRC_MAC_CCCH_DATA_IND (message_p).sdu, UE_RRC_CCCH_DATA_IND(msg_p).sdu, UE_RRC_CCCH_DATA_IND(msg_p).size); - itti_send_msg_to_task (TASK_RRC_GNB, instance, message_p); - break; - case UE_RRC_DCCH_DATA_IND: - message_p = itti_alloc_new_message (TASK_RRC_GNB_SIM, 0, NR_RRC_DCCH_DATA_IND); - NR_RRC_DCCH_DATA_IND (message_p).sdu_size = UE_RRC_DCCH_DATA_IND(msg_p).size; - NR_RRC_DCCH_DATA_IND (message_p).dcch_index = UE_RRC_DCCH_DATA_IND(msg_p).rbid; - NR_RRC_DCCH_DATA_IND (message_p).sdu_p = UE_RRC_DCCH_DATA_IND(msg_p).sdu; - itti_send_msg_to_task (TASK_RRC_GNB, instance, message_p); - break; - - default: - LOG_E(NR_RRC, "[UE %d] Received unexpected message %s\n", ue_mod_id, ITTI_MSG_NAME (msg_p)); - break; - } - - result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p); - AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); - msg_p = NULL; - } -} - - -int main( int argc, char **argv ) -{ - start_background_system(); - - ///static configuration for NR at the moment - if ( load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY) == NULL) { - exit_fun("[SOFTMODEM] Error, configuration module init failed\n"); - } - set_softmodem_sighandler(); -#ifdef DEBUG_CONSOLE - setvbuf(stdout, NULL, _IONBF, 0); - setvbuf(stderr, NULL, _IONBF, 0); -#endif - - logInit(); - //set_latency_target(); - printf("Reading in command-line options\n"); - get_options (); - - if (CONFIG_ISFLAGSET(CONFIG_ABORT) ) { - fprintf(stderr,"Getting configuration failed\n"); - exit(-1); - } - - AMF_MODE_ENABLED = !IS_SOFTMODEM_NOS1; -// AMF_MODE_ENABLED = 0; - NGAP_CONF_MODE = !IS_SOFTMODEM_NOS1; //!get_softmodem_params()->phy_test; - -#if T_TRACER - T_Config_Init(); -#endif - //randominit (0); - set_taus_seed (0); - printf("configuring for RAU/RRU\n"); - - if (opp_enabled ==1) { - reset_opp_meas(); - } - - cpuf=get_cpu_freq_GHz(); - itti_init(TASK_MAX, tasks_info); - - init_opt(); - - LOG_I(HW, "Version: %s\n", PACKAGE_VERSION); - - if(IS_SOFTMODEM_NOS1) - init_pdcp(); - - if (RC.nb_nr_inst > 0) { - nr_read_config_and_init(); - // don't create if node doesn't connect to RRC/S1/GTP - AssertFatal(create_gNB_tasks(1) == 0,"cannot create ITTI tasks\n"); - for (int gnb_id = 0; gnb_id < RC.nb_nr_inst; gnb_id++) { - MessageDef *msg_p = itti_alloc_new_message (TASK_GNB_APP, 0, NRRRC_CONFIGURATION_REQ); - NRRRC_CONFIGURATION_REQ(msg_p) = RC.nrrrc[gnb_id]->configuration; - itti_send_msg_to_task (TASK_RRC_GNB, GNB_MODULE_ID_TO_INSTANCE(gnb_id), msg_p); - } - } else { - printf("No ITTI, Initializing L1\n"); - return 0; - } - - if(itti_create_task (TASK_RRC_GNB_SIM, itti_sim_gnb_rrc_task, NULL) < 0){ - printf("cannot create ITTI tasks\n"); - exit(-1); // need a softer mode - } - - openair_rrc_top_init_ue_nr("./"); - - if (create_tasks_nrue(1) < 0) { - printf("cannot create ITTI tasks\n"); - exit(-1); // need a softer mode - } - - if(itti_create_task (TASK_RRC_UE_SIM, itti_sim_ue_rrc_task, NULL) < 0){ - printf("cannot create ITTI tasks\n"); - exit(-1); // need a softer mode - } - - pthread_cond_init(&sync_cond,NULL); - pthread_mutex_init(&sync_mutex, NULL); - - printf("Sending sync to all threads\n"); - pthread_mutex_lock(&sync_mutex); - sync_var=0; - pthread_cond_broadcast(&sync_cond); - pthread_mutex_unlock(&sync_mutex); - // wait for end of program - printf("TYPE TO TERMINATE\n"); - - usleep(100000); - protocol_ctxt_t ctxt; - struct rrc_gNB_ue_context_s *ue_context_p = NULL; - - - ue_context_p = rrc_gNB_allocate_new_UE_context(RC.nrrrc[0]); - - if(ue_context_p == NULL){ - printf("ue_context_p == NULL"); - } - PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, - 0, - ENB_FLAG_YES, - 0, - 0, - 0); - NR_UE_rrc_inst[ctxt.module_id].Info[0].State = RRC_SI_RECEIVED; - - nr_rrc_ue_generate_RRCSetupRequest(ctxt.module_id, 0); - - printf("Entering ITTI signals handler\n"); - itti_wait_tasks_end(); - printf("Returned from ITTI signal handler\n"); - oai_exit=1; - printf("oai_exit=%d\n",oai_exit); - - printf("stopping MODEM threads\n"); - - - /* release memory used by the RU/gNB threads (incomplete), after all - * threads have been stopped (they partially use the same memory) */ - - pthread_cond_destroy(&sync_cond); - pthread_mutex_destroy(&sync_mutex); - - logClean(); - printf("Bye.\n"); - return 0; -} - - - diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index d7db2f70b4..976a4220dd 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -1369,15 +1369,6 @@ int ngap_gNB_pdusession_release_resp(instance_t instance, item->pDUSessionResourceReleaseResponseTransfer.size = 0; item->pDUSessionResourceReleaseResponseTransfer.buf = NULL; NGAP_DEBUG("pdusession_release_resp: transfer_buffer is NULL!\n"); -#ifdef ITTI_SIM - //For testing only - item->pDUSessionResourceReleaseResponseTransfer.buf = malloc(sizeof(uint8_t) * 1); - item->pDUSessionResourceReleaseResponseTransfer.size = 1; - uint8_t temp = 0; - memcpy(item->pDUSessionResourceReleaseResponseTransfer.buf, - &temp, - item->pDUSessionResourceReleaseResponseTransfer.size); -#endif } NGAP_DEBUG("pdusession_release_resp: pdusession ID %ld\n", item->pDUSessionID); ASN_SEQUENCE_ADD(&ie->value.choice.PDUSessionResourceReleasedListRelRes.list, item); From 18a68387c44d658fc90759bba6c1bc03ca640016 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 3 May 2022 12:22:01 +0200 Subject: [PATCH 258/267] Transfer Initial UL RRC Message through internal F1 --- common/utils/ocp_itti/intertask_interface.h | 1 + openair2/COMMON/f1ap_messages_types.h | 3 +- openair2/F1AP/f1ap_cu_rrc_message_transfer.c | 80 ++++---- openair2/F1AP/f1ap_du_rrc_message_transfer.c | 4 +- openair2/F1AP/f1ap_du_rrc_message_transfer.h | 2 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 60 +++++- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 16 +- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 7 + .../LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c | 18 +- openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c | 17 +- openair2/LAYER2/NR_MAC_gNB/main.c | 1 + openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 3 + openair2/RRC/NR/L2_nr_interface.c | 68 ------- openair2/RRC/NR/MESSAGES/asn1_msg.c | 80 +++----- openair2/RRC/NR/MESSAGES/asn1_msg.h | 25 +-- openair2/RRC/NR/nr_rrc_config.c | 16 +- openair2/RRC/NR/nr_rrc_config.h | 10 +- openair2/RRC/NR/nr_rrc_proto.h | 21 +-- openair2/RRC/NR/rrc_gNB.c | 172 ++++++++---------- openair2/RRC/NR/rrc_gNB_reconfig.c | 6 +- 20 files changed, 293 insertions(+), 317 deletions(-) diff --git a/common/utils/ocp_itti/intertask_interface.h b/common/utils/ocp_itti/intertask_interface.h index 636d305c13..a3f447baa3 100644 --- a/common/utils/ocp_itti/intertask_interface.h +++ b/common/utils/ocp_itti/intertask_interface.h @@ -304,6 +304,7 @@ void *rrc_enb_process_msg(void *); TASK_DEF(TASK_BM, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_PHY_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_MAC_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_MAC_GNB, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_RLC_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_RRC_ENB_NB_IoT, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_PDCP_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \ diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index c19bdff9a2..cbc4d1c6f2 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -62,7 +62,6 @@ #define F1AP_MAX_NO_OF_TNL_ASSOCIATIONS 32 #define F1AP_MAX_NO_UE_ID 1024 -#define F1AP_MAX_DU2CU_RRC_LENGTH 1024 typedef struct f1ap_net_ip_address_s { unsigned ipv4:1; @@ -310,7 +309,7 @@ typedef struct f1ap_initial_ul_rrc_message_s { uint16_t crnti; uint8_t *rrc_container; int rrc_container_length; - char du2cu_rrc_container[F1AP_MAX_DU2CU_RRC_LENGTH]; + uint8_t *du2cu_rrc_container; int du2cu_rrc_container_length; } f1ap_initial_ul_rrc_message_t; diff --git a/openair2/F1AP/f1ap_cu_rrc_message_transfer.c b/openair2/F1AP/f1ap_cu_rrc_message_transfer.c index 62a62095b1..3ae30cafb9 100644 --- a/openair2/F1AP/f1ap_cu_rrc_message_transfer.c +++ b/openair2/F1AP/f1ap_cu_rrc_message_transfer.c @@ -79,56 +79,60 @@ int CU_handle_INITIAL_UL_RRC_MESSAGE_TRANSFER(instance_t instance, F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_InitialULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_C_RNTI, true); rnti = ie->value.choice.C_RNTI; - /* RRC Container */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_InitialULRRCMessageTransferIEs_t, ie, container, + F1AP_InitialULRRCMessageTransferIEs_t *rrccont; + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_InitialULRRCMessageTransferIEs_t, rrccont, container, F1AP_ProtocolIE_ID_id_RRCContainer, true); - AssertFatal(ie!=NULL,"RRCContainer is missing\n"); + AssertFatal(rrccont!=NULL,"RRCContainer is missing\n"); - // create an ITTI message and copy SDU - if (f1ap_req(true, instance)->cell_type==CELL_MACRO_GNB) { - message_p = itti_alloc_new_message (TASK_CU_F1, 0, NR_RRC_MAC_CCCH_DATA_IND); - memset (NR_RRC_MAC_CCCH_DATA_IND (message_p).sdu, 0, CCCH_SDU_SIZE); - ccch_sdu_len = ie->value.choice.RRCContainer.size; - memcpy(NR_RRC_MAC_CCCH_DATA_IND (message_p).sdu, ie->value.choice.RRCContainer.buf, - ccch_sdu_len); - } else { - message_p = itti_alloc_new_message (TASK_CU_F1, 0, RRC_MAC_CCCH_DATA_IND); - memset (RRC_MAC_CCCH_DATA_IND (message_p).sdu, 0, CCCH_SDU_SIZE); - ccch_sdu_len = ie->value.choice.RRCContainer.size; - memcpy(RRC_MAC_CCCH_DATA_IND (message_p).sdu, ie->value.choice.RRCContainer.buf, - ccch_sdu_len); - } - - LOG_I(F1AP, "%s() RRCContainer (CCCH) size %ld: ", __func__, ie->value.choice.RRCContainer.size); - /* DUtoCURRCContainer */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_InitialULRRCMessageTransferIEs_t, ie, container, + F1AP_InitialULRRCMessageTransferIEs_t *du2cu; + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_InitialULRRCMessageTransferIEs_t, du2cu, container, F1AP_ProtocolIE_ID_id_DUtoCURRCContainer, false); - if (ie) { - NR_RRC_MAC_CCCH_DATA_IND (message_p).du_to_cu_rrc_container = malloc(sizeof(OCTET_STRING_t)); - NR_RRC_MAC_CCCH_DATA_IND (message_p).du_to_cu_rrc_container->size = ie->value.choice.DUtoCURRCContainer.size; - NR_RRC_MAC_CCCH_DATA_IND (message_p).du_to_cu_rrc_container->buf = malloc(ie->value.choice.DUtoCURRCContainer.size); - memcpy(NR_RRC_MAC_CCCH_DATA_IND (message_p).du_to_cu_rrc_container->buf, - ie->value.choice.DUtoCURRCContainer.buf, - ie->value.choice.DUtoCURRCContainer.size); - } - int f1ap_uid = f1ap_add_ue(CUtype, instance, rnti); if (f1ap_uid < 0 ) { LOG_E(F1AP, "Failed to add UE \n"); - itti_free(ITTI_MSG_ORIGIN_ID(message_p), message_p); return -1; } + // create an ITTI message and copy SDU + if (f1ap_req(true, instance)->cell_type==CELL_MACRO_GNB) { + message_p = itti_alloc_new_message (TASK_CU_F1, 0, F1AP_INITIAL_UL_RRC_MESSAGE); + f1ap_initial_ul_rrc_message_t *ul_rrc = &F1AP_INITIAL_UL_RRC_MESSAGE(message_p); + ul_rrc->nr_cellid = nr_cellid; // CU instance + ul_rrc->crnti = rnti; + ul_rrc->rrc_container_length = rrccont->value.choice.RRCContainer.size; + ul_rrc->rrc_container = malloc(ul_rrc->rrc_container_length); + memcpy(ul_rrc->rrc_container, rrccont->value.choice.RRCContainer.buf, ul_rrc->rrc_container_length); + AssertFatal(du2cu != NULL, "no masterCellGroup in initial UL RRC message\n"); + ul_rrc->du2cu_rrc_container_length = du2cu->value.choice.DUtoCURRCContainer.size; + ul_rrc->du2cu_rrc_container = malloc(ul_rrc->du2cu_rrc_container_length); + memcpy(ul_rrc->du2cu_rrc_container, du2cu->value.choice.DUtoCURRCContainer.buf, ul_rrc->du2cu_rrc_container_length); + itti_send_msg_to_task(TASK_RRC_GNB, instance, message_p); + } else { + message_p = itti_alloc_new_message (TASK_CU_F1, 0, RRC_MAC_CCCH_DATA_IND); + memset (RRC_MAC_CCCH_DATA_IND (message_p).sdu, 0, CCCH_SDU_SIZE); + ccch_sdu_len = rrccont->value.choice.RRCContainer.size; + memcpy(RRC_MAC_CCCH_DATA_IND (message_p).sdu, rrccont->value.choice.RRCContainer.buf, + ccch_sdu_len); + NR_RRC_MAC_CCCH_DATA_IND (message_p).frame = 0; + NR_RRC_MAC_CCCH_DATA_IND (message_p).sub_frame = 0; + NR_RRC_MAC_CCCH_DATA_IND (message_p).sdu_size = ccch_sdu_len; + NR_RRC_MAC_CCCH_DATA_IND (message_p).nr_cellid = nr_cellid; // CU instance + NR_RRC_MAC_CCCH_DATA_IND (message_p).rnti = rnti; + NR_RRC_MAC_CCCH_DATA_IND (message_p).CC_id = CC_id; + if (du2cu) { + NR_RRC_MAC_CCCH_DATA_IND (message_p).du_to_cu_rrc_container = malloc(sizeof(OCTET_STRING_t)); + NR_RRC_MAC_CCCH_DATA_IND (message_p).du_to_cu_rrc_container->size = du2cu->value.choice.DUtoCURRCContainer.size; + NR_RRC_MAC_CCCH_DATA_IND (message_p).du_to_cu_rrc_container->buf = malloc(du2cu->value.choice.DUtoCURRCContainer.size); + memcpy(NR_RRC_MAC_CCCH_DATA_IND (message_p).du_to_cu_rrc_container->buf, + du2cu->value.choice.DUtoCURRCContainer.buf, + du2cu->value.choice.DUtoCURRCContainer.size); + } + itti_send_msg_to_task (TASK_RRC_ENB, instance, message_p); + } + //getCxt(true,ITTI_MSG_DESTINATION_ID(message_p))->f1ap_ue[f1ap_uid].du_ue_f1ap_id = du_ue_f1ap_id; - NR_RRC_MAC_CCCH_DATA_IND (message_p).frame = 0; - NR_RRC_MAC_CCCH_DATA_IND (message_p).sub_frame = 0; - NR_RRC_MAC_CCCH_DATA_IND (message_p).sdu_size = ccch_sdu_len; - NR_RRC_MAC_CCCH_DATA_IND (message_p).nr_cellid = nr_cellid; // CU instance - NR_RRC_MAC_CCCH_DATA_IND (message_p).rnti = rnti; - NR_RRC_MAC_CCCH_DATA_IND (message_p).CC_id = CC_id; - itti_send_msg_to_task (f1ap_req(true,ITTI_MSG_DESTINATION_ID(message_p))->cell_type==CELL_MACRO_GNB?TASK_RRC_GNB:TASK_RRC_ENB, instance, message_p); return 0; } diff --git a/openair2/F1AP/f1ap_du_rrc_message_transfer.c b/openair2/F1AP/f1ap_du_rrc_message_transfer.c index d896a2640b..c0f8b79839 100644 --- a/openair2/F1AP/f1ap_du_rrc_message_transfer.c +++ b/openair2/F1AP/f1ap_du_rrc_message_transfer.c @@ -749,7 +749,7 @@ int DU_send_INITIAL_UL_RRC_MESSAGE_TRANSFER(instance_t instanceP, rnti_t rntiP, const uint8_t *sduP, sdu_size_t sdu_lenP, - const char *sdu2P, + const uint8_t *sdu2P, sdu_size_t sdu2_lenP) { F1AP_F1AP_PDU_t pdu= {0}; F1AP_InitialULRRCMessageTransfer_t *out; @@ -808,7 +808,7 @@ int DU_send_INITIAL_UL_RRC_MESSAGE_TRANSFER(instance_t instanceP, ie5->criticality = F1AP_Criticality_reject; ie5->value.present = F1AP_InitialULRRCMessageTransferIEs__value_PR_DUtoCURRCContainer; OCTET_STRING_fromBuf(&ie5->value.choice.DUtoCURRCContainer, - sdu2P, + (const char *)sdu2P, sdu2_lenP); } /* mandatory */ diff --git a/openair2/F1AP/f1ap_du_rrc_message_transfer.h b/openair2/F1AP/f1ap_du_rrc_message_transfer.h index d6f196e384..b42d731ac7 100644 --- a/openair2/F1AP/f1ap_du_rrc_message_transfer.h +++ b/openair2/F1AP/f1ap_du_rrc_message_transfer.h @@ -50,7 +50,7 @@ int DU_send_INITIAL_UL_RRC_MESSAGE_TRANSFER(instance_t instanceP, rnti_t rntiP, const uint8_t *sduP, sdu_size_t sdu_lenP, - const char *sdu2P, + const uint8_t *sdu2P, sdu_size_t sdu2_lenP); #endif /* F1AP_DU_RRC_MESSAGE_TRANSFER_H_ */ diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index a737e66c40..1475abc08a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -44,9 +44,12 @@ #include "OCG.h" #include "OCG_extern.h" +/* TODO REMOVE_DU_RRC: the RRC in the DU is a hack and should be taken out in the future */ #include "RRC/LTE/rrc_extern.h" #include "RRC/NR/nr_rrc_extern.h" +#include "RRC/NR/rrc_gNB_UE_context.h" #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" +#include "RRC/NR/MESSAGES/asn1_msg.h" #include "intertask_interface.h" @@ -2136,7 +2139,7 @@ int rnti_to_remove[10]; volatile int rnti_to_remove_count; pthread_mutex_t rnti_to_remove_mutex = PTHREAD_MUTEX_INITIALIZER; -void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr) +void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr, uid_allocator_t *uia) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; destroy_nr_list(&sched_ctrl->available_dl_harq); @@ -2145,6 +2148,7 @@ void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr) destroy_nr_list(&sched_ctrl->available_ul_harq); destroy_nr_list(&sched_ctrl->feedback_ul_harq); destroy_nr_list(&sched_ctrl->retrans_ul_harq); + uid_linear_allocator_free(uia, UE->uid); LOG_I(NR_MAC, "Remove NR rnti 0x%04x\n", UE->rnti); const rnti_t rnti = UE->rnti; free(UE); @@ -2439,6 +2443,7 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf } UE->rnti = rntiP; + UE->uid = uid_linear_allocator_new(&UE_info->uid_allocator); UE->CellGroup = CellGroup; if (CellGroup) @@ -2492,7 +2497,7 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf } if (i == MAX_MOBILES_PER_GNB) { LOG_E(NR_MAC,"Try to add UE %04x but the list is full\n", rntiP); - delete_nr_ue_data(UE, nr_mac->common_channels); + delete_nr_ue_data(UE, nr_mac->common_channels, &UE_info->uid_allocator); pthread_mutex_unlock(&UE_info->mutex); return NULL; } @@ -2596,7 +2601,7 @@ void mac_remove_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rnti) memcpy(UE_info->list, newUEs, sizeof(UE_info->list)); pthread_mutex_unlock(&UE_info->mutex); - delete_nr_ue_data(UE, nr_mac->common_channels); + delete_nr_ue_data(UE, nr_mac->common_channels, &UE_info->uid_allocator); } void nr_mac_remove_ra_rnti(module_id_t mod_id, rnti_t rnti) { @@ -2979,3 +2984,52 @@ void UL_tti_req_ahead_initialization(gNB_MAC_INST * gNB, NR_ServingCellConfigCom req->Slot = i; } } + +void send_initial_ul_rrc_message(module_id_t module_id, + int CC_id, + const NR_UE_info_t *UE, + rb_id_t srb_id, + const uint8_t *sdu, + sdu_size_t sdu_len) { + const gNB_MAC_INST *mac = RC.nrmac[module_id]; + const rnti_t rnti = UE->rnti; + LOG_W(MAC, + "[RAPROC] Received SDU for CCCH on SRB %ld length %d for UE %04x\n", + srb_id, sdu_len, rnti); + + /* TODO REMOVE_DU_RRC: the RRC in the DU is a hack and should be taken out in the future */ + if (NODE_IS_DU(RC.nrrrc[module_id]->node_type)) { + struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_allocate_new_UE_context(RC.nrrrc[module_id]); + ue_context_p->ue_id_rnti = rnti; + ue_context_p->ue_context.rnti = rnti; + ue_context_p->ue_context.random_ue_identity = rnti; + ue_context_p->ue_context.Srb0.Active = 1; + RB_INSERT(rrc_nr_ue_tree_s, &RC.nrrrc[module_id]->rrc_ue_head, ue_context_p); + } + + const NR_ServingCellConfigCommon_t *scc = RC.nrrrc[module_id]->carrier.servingcellconfigcommon; + const NR_ServingCellConfig_t *sccd = RC.nrrrc[module_id]->configuration.scd; + NR_CellGroupConfig_t cellGroupConfig = {0}; + fill_initial_cellGroupConfig(UE->uid, &cellGroupConfig, scc, sccd, &RC.nrrrc[module_id]->configuration); + + uint8_t du2cu_rrc_container[1024]; + asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, + NULL, + &cellGroupConfig, + du2cu_rrc_container, + sizeof(du2cu_rrc_container)); + AssertFatal(enc_rval.encoded > 0, + "Could not encode cellGroupConfig for UE %04x, failed element %s\n", + rnti, + enc_rval.failed_type->name); + + const f1ap_initial_ul_rrc_message_t ul_rrc_msg = { + /* TODO: add mcc, mnc, cell_id, ..., is not available at MAC yet */ + .crnti = rnti, + .rrc_container = (uint8_t *) sdu, + .rrc_container_length = sdu_len, + .du2cu_rrc_container = (uint8_t *) du2cu_rrc_container, + .du2cu_rrc_container_length = (enc_rval.encoded + 7) / 8 + }; + mac->mac_rrc.initial_ul_rrc_message_transfer(module_id, &ul_rrc_msg); +} diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 27af724c20..43e88eb9a9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -312,16 +312,12 @@ int nr_process_mac_pdu( instance_t module_idP, mac_len = 6; } - nr_mac_rrc_data_ind(module_idP, - CC_id, - frameP, - 0, - 0, - UE->rnti, - CCCH, - pduP + mac_subheader_len, - mac_len, - 0); + send_initial_ul_rrc_message(module_idP, + CC_id, + UE, + CCCH, + pduP + mac_subheader_len, + mac_len); break; case UL_SCH_LCID_DTCH ... (UL_SCH_LCID_DTCH + 28): diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index c61a12de16..674d80a4d4 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -502,6 +502,13 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset void process_CellGroup(NR_CellGroupConfig_t *CellGroup, NR_UE_sched_ctrl_t *sched_ctrl); +void send_initial_ul_rrc_message(module_id_t module_id, + int CC_id, + const NR_UE_info_t *UE, + rb_id_t srb_id, + const uint8_t *sdu, + sdu_size_t sdu_len); + void abort_nr_dl_harq(NR_UE_info_t* UE, int8_t harq_pid); #endif /*__LAYER2_NR_MAC_PROTO_H__*/ diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c index f290e0d268..25ee7feb14 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c @@ -25,8 +25,22 @@ static void initial_ul_rrc_message_transfer_direct(module_id_t module_id, const f1ap_initial_ul_rrc_message_t *ul_rrc) { - /* TODO ITTI message for NR_RRC_MAC_IND? */ - AssertFatal(0 == 1, "not implemented\n"); + MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_INITIAL_UL_RRC_MESSAGE); + /* copy all fields, but reallocate rrc_containers! */ + f1ap_initial_ul_rrc_message_t *f1ap_msg = &F1AP_INITIAL_UL_RRC_MESSAGE(msg); + *f1ap_msg = *ul_rrc; + + f1ap_msg->rrc_container = malloc(ul_rrc->rrc_container_length); + DevAssert(f1ap_msg->rrc_container); + memcpy(f1ap_msg->rrc_container, ul_rrc->rrc_container, ul_rrc->rrc_container_length); + f1ap_msg->rrc_container_length = ul_rrc->rrc_container_length; + + f1ap_msg->du2cu_rrc_container = malloc(ul_rrc->du2cu_rrc_container_length); + DevAssert(f1ap_msg->du2cu_rrc_container); + memcpy(f1ap_msg->du2cu_rrc_container, ul_rrc->du2cu_rrc_container, ul_rrc->du2cu_rrc_container_length); + f1ap_msg->du2cu_rrc_container_length = ul_rrc->du2cu_rrc_container_length; + + itti_send_msg_to_task(TASK_RRC_GNB, module_id, msg); } void mac_rrc_ul_direct_init(struct nr_mac_rrc_ul_if_s *mac_rrc) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c index ed67fb9119..65e7f10405 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c @@ -25,7 +25,22 @@ static void initial_ul_rrc_message_transfer_f1ap(module_id_t module_id, const f1ap_initial_ul_rrc_message_t *ul_rrc) { - AssertFatal(0 == 1, "not implemented\n"); + MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_INITIAL_UL_RRC_MESSAGE); + /* copy all fields, but reallocate rrc_containers! */ + f1ap_initial_ul_rrc_message_t *f1ap_msg = &F1AP_INITIAL_UL_RRC_MESSAGE(msg); + *f1ap_msg = *ul_rrc; + + f1ap_msg->rrc_container = malloc(ul_rrc->rrc_container_length); + DevAssert(f1ap_msg->rrc_container); + memcpy(f1ap_msg->rrc_container, ul_rrc->rrc_container, ul_rrc->rrc_container_length); + f1ap_msg->rrc_container_length = ul_rrc->rrc_container_length; + + f1ap_msg->du2cu_rrc_container = malloc(ul_rrc->du2cu_rrc_container_length); + DevAssert(f1ap_msg->du2cu_rrc_container); + memcpy(f1ap_msg->du2cu_rrc_container, ul_rrc->du2cu_rrc_container, ul_rrc->du2cu_rrc_container_length); + f1ap_msg->du2cu_rrc_container_length = ul_rrc->du2cu_rrc_container_length; + + itti_send_msg_to_task(TASK_DU_F1, module_id, msg); } void mac_rrc_ul_f1ap_init(struct nr_mac_rrc_ul_if_s *mac_rrc) diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 0694f7d757..8c1abf4561 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -228,6 +228,7 @@ void mac_top_init_gNB(ngran_node_t node_type) RC.nrmac[i]->first_MIB = true; pthread_mutex_init(&RC.nrmac[i]->UE_info.mutex, NULL); + uid_linear_allocator_init(&RC.nrmac[i]->UE_info.uid_allocator); if (get_softmodem_params()->phy_test) { RC.nrmac[i]->pre_processor_dl = nr_preprocessor_phytest; diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 3c3ea4dfc8..09f3193790 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -46,6 +46,7 @@ #include "targets/ARCH/COMMON/common_lib.h" #include "COMMON/platform_constants.h" #include "common/ran_context.h" +#include "collection/linear_alloc.h" /* RRC */ #include "NR_BCCH-BCH-Message.h" @@ -694,6 +695,7 @@ typedef struct nr_mac_rrc_ul_if_s { /*! \brief UE list used by gNB to order UEs/CC for scheduling*/ typedef struct { rnti_t rnti; + uid_t uid; // unique ID of this UE /// scheduling control info nr_csi_report_t csi_report_template[MAX_CSI_REPORTCONFIG]; NR_UE_sched_ctrl_t UE_sched_ctrl; @@ -720,6 +722,7 @@ typedef struct { pthread_mutex_t mutex; NR_UE_info_t *list[MAX_MOBILES_PER_GNB+1]; bool sched_csirs; + uid_allocator_t uid_allocator; } NR_UEs_t; #define UE_iterator(BaSe, VaR) NR_UE_info_t ** VaR##pptr=BaSe, *VaR; while ((VaR=*(VaR##pptr++))) diff --git a/openair2/RRC/NR/L2_nr_interface.c b/openair2/RRC/NR/L2_nr_interface.c index ab9e3984d8..67e06914ef 100644 --- a/openair2/RRC/NR/L2_nr_interface.c +++ b/openair2/RRC/NR/L2_nr_interface.c @@ -202,74 +202,6 @@ int8_t nr_mac_rrc_bwp_switch_req(const module_id_t module_idP, return 0; } -int8_t nr_mac_rrc_data_ind(const module_id_t module_idP, - const int CC_id, - const frame_t frameP, - const sub_frame_t sub_frameP, - const int UE_id, - const rnti_t rntiP, - const rb_id_t srb_idP, - const uint8_t *sduP, - const sdu_size_t sdu_lenP, - const bool brOption) { - - if (NODE_IS_DU(RC.nrrrc[module_idP]->node_type)) { - LOG_W(RRC,"[DU %d][RAPROC] Received SDU for CCCH on SRB %ld length %d for UE id %d RNTI %x \n", - module_idP, srb_idP, sdu_lenP, UE_id, rntiP); - - // Generate DUtoCURRCContainer - // call do_RRCSetup like full procedure and extract masterCellGroup - NR_CellGroupConfig_t cellGroupConfig; - NR_ServingCellConfigCommon_t *scc=RC.nrrrc[module_idP]->carrier.servingcellconfigcommon; - NR_ServingCellConfig_t *servingcellconfigdedicated = RC.nrrrc[module_idP]->configuration.scd; - memset(&cellGroupConfig,0,sizeof(cellGroupConfig)); - - struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_allocate_new_UE_context(RC.nrrrc[module_idP]); - ue_context_p->ue_id_rnti = rntiP; - ue_context_p->ue_context.rnti = rntiP; - ue_context_p->ue_context.random_ue_identity = rntiP; - ue_context_p->ue_context.Srb0.Active = 1; - RB_INSERT(rrc_nr_ue_tree_s, &RC.nrrrc[module_idP]->rrc_ue_head, ue_context_p); - - fill_initial_cellGroupConfig(ue_context_p->local_uid,&cellGroupConfig,scc,servingcellconfigdedicated,&RC.nrrrc[module_idP]->configuration); - - MessageDef* tmp=itti_alloc_new_message_sized(TASK_RRC_GNB, 0, F1AP_INITIAL_UL_RRC_MESSAGE, sizeof(f1ap_initial_ul_rrc_message_t) + sdu_lenP); - f1ap_initial_ul_rrc_message_t *msg = &F1AP_INITIAL_UL_RRC_MESSAGE(tmp); - - asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, - NULL, - (void *)&cellGroupConfig, - msg->du2cu_rrc_container, - F1AP_MAX_DU2CU_RRC_LENGTH); - - if (enc_rval.encoded == -1) { - LOG_E(F1AP,"Could not encoded cellGroupConfig, failed element %s\n",enc_rval.failed_type->name); - exit(-1); - } - /* do ITTI message */ - msg->du2cu_rrc_container_length = (enc_rval.encoded+7)/8; - msg->crnti=rntiP; - msg->rrc_container=(uint8_t*) (msg+1); // Made extra room after the struct with itti_alloc_msg_sized() - memcpy(msg->rrc_container, sduP, sdu_lenP); - msg->rrc_container_length=sdu_lenP; - itti_send_msg_to_task(TASK_DU_F1, 0, tmp); - - return 0; - } - - protocol_ctxt_t ctxt; - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, GNB_FLAG_YES, rntiP, frameP, sub_frameP,0); - - if((srb_idP & RAB_OFFSET) == CCCH) { - LOG_D(NR_RRC, "[gNB %d] Received SDU for CCCH on SRB %ld\n", module_idP, srb_idP); - ctxt.brOption = brOption; - if (sdu_lenP > 0) { - nr_rrc_gNB_decode_ccch(&ctxt, sduP, sdu_lenP, NULL, CC_id); - } - } - return 0; -} - void nr_mac_gNB_rrc_ul_failure(const module_id_t Mod_instP, const int CC_idP, const frame_t frameP, diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 2c620f62a5..6aaa96a8e7 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -986,8 +986,8 @@ uint8_t do_RRCReject(uint8_t Mod_id, void fill_default_downlinkBWP(NR_BWP_Downlink_t *bwp, int bwp_loop, - NR_ServingCellConfig_t *servingcellconfigdedicated, - NR_ServingCellConfigCommon_t *scc, + const NR_ServingCellConfig_t *servingcellconfigdedicated, + const NR_ServingCellConfigCommon_t *scc, const gNB_RrcConfigurationReq *configuration) { /// BWP common configuration @@ -1133,8 +1133,8 @@ void fill_default_downlinkBWP(NR_BWP_Downlink_t *bwp, void fill_default_uplinkBWP(NR_BWP_Uplink_t *ubwp, int bwp_loop, - NR_ServingCellConfig_t *servingcellconfigdedicated, - NR_ServingCellConfigCommon_t *scc, + const NR_ServingCellConfig_t *servingcellconfigdedicated, + const NR_ServingCellConfigCommon_t *scc, const gNB_RrcConfigurationReq *configuration, int uid) { @@ -1330,13 +1330,11 @@ void fill_default_uplinkBWP(NR_BWP_Uplink_t *ubwp, } void fill_initial_SpCellConfig(int uid, - NR_CellGroupConfig_t *cellGroupConfig, - NR_ServingCellConfigCommon_t *scc, - NR_ServingCellConfig_t *servingcellconfigdedicated, - const gNB_RrcConfigurationReq *configuration) { - - NR_SpCellConfig_t *SpCellConfig = cellGroupConfig->spCellConfig; - + NR_SpCellConfig_t *SpCellConfig, + const NR_ServingCellConfigCommon_t *scc, + const NR_ServingCellConfig_t *servingcellconfigdedicated, + const gNB_RrcConfigurationReq *configuration) +{ // This assert will never happen in the current implementation because NUMBER_OF_UE_MAX = 4. // However, if in the future NUMBER_OF_UE_MAX is increased, it will be necessary to improve the allocation of SRS resources, // where the startPosition = 2 or 3 and sl160 = 17, 17, 27 ... 157 only give us 30 different allocations. @@ -1915,8 +1913,8 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, void fill_initial_cellGroupConfig(int uid, NR_CellGroupConfig_t *cellGroupConfig, - NR_ServingCellConfigCommon_t *scc, - NR_ServingCellConfig_t *servingcellconfigdedicated, + const NR_ServingCellConfigCommon_t *scc, + const NR_ServingCellConfig_t *servingcellconfigdedicated, const gNB_RrcConfigurationReq *configuration) { NR_MAC_CellGroupConfig_t *mac_CellGroupConfig = NULL; @@ -1970,20 +1968,21 @@ void fill_initial_cellGroupConfig(int uid, cellGroupConfig->spCellConfig = calloc(1,sizeof(*cellGroupConfig->spCellConfig)); - fill_initial_SpCellConfig(uid,cellGroupConfig,scc,servingcellconfigdedicated,configuration); + fill_initial_SpCellConfig(uid,cellGroupConfig->spCellConfig,scc,servingcellconfigdedicated,configuration); cellGroupConfig->sCellToAddModList = NULL; cellGroupConfig->sCellToReleaseList = NULL; } //------------------------------------------------------------------------------ -int16_t do_RRCSetup(rrc_gNB_ue_context_t *const ue_context_pP, - uint8_t *const buffer, - const uint8_t transaction_id, - OCTET_STRING_t *masterCellGroup_from_DU, - NR_ServingCellConfigCommon_t *scc, - NR_ServingCellConfig_t *servingcellconfigdedicated, - const gNB_RrcConfigurationReq *configuration) +int do_RRCSetup(rrc_gNB_ue_context_t *const ue_context_pP, + uint8_t *const buffer, + const uint8_t transaction_id, + const uint8_t *masterCellGroup, + int masterCellGroup_len, + const NR_ServingCellConfigCommon_t *scc, + const NR_ServingCellConfig_t *servingcellconfigdedicated, + const gNB_RrcConfigurationReq *configuration) //------------------------------------------------------------------------------ { asn_enc_rval_t enc_rval; @@ -1993,7 +1992,6 @@ int16_t do_RRCSetup(rrc_gNB_ue_context_t *const ue_context_pP, NR_SRB_ToAddMod_t *SRB1_config = NULL; NR_PDCP_Config_t *pdcp_Config = NULL; NR_CellGroupConfig_t *cellGroupConfig = NULL; - char masterCellGroup_buf[3000]; AssertFatal(ue_context_pP != NULL,"ue_context_p is null\n"); gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; @@ -2036,38 +2034,14 @@ int16_t do_RRCSetup(rrc_gNB_ue_context_t *const ue_context_pP, ie->radioBearerConfig.securityConfig = NULL; /****************************** masterCellGroup ******************************/ - /* TODO */ - if (masterCellGroup_from_DU) { - memcpy(&ie->masterCellGroup,masterCellGroup_from_DU,sizeof(*masterCellGroup_from_DU)); - // decode masterCellGroup OCTET_STRING received from DU and place in ue context - uper_decode(NULL, - &asn_DEF_NR_CellGroupConfig, //might be added prefix later - (void **)&cellGroupConfig, - (uint8_t *)masterCellGroup_from_DU->buf, - masterCellGroup_from_DU->size, 0, 0); - } - else { - cellGroupConfig = calloc(1, sizeof(NR_CellGroupConfig_t)); - fill_initial_cellGroupConfig(ue_context_pP->local_uid,cellGroupConfig,scc,servingcellconfigdedicated,configuration); - - enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, - NULL, - (void *)cellGroupConfig, - masterCellGroup_buf, - 3000); - - if(enc_rval.encoded == -1) { - LOG_E(NR_RRC, "ASN1 message CellGroupConfig encoding failed (%s, %lu)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - return -1; - } - - if (OCTET_STRING_fromBuf(&ie->masterCellGroup, masterCellGroup_buf, (enc_rval.encoded+7)/8) == -1) { - LOG_E(NR_RRC, "fatal: OCTET_STRING_fromBuf failed\n"); - return -1; - } - } + DevAssert(masterCellGroup && masterCellGroup_len > 0); + ie->masterCellGroup.buf = malloc(masterCellGroup_len); + AssertFatal(ie->masterCellGroup.buf != NULL, "could not allocate memory for masterCellGroup\n"); + memcpy(ie->masterCellGroup.buf, masterCellGroup, masterCellGroup_len); + ie->masterCellGroup.size = masterCellGroup_len; + // decode masterCellGroup OCTET_STRING received from DU and place in ue context + uper_decode(NULL, &asn_DEF_NR_CellGroupConfig, (void **)&cellGroupConfig, masterCellGroup, masterCellGroup_len, 0, 0); ue_p->masterCellGroup = cellGroupConfig; if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index ea4b185f6b..1d6be68f5c 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -100,15 +100,15 @@ uint8_t do_RRCReject(uint8_t Mod_id, uint8_t *const buffer); void fill_initial_SpCellConfig(int uid, - NR_CellGroupConfig_t *cellGroupConfig, - NR_ServingCellConfigCommon_t *scc, - NR_ServingCellConfig_t *servingcellconfigdedicated, + NR_SpCellConfig_t *SpCellConfig, + const NR_ServingCellConfigCommon_t *scc, + const NR_ServingCellConfig_t *servingcellconfigdedicated, const gNB_RrcConfigurationReq *configuration); void fill_initial_cellGroupConfig(int uid, NR_CellGroupConfig_t *cellGroupConfig, - NR_ServingCellConfigCommon_t *scc, - NR_ServingCellConfig_t *servingcellconfigdedicated, + const NR_ServingCellConfigCommon_t *scc, + const NR_ServingCellConfig_t *servingcellconfigdedicated, const gNB_RrcConfigurationReq *configuration); void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, @@ -124,13 +124,14 @@ void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, uint8_t nb_bearers_to_setup, long *priority); -int16_t do_RRCSetup(rrc_gNB_ue_context_t *const ue_context_pP, - uint8_t *const buffer, - const uint8_t transaction_id, - OCTET_STRING_t *masterCellGroup_from_DU, - NR_ServingCellConfigCommon_t *scc, - NR_ServingCellConfig_t *servingcellconfigdedicated, - const gNB_RrcConfigurationReq *configuration); +int do_RRCSetup(rrc_gNB_ue_context_t *const ue_context_pP, + uint8_t *const buffer, + const uint8_t transaction_id, + const uint8_t *masterCellGroup, + int masterCellGroup_len, + const NR_ServingCellConfigCommon_t *scc, + const NR_ServingCellConfig_t *servingcellconfigdedicated, + const gNB_RrcConfigurationReq *configuration); uint8_t do_NR_SecurityModeCommand( const protocol_ctxt_t *const ctxt_pP, diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index f67fb93c23..5d1e3e97d0 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -71,7 +71,7 @@ void rrc_coreset_config(NR_ControlResourceSet_t *coreset, coreset->pdcch_DMRS_ScramblingID = NULL; } -uint64_t get_ssb_bitmap(NR_ServingCellConfigCommon_t *scc) { +uint64_t get_ssb_bitmap(const NR_ServingCellConfigCommon_t *scc) { uint64_t bitmap=0; switch (scc->ssb_PositionsInBurst->present) { case 1 : @@ -138,7 +138,7 @@ void set_csirs_periodicity(NR_NZP_CSI_RS_Resource_t *nzpcsi0, int uid, int nb_sl } } -void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, +void config_csirs(const NR_ServingCellConfigCommon_t *servingcellconfigcommon, NR_CSI_MeasConfig_t *csi_MeasConfig, int uid, int num_dl_antenna_ports, @@ -495,7 +495,7 @@ void prepare_sim_uecap(NR_UE_NR_Capability_t *cap, phy_Parameters->phy_ParametersFRX_Diff->pucch_F0_2WithoutFH = NULL; } -void nr_rrc_config_dl_tda(NR_ServingCellConfigCommon_t *scc, +void nr_rrc_config_dl_tda(const NR_ServingCellConfigCommon_t *scc, NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList, int curr_bwp) { @@ -716,9 +716,9 @@ void set_pucch_power_config(NR_PUCCH_Config_t *pucch_Config, int do_csirs) { ASN_SEQUENCE_ADD(&pucch_Config->spatialRelationInfoToAddModList->list,pucchspatial); } -void set_SR_periodandoffset(NR_SchedulingRequestResourceConfig_t *schedulingRequestResourceConfig, - NR_ServingCellConfigCommon_t *scc) { - +static void set_SR_periodandoffset(NR_SchedulingRequestResourceConfig_t *schedulingRequestResourceConfig, + const NR_ServingCellConfigCommon_t *scc) +{ const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; int sr_slot = 1; // in FDD SR in slot 1 if(tdd) @@ -760,7 +760,7 @@ void set_SR_periodandoffset(NR_SchedulingRequestResourceConfig_t *schedulingRequ schedulingRequestResourceConfig->periodicityAndOffset->choice.sl640 = sr_slot; } -void scheduling_request_config(NR_ServingCellConfigCommon_t *scc, +void scheduling_request_config(const NR_ServingCellConfigCommon_t *scc, NR_PUCCH_Config_t *pucch_Config) { // format with <=2 bits in pucch resource set 0 @@ -784,7 +784,7 @@ void set_dl_mcs_table(int scs, NR_UE_NR_Capability_t *cap, NR_SpCellConfig_t *SpCellConfig, NR_BWP_DownlinkDedicated_t *bwp_Dedicated, - NR_ServingCellConfigCommon_t *scc) { + const NR_ServingCellConfigCommon_t *scc) { if (cap == NULL){ bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table = NULL; diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index b1367a0c8a..27aebcf94b 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -111,12 +111,12 @@ typedef struct physicalcellgroup_s{ long RNTI_Value[MAX_NUM_CCs]; }physicalcellgroup_t; -uint64_t get_ssb_bitmap(NR_ServingCellConfigCommon_t *scc); +uint64_t get_ssb_bitmap(const NR_ServingCellConfigCommon_t *scc); void rrc_coreset_config(NR_ControlResourceSet_t *coreset, int bwp_id, int curr_bwp, uint64_t ssb_bitmap); -void nr_rrc_config_dl_tda(NR_ServingCellConfigCommon_t *scc, +void nr_rrc_config_dl_tda(const NR_ServingCellConfigCommon_t *scc, NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList, int curr_bwp); void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay); @@ -124,9 +124,9 @@ void config_pucch_resset0(NR_PUCCH_Config_t *pucch_Config, int uid, int curr_bwp void config_pucch_resset1(NR_PUCCH_Config_t *pucch_Config, NR_UE_NR_Capability_t *uecap); void set_dl_DataToUL_ACK(NR_PUCCH_Config_t *pucch_Config, int min_feedback_time); void set_pucch_power_config(NR_PUCCH_Config_t *pucch_Config, int do_csirs); -void scheduling_request_config(NR_ServingCellConfigCommon_t *scc, +void scheduling_request_config(const NR_ServingCellConfigCommon_t *scc, NR_PUCCH_Config_t *pucch_Config); -void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, +void config_csirs(const NR_ServingCellConfigCommon_t *servingcellconfigcommon, NR_CSI_MeasConfig_t *csi_MeasConfig, int uid, int num_dl_antenna_ports, @@ -142,7 +142,7 @@ void set_dl_mcs_table(int scs, NR_UE_NR_Capability_t *cap, NR_SpCellConfig_t *SpCellConfig, NR_BWP_DownlinkDedicated_t *bwp_Dedicated, - NR_ServingCellConfigCommon_t *scc); + const NR_ServingCellConfigCommon_t *scc); void prepare_sim_uecap(NR_UE_NR_Capability_t *cap, NR_ServingCellConfigCommon_t *scc, int numerology, diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index dc6e14215f..b90cf4dfa4 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -108,9 +108,9 @@ void rrc_gNB_generate_RRCSetup( const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *const ue_context_pP, - OCTET_STRING_t *masterCellGroup_from_DU, - NR_ServingCellConfigCommon_t *scc, - const int CC_id); + const uint8_t *masterCellGroup, + int masterCellGroup_len, + NR_ServingCellConfigCommon_t *scc); int parse_CG_ConfigInfo(gNB_RRC_INST *rrc, NR_CG_ConfigInfo_t *CG_ConfigInfo, x2ap_ENDC_sgnb_addition_req_t *m); @@ -174,17 +174,6 @@ int8_t nr_mac_rrc_bwp_switch_req(const module_id_t module_idP, const int dl_bwp_id, const int ul_bwp_id); -int8_t nr_mac_rrc_data_ind(const module_id_t module_idP, - const int CC_id, - const frame_t frameP, - const sub_frame_t sub_frameP, - const int UE_id, - const rnti_t rntiP, - const rb_id_t srb_idP, - const uint8_t *sduP, - const sdu_size_t sdu_lenP, - const bool brOption); - int nr_rrc_reconfiguration_req(rrc_gNB_ue_context_t *const ue_context_pP, protocol_ctxt_t *const ctxt_pP, const int dl_bwp_id, @@ -193,8 +182,8 @@ int nr_rrc_reconfiguration_req(rrc_gNB_ue_context_t *const ue_context_pP int nr_rrc_gNB_decode_ccch(protocol_ctxt_t *const ctxt_pP, const uint8_t *buffer, int buffer_length, - OCTET_STRING_t *du_to_cu_rrc_container, - const int CC_id); + const uint8_t *du_to_cu_rrc_container, + int du_to_cu_rrc_container_length); void rrc_gNB_generate_dedicatedRRCReconfiguration_release( diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 1cacc1abb3..208a78d37e 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -339,10 +339,9 @@ void rrc_gNB_generate_RRCSetup( const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *const ue_context_pP, - OCTET_STRING_t *masterCellGroup_from_DU, - NR_ServingCellConfigCommon_t *scc, - const int CC_id -) + const uint8_t *masterCellGroup, + int masterCellGroup_len, + NR_ServingCellConfigCommon_t *scc) //----------------------------------------------------------------------------- { LOG_I(NR_RRC, "rrc_gNB_generate_RRCSetup for RNTI %04x\n", ctxt_pP->rnti); @@ -355,16 +354,15 @@ rrc_gNB_generate_RRCSetup( gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; - NR_ServingCellConfig_t *servingcellconfigdedicated = rrc->configuration.scd; - int16_t ret = do_RRCSetup(ue_context_pP, - (uint8_t *) ue_p->Srb0.Tx_buffer.Payload, - rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id), - masterCellGroup_from_DU, - scc,servingcellconfigdedicated,&rrc->configuration); - - AssertFatal(ret>0,"Error generating RRCSetup for RRCSetupRequest\n"); - - ue_p->Srb0.Tx_buffer.payload_size = ret; + const NR_ServingCellConfig_t *sccd = rrc->configuration.scd; + ue_p->Srb0.Tx_buffer.payload_size = do_RRCSetup(ue_context_pP, + (uint8_t *) ue_p->Srb0.Tx_buffer.Payload, + rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id), + masterCellGroup, + masterCellGroup_len, + scc, + sccd, + &rrc->configuration); LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)(ue_p->Srb0.Tx_buffer.Payload), @@ -400,8 +398,8 @@ rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest( LOG_I(NR_RRC, "generate RRCSetup for RRCReestablishmentRequest \n"); rrc_gNB_ue_context_t *ue_context_pP = NULL; gNB_RRC_INST *rrc_instance_p = RC.nrrrc[ctxt_pP->module_id]; - NR_ServingCellConfigCommon_t *scc=rrc_instance_p->carrier.servingcellconfigcommon; - NR_ServingCellConfig_t *servingcellconfigdedicated = rrc_instance_p->configuration.scd; + const NR_ServingCellConfigCommon_t *scc=rrc_instance_p->carrier.servingcellconfigcommon; + const NR_ServingCellConfig_t *sccd = rrc_instance_p->configuration.scd; ue_context_pP = rrc_gNB_get_next_free_ue_context(ctxt_pP, rrc_instance_p, 0); @@ -410,7 +408,10 @@ rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest( (uint8_t *) ue_p->Srb0.Tx_buffer.Payload, rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id), NULL, - scc,servingcellconfigdedicated,&rrc_instance_p->configuration); + 0, + scc, + sccd, + &rrc_instance_p->configuration); AssertFatal(ret>0,"Error generating RRCSetup for RRCReestablishmentRequest\n"); @@ -452,9 +453,7 @@ rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest( void rrc_gNB_generate_RRCReject( const protocol_ctxt_t *const ctxt_pP, - rrc_gNB_ue_context_t *const ue_context_pP, - const int CC_id -) + rrc_gNB_ue_context_t *const ue_context_pP) //----------------------------------------------------------------------------- { LOG_I(NR_RRC, "rrc_gNB_generate_RRCReject \n"); @@ -1859,8 +1858,8 @@ int nr_rrc_reconfiguration_req(rrc_gNB_ue_context_t *const ue_context_pP int nr_rrc_gNB_decode_ccch(protocol_ctxt_t *const ctxt_pP, const uint8_t *buffer, int buffer_length, - OCTET_STRING_t *du_to_cu_rrc_container, - const int CC_id) + const uint8_t *du_to_cu_rrc_container, + int du_to_cu_rrc_container_len) { module_id_t Idx; asn_dec_rval_t dec_rval; @@ -1870,22 +1869,16 @@ int nr_rrc_gNB_decode_ccch(protocol_ctxt_t *const ctxt_pP, NR_RRCSetupRequest_IEs_t *rrcSetupRequest = NULL; NR_RRCReestablishmentRequest_IEs_t rrcReestablishmentRequest; uint64_t random_value = 0; - int i; - dec_rval = uper_decode( NULL, - &asn_DEF_NR_UL_CCCH_Message, - (void **)&ul_ccch_msg, - (uint8_t *) buffer, - 100, - 0, - 0); + LOG_I(NR_RRC, "Decoding CCCH: RNTI %04x, inst %ld, payload_size %d\n", ctxt_pP->rnti, ctxt_pP->instance, buffer_length); + dec_rval = uper_decode(NULL, &asn_DEF_NR_UL_CCCH_Message, (void **) &ul_ccch_msg, buffer, buffer_length, 0, 0); - if (dec_rval.consumed == 0) { - /* TODO */ - LOG_E(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" FATAL Error in receiving CCCH\n", - PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP)); - return -1; - } + if (dec_rval.code != RC_OK || dec_rval.consumed == 0) { + LOG_E(NR_RRC, + PROTOCOL_NR_RRC_CTXT_UE_FMT" FATAL Error in receiving CCCH\n", + PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP)); + return -1; + } if (ul_ccch_msg->message.present == NR_UL_CCCH_MessageType_PR_c1) { switch (ul_ccch_msg->message.choice.c1->present) { @@ -1991,8 +1984,7 @@ int nr_rrc_gNB_decode_ccch(protocol_ctxt_t *const ctxt_pP, PROTOCOL_NR_RRC_CTXT_UE_FMT" RRCSetupRequest without random UE identity or S-TMSI not supported, let's reject the UE\n", PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP)); rrc_gNB_generate_RRCReject(ctxt_pP, - rrc_gNB_get_ue_context(gnb_rrc_inst, ctxt_pP->rnti), - CC_id); + rrc_gNB_get_ue_context(gnb_rrc_inst, ctxt_pP->rnti)); break; } @@ -2001,8 +1993,8 @@ int nr_rrc_gNB_decode_ccch(protocol_ctxt_t *const ctxt_pP, rrc_gNB_generate_RRCSetup(ctxt_pP, rrc_gNB_get_ue_context(gnb_rrc_inst, ctxt_pP->rnti), du_to_cu_rrc_container, - gnb_rrc_inst->carrier.servingcellconfigcommon, - CC_id); + du_to_cu_rrc_container_len, + gnb_rrc_inst->carrier.servingcellconfigcommon); } break; @@ -2034,13 +2026,13 @@ int nr_rrc_gNB_decode_ccch(protocol_ctxt_t *const ctxt_pP, PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP), rrcReestablishmentRequest.ue_Identity.physCellId, RC.nrrrc[ctxt_pP->module_id]->carrier.physCellId); - rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest(ctxt_pP, CC_id); + rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest(ctxt_pP, 0); break; } LOG_D(NR_RRC, "physCellId is %ld\n", rrcReestablishmentRequest.ue_Identity.physCellId); - for (i = 0; i < rrcReestablishmentRequest.ue_Identity.shortMAC_I.size; i++) { + for (int i = 0; i < rrcReestablishmentRequest.ue_Identity.shortMAC_I.size; i++) { LOG_D(NR_RRC, "rrcReestablishmentRequest.ue_Identity.shortMAC_I.buf[%d] = %x\n", i, rrcReestablishmentRequest.ue_Identity.shortMAC_I.buf[i]); } @@ -2051,7 +2043,7 @@ int nr_rrc_gNB_decode_ccch(protocol_ctxt_t *const ctxt_pP, LOG_E(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" NR_RRCReestablishmentRequest c_RNTI range error, fallback to RRC establishment\n", PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP)); - rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest(ctxt_pP, CC_id); + rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest(ctxt_pP, 0); break; } @@ -2063,7 +2055,7 @@ int nr_rrc_gNB_decode_ccch(protocol_ctxt_t *const ctxt_pP, LOG_E(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" NR_RRCReestablishmentRequest without UE context, fallback to RRC establishment\n", PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP)); - rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest(ctxt_pP, CC_id); + rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest(ctxt_pP, 0); break; } #if(0) @@ -2074,14 +2066,14 @@ int nr_rrc_gNB_decode_ccch(protocol_ctxt_t *const ctxt_pP, LOG_E(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" NR_RRCReestablishmentRequest without UE_id(MAC) rnti %x, fallback to RRC establishment\n", PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP),c_rnti); - rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest(ctxt_pP, CC_id); + rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest(ctxt_pP, 0); break; } //previous rnti rnti_t previous_rnti = 0; - for (i = 0; i < MAX_MOBILES_PER_ENB; i++) { + for (int i = 0; i < MAX_MOBILES_PER_ENB; i++) { if (reestablish_rnti_map[i][1] == c_rnti) { previous_rnti = reestablish_rnti_map[i][0]; break; @@ -2095,7 +2087,7 @@ int nr_rrc_gNB_decode_ccch(protocol_ctxt_t *const ctxt_pP, LOG_E(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" RRCReestablishmentRequest without UE_id(MAC) previous rnti %x, fallback to RRC establishment\n", PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP),previous_rnti); - rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest(ctxt_pP, CC_id); + rrc_gNB_generate_RRCSetup_for_RRCReestablishmentRequest(ctxt_pP, 0); break; } } @@ -2149,7 +2141,7 @@ int nr_rrc_gNB_decode_ccch(protocol_ctxt_t *const ctxt_pP, ue_context_p->ue_context.reestablishment_xid = -1; // insert C-RNTI to map - for (i = 0; i < MAX_MOBILES_PER_ENB; i++) { + for (int i = 0; i < MAX_MOBILES_PER_ENB; i++) { if (reestablish_rnti_map[i][0] == 0) { reestablish_rnti_map[i][0] = ctxt_pP->rnti; reestablish_rnti_map[i][1] = c_rnti; @@ -2165,7 +2157,7 @@ int nr_rrc_gNB_decode_ccch(protocol_ctxt_t *const ctxt_pP, rrcReestablishmentRequest.ue_Identity.physCellId, ue_context_p->ue_context.reestablishment_cause); - ue_context_p->ue_context.primaryCC_id = CC_id; + ue_context_p->ue_context.primaryCC_id = 0; //LG COMMENT Idx = (ue_mod_idP * NB_RB_MAX) + DCCH; Idx = DCCH; // SRB1 @@ -2187,7 +2179,7 @@ int nr_rrc_gNB_decode_ccch(protocol_ctxt_t *const ctxt_pP, &DCCH_LCHAN_DESC, LCHAN_DESC_SIZE); - rrc_gNB_generate_RRCReestablishment(ctxt_pP, ue_context_p, CC_id); + rrc_gNB_generate_RRCReestablishment(ctxt_pP, ue_context_p, 0); LOG_I(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT"CALLING RLC CONFIG SRB1 (rbid %d)\n", PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP), @@ -2877,6 +2869,38 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *f1_setup_req) { }//for (int i=0;inum_cells_available;i++) } +void rrc_gNB_process_initial_ul_rrc_message(const f1ap_initial_ul_rrc_message_t *ul_rrc) +{ + // first get RRC instance (note, no the ITTI instance) + module_id_t i = 0; + for (i=0; i < RC.nb_nr_inst; i++) { + gNB_RRC_INST *rrc = RC.nrrrc[i]; + if (rrc->nr_cellid == ul_rrc->nr_cellid) + break; + } + //AssertFatal(i != RC.nb_nr_inst, "Cell_id not found\n"); + // TODO REMOVE_DU_RRC in monolithic mode, the MAC does not have the + // nr_cellid. Thus, the above check would fail. For the time being, just put + // a warning, as we handle one DU only anyway + if (i == RC.nb_nr_inst) { + i = 0; + LOG_W(RRC, "initial UL RRC message nr_cellid %ld does not match RRC's %ld\n", ul_rrc->nr_cellid, RC.nrrrc[0]->nr_cellid); + } + protocol_ctxt_t ctxt = { 0 }; + PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, i, GNB_FLAG_YES, ul_rrc->crnti, 0, 0); + + nr_rrc_gNB_decode_ccch(&ctxt, + ul_rrc->rrc_container, + ul_rrc->rrc_container_length, + ul_rrc->du2cu_rrc_container, + ul_rrc->du2cu_rrc_container_length); + + if (ul_rrc->rrc_container) + free(ul_rrc->rrc_container); + if (ul_rrc->du2cu_rrc_container) + free(ul_rrc->du2cu_rrc_container); +} + void rrc_gNB_process_release_request(const module_id_t gnb_mod_idP, x2ap_ENDC_sgnb_release_request_t *m) { gNB_RRC_INST *rrc = RC.nrrrc[gnb_mod_idP]; @@ -3897,49 +3921,11 @@ void *rrc_gnb_task(void *args_p) { nr_rrc_subframe_process(&RRC_SUBFRAME_PROCESS(msg_p).ctxt, RRC_SUBFRAME_PROCESS(msg_p).CC_id); break; - /* Messages from MAC */ - case NR_RRC_MAC_CCCH_DATA_IND: - { - instance_t i; - for (i=0; inr_cellid == NR_RRC_MAC_CCCH_DATA_IND(msg_p).nr_cellid) - break; - } - AssertFatal(i!=RC.nb_nr_inst, "Cell_id not found\n"); - PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, - i, - GNB_FLAG_YES, - NR_RRC_MAC_CCCH_DATA_IND(msg_p).rnti, - msg_p->ittiMsgHeader.lte_time.frame, - msg_p->ittiMsgHeader.lte_time.slot); - LOG_I(NR_RRC,"Decoding CCCH : ue %d, inst %ld, CC_id %d, ctxt %p, sib_info_p->Rx_buffer.payload_size %d\n", - ctxt.rnti, - i, - NR_RRC_MAC_CCCH_DATA_IND(msg_p).CC_id, - &ctxt, - NR_RRC_MAC_CCCH_DATA_IND(msg_p).sdu_size); - - if (NR_RRC_MAC_CCCH_DATA_IND(msg_p).sdu_size >= CCCH_SDU_SIZE) { - LOG_I(NR_RRC, "CCCH message has size %d > %d\n", - NR_RRC_MAC_CCCH_DATA_IND(msg_p).sdu_size,CCCH_SDU_SIZE); - break; - } - - nr_rrc_gNB_decode_ccch(&ctxt, - (uint8_t *)NR_RRC_MAC_CCCH_DATA_IND(msg_p).sdu, - NR_RRC_MAC_CCCH_DATA_IND(msg_p).sdu_size, - NR_RRC_MAC_CCCH_DATA_IND(msg_p).du_to_cu_rrc_container, - NR_RRC_MAC_CCCH_DATA_IND(msg_p).CC_id); - - if (NR_RRC_MAC_CCCH_DATA_IND(msg_p).du_to_cu_rrc_container) { - free(NR_RRC_MAC_CCCH_DATA_IND(msg_p).du_to_cu_rrc_container->buf); - free(NR_RRC_MAC_CCCH_DATA_IND(msg_p).du_to_cu_rrc_container); - } - } - break; + case F1AP_INITIAL_UL_RRC_MESSAGE: + AssertFatal(NODE_IS_CU(RC.nrrrc[instance]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[instance]->node_type), + "should not receive F1AP_INITIAL_UL_RRC_MESSAGE, need call by CU!\n"); + rrc_gNB_process_initial_ul_rrc_message(&F1AP_INITIAL_UL_RRC_MESSAGE(msg_p)); + break; /* Messages from PDCP */ case NR_RRC_DCCH_DATA_IND: diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index 2ee3a26c4b..08baeb3d45 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -82,9 +82,9 @@ void fix_servingcellconfigdedicated(NR_ServingCellConfig_t *scd) { void fill_default_nsa_downlinkBWP(NR_BWP_Downlink_t *bwp, long bwp_loop, - NR_CellGroupConfig_t *secondaryCellGroup, - NR_ServingCellConfig_t *servingcellconfigdedicated, - NR_ServingCellConfigCommon_t *servingcellconfigcommon, + const NR_CellGroupConfig_t *secondaryCellGroup, + const NR_ServingCellConfig_t *servingcellconfigdedicated, + const NR_ServingCellConfigCommon_t *servingcellconfigcommon, const gNB_RrcConfigurationReq *configuration, NR_UE_NR_Capability_t *uecap, int dl_antenna_ports, From 9622a56bf12389a3d1a02f775c9e99bc1499f0ba Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 10 May 2022 13:13:09 +0200 Subject: [PATCH 259/267] gNB RRC: handle F1AP_UL_RRC_MESSAGE --- common/utils/ocp_itti/intertask_interface.h | 1 + openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 45 +++++++++++---------- openair2/RRC/NR/rrc_gNB.c | 26 +++++------- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/common/utils/ocp_itti/intertask_interface.h b/common/utils/ocp_itti/intertask_interface.h index a3f447baa3..3a03e380a1 100644 --- a/common/utils/ocp_itti/intertask_interface.h +++ b/common/utils/ocp_itti/intertask_interface.h @@ -308,6 +308,7 @@ void *rrc_enb_process_msg(void *); TASK_DEF(TASK_RLC_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_RRC_ENB_NB_IoT, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_PDCP_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_PDCP_GNB, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_DATA_FORWARDING, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_END_MARKER, TASK_PRIORITY_MED, 200, NULL, NULL) \ TASK_DEF(TASK_RRC_ENB, TASK_PRIORITY_MED, 200, NULL,NULL)\ diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 9598bf1ad6..ad73a610e1 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -734,27 +734,30 @@ static void deliver_sdu_srb(void *_ue, nr_pdcp_entity_t *entity, __FILE__, __LINE__, __FUNCTION__, ue->rnti); exit(1); - srb_found: - { - uint8_t *rrc_buffer_p = entity->is_gnb ? - itti_malloc(TASK_PDCP_ENB, TASK_RRC_GNB, size): - itti_malloc(TASK_PDCP_UE, TASK_RRC_NRUE, size); - MessageDef *message_p; - - AssertFatal(rrc_buffer_p != NULL, "OUT OF MEMORY"); - memcpy(rrc_buffer_p, buf, size); - message_p = entity->is_gnb ? - itti_alloc_new_message(TASK_PDCP_ENB, 0, NR_RRC_DCCH_DATA_IND): - itti_alloc_new_message(TASK_PDCP_UE, 0, NR_RRC_DCCH_DATA_IND); - - AssertFatal(message_p != NULL, "OUT OF MEMORY"); - NR_RRC_DCCH_DATA_IND(message_p).dcch_index = srb_id; - NR_RRC_DCCH_DATA_IND(message_p).sdu_p = rrc_buffer_p; - NR_RRC_DCCH_DATA_IND(message_p).sdu_size = size; - NR_RRC_DCCH_DATA_IND(message_p).rnti = ue->rnti; - - itti_send_msg_to_task(entity->is_gnb ? TASK_RRC_GNB : TASK_RRC_NRUE, 0, message_p); - } +srb_found: + if (entity->is_gnb) { + MessageDef *message_p = itti_alloc_new_message(TASK_PDCP_GNB, 0, F1AP_UL_RRC_MESSAGE); + AssertFatal(message_p != NULL, "OUT OF MEMORY\n"); + f1ap_ul_rrc_message_t *ul_rrc = &F1AP_UL_RRC_MESSAGE(message_p); + ul_rrc->rnti = ue->rnti; + ul_rrc->srb_id = srb_id; + ul_rrc->rrc_container = malloc(size); + AssertFatal(ul_rrc->rrc_container != NULL, "OUT OF MEMORY\n"); + memcpy(ul_rrc->rrc_container, buf, size); + ul_rrc->rrc_container_length = size; + itti_send_msg_to_task(TASK_RRC_GNB, 0, message_p); + } else { + uint8_t *rrc_buffer_p = itti_malloc(TASK_PDCP_UE, TASK_RRC_NRUE, size); + AssertFatal(rrc_buffer_p != NULL, "OUT OF MEMORY\n"); + memcpy(rrc_buffer_p, buf, size); + MessageDef *message_p = itti_alloc_new_message(TASK_PDCP_UE, 0, NR_RRC_DCCH_DATA_IND); + AssertFatal(message_p != NULL, "OUT OF MEMORY\n"); + NR_RRC_DCCH_DATA_IND(message_p).dcch_index = srb_id; + NR_RRC_DCCH_DATA_IND(message_p).sdu_p = rrc_buffer_p; + NR_RRC_DCCH_DATA_IND(message_p).sdu_size = size; + NR_RRC_DCCH_DATA_IND(message_p).rnti = ue->rnti; + itti_send_msg_to_task(TASK_RRC_NRUE, 0, message_p); + } } static void deliver_pdu_srb(void *_ue, nr_pdcp_entity_t *entity, diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 208a78d37e..8be829f51f 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -3928,28 +3928,24 @@ void *rrc_gnb_task(void *args_p) { break; /* Messages from PDCP */ - case NR_RRC_DCCH_DATA_IND: + case F1AP_UL_RRC_MESSAGE: PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, GNB_FLAG_YES, - NR_RRC_DCCH_DATA_IND(msg_p).rnti, - msg_p->ittiMsgHeader.lte_time.frame, - msg_p->ittiMsgHeader.lte_time.slot); - LOG_D(NR_RRC,"Decoding DCCH : ue %d, inst %ld, ctxt %p, size %d\n", + F1AP_UL_RRC_MESSAGE(msg_p).rnti, + 0, + 0); + LOG_D(NR_RRC,"Decoding DCCH %d: ue %04x, inst %ld, ctxt %p, size %d\n", + F1AP_UL_RRC_MESSAGE(msg_p).srb_id, ctxt.rnti, instance, &ctxt, - NR_RRC_DCCH_DATA_IND(msg_p).sdu_size); - LOG_D(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" Received on DCCH %d %s\n", - PROTOCOL_NR_RRC_CTXT_UE_ARGS(&ctxt), - NR_RRC_DCCH_DATA_IND(msg_p).dcch_index, - msg_name_p); + F1AP_UL_RRC_MESSAGE(msg_p).rrc_container_length); rrc_gNB_decode_dcch(&ctxt, - NR_RRC_DCCH_DATA_IND(msg_p).dcch_index, - NR_RRC_DCCH_DATA_IND(msg_p).sdu_p, - NR_RRC_DCCH_DATA_IND(msg_p).sdu_size); - result = itti_free(ITTI_MSG_ORIGIN_ID(msg_p), NR_RRC_DCCH_DATA_IND(msg_p).sdu_p); - + F1AP_UL_RRC_MESSAGE(msg_p).srb_id, + F1AP_UL_RRC_MESSAGE(msg_p).rrc_container, + F1AP_UL_RRC_MESSAGE(msg_p).rrc_container_length); + free(F1AP_UL_RRC_MESSAGE(msg_p).rrc_container); break; case NGAP_DOWNLINK_NAS: From b749ac12f71c6cf546fc5168d86c155978598f52 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 8 Aug 2022 17:12:12 +0200 Subject: [PATCH 260/267] hotfix for UE NDI init --- openair1/SCHED_NR_UE/harq_nr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/SCHED_NR_UE/harq_nr.c b/openair1/SCHED_NR_UE/harq_nr.c index 795cea5dfa..dc62ea646c 100644 --- a/openair1/SCHED_NR_UE/harq_nr.c +++ b/openair1/SCHED_NR_UE/harq_nr.c @@ -308,7 +308,7 @@ void init_downlink_harq_status(NR_DL_UE_HARQ_t *dl_harq) dl_harq->status = SCH_IDLE; dl_harq->first_rx = 1; dl_harq->DLround = 0; - dl_harq->Ndi = 1; + dl_harq->Ndi = 2; // set to an invalid value dl_harq->ack = DL_ACKNACK_NO_SET; } From 5382227866f0a64f712fd8ebfe6f217f5235c04f Mon Sep 17 00:00:00 2001 From: Angelo Athanassopoulos Date: Mon, 8 Aug 2022 17:18:04 +0200 Subject: [PATCH 261/267] Fix SDAP, get QFI & PDUSession ID from CN --- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 6 +++--- openair2/SDAP/nr_sdap/nr_sdap.c | 9 +++++++++ openair2/SDAP/nr_sdap/nr_sdap.h | 2 ++ openair3/NAS/NR_UE/nr_nas_msg_sim.c | 9 +++++++-- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 9598bf1ad6..4ce570bc12 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -484,12 +484,12 @@ static void *ue_tun_read_thread(void *_) ctxt.rnti = rnti; bool dc = SDAP_HDR_UL_DATA_PDU; - uint8_t qfi = 7; - int pdusession_id = 10; + extern uint8_t nas_qfi; + extern uint8_t nas_pduid; sdap_data_req(&ctxt, SRB_FLAG_NO, rb_id, RLC_MUI_UNDEFINED, RLC_SDU_CONFIRM_NO, len, (unsigned char *)rx_buf, - PDCP_TRANSMISSION_MODE_DATA, NULL, NULL, qfi, dc, pdusession_id); + PDCP_TRANSMISSION_MODE_DATA, NULL, NULL, nas_qfi, dc, nas_pduid); } return NULL; diff --git a/openair2/SDAP/nr_sdap/nr_sdap.c b/openair2/SDAP/nr_sdap/nr_sdap.c index dd7a76920d..6457843ae0 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.c +++ b/openair2/SDAP/nr_sdap/nr_sdap.c @@ -21,6 +21,9 @@ #include "nr_sdap.h" +uint8_t nas_qfi; +uint8_t nas_pduid; + bool sdap_data_req(protocol_ctxt_t *ctxt_p, const srb_flag_t srb_flag, const rb_id_t rb_id, @@ -84,3 +87,9 @@ void sdap_data_ind(rb_id_t pdcp_entity, buf, size); } + +void set_qfi_pduid(uint8_t qfi, uint8_t pduid){ + nas_qfi = qfi; + nas_pduid = pduid; + return; +} diff --git a/openair2/SDAP/nr_sdap/nr_sdap.h b/openair2/SDAP/nr_sdap/nr_sdap.h index 5959ca1558..ea4fe7f74d 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.h +++ b/openair2/SDAP/nr_sdap/nr_sdap.h @@ -62,4 +62,6 @@ void sdap_data_ind(rb_id_t pdcp_entity, int size ); +void set_qfi_pduid(uint8_t qfi, uint8_t pduid); + #endif diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index e151fec9b4..43c3b56aa4 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -44,6 +44,7 @@ #include #include #include +#include "openair2/SDAP/nr_sdap/nr_sdap.h" uint8_t *registration_request_buf; uint32_t registration_request_len; @@ -915,7 +916,7 @@ void *nas_nrue_task(void *args_p) payload_container = pdu_buffer + offset; } offset = 0; - + uint8_t pdu_id = *(pdu_buffer+14); while(offset < payload_container_length) { // Fixme: this is not good 'type' 0x29 searching in TLV like structure // AND fix dirsty code copy hereafter of the same!!! @@ -929,9 +930,13 @@ void *nas_nrue_task(void *args_p) *(payload_container+offset+3), *(payload_container+offset+4), *(payload_container+offset+5), *(payload_container+offset+6)); nas_config(1,third_octet,fourth_octet,"oaitun_ue"); - break; } } + if (*(payload_container + offset) == 0x79) { + uint8_t qfi = *(payload_container+offset+3); + set_qfi_pduid(qfi, pdu_id); + break; + } offset++; } } From ee7aca5d05ca2711690e8f31eb36764c3d2dd70e Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 9 Aug 2022 12:20:05 +0200 Subject: [PATCH 262/267] ngap: minor fix: access the array correctly --- openair3/NGAP/ngap_gNB.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair3/NGAP/ngap_gNB.c b/openair3/NGAP/ngap_gNB.c index 9d6bd7f07f..59e275ad53 100644 --- a/openair3/NGAP/ngap_gNB.c +++ b/openair3/NGAP/ngap_gNB.c @@ -494,7 +494,7 @@ static int ngap_gNB_generate_ng_setup_request( ssi = (NGAP_SliceSupportItem_t *)calloc(1, sizeof(NGAP_SliceSupportItem_t)); INT8_TO_OCTET_STRING(instance_p->s_nssai[i][si].sST, &ssi->s_NSSAI.sST); - if(instance_p->s_nssai[i]->sD_flag) { + if (instance_p->s_nssai[i][si].sD_flag) { ssi->s_NSSAI.sD = calloc(1, sizeof(NGAP_SD_t)); ssi->s_NSSAI.sD->buf = calloc(3, sizeof(uint8_t)); ssi->s_NSSAI.sD->size = 3; From c21f86421eab475cf111f9036838ba358ab8e25c Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 9 Aug 2022 15:05:37 +0200 Subject: [PATCH 263/267] Test SDAP in 5G FDD RFsim test --- ci-scripts/conf_files/gnb.sa.band66.fr1.106PRB.usrpn300.conf | 1 + ci-scripts/xml_files/container_5g_fdd_rfsim.xml | 2 +- ci-scripts/xml_files/container_5g_fdd_rfsim_down.xml | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ci-scripts/conf_files/gnb.sa.band66.fr1.106PRB.usrpn300.conf b/ci-scripts/conf_files/gnb.sa.band66.fr1.106PRB.usrpn300.conf index 197e1d211c..6b7122341d 100644 --- a/ci-scripts/conf_files/gnb.sa.band66.fr1.106PRB.usrpn300.conf +++ b/ci-scripts/conf_files/gnb.sa.band66.fr1.106PRB.usrpn300.conf @@ -33,6 +33,7 @@ gNBs = ////////// Physical parameters: min_rxtxtime = 6; + enable_sdap = 1; pdcch_ConfigSIB1 = ( { diff --git a/ci-scripts/xml_files/container_5g_fdd_rfsim.xml b/ci-scripts/xml_files/container_5g_fdd_rfsim.xml index b41dafb767..09f3d62e26 100644 --- a/ci-scripts/xml_files/container_5g_fdd_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_fdd_rfsim.xml @@ -22,7 +22,7 @@ --> rfsim-5gnr-fdd - Testing 5G NR RF sim - Monolithic FDD gNB + Testing 5G NR RF sim - Monolithic FDD gNB with SDAP wrench 4 diff --git a/ci-scripts/xml_files/container_5g_fdd_rfsim_down.xml b/ci-scripts/xml_files/container_5g_fdd_rfsim_down.xml index d960949f7d..408348e446 100644 --- a/ci-scripts/xml_files/container_5g_fdd_rfsim_down.xml +++ b/ci-scripts/xml_files/container_5g_fdd_rfsim_down.xml @@ -22,7 +22,7 @@ --> rfsim-5gnr-fdd-down - CleanUp 5G RF - Monolithic FDD gNB + CleanUp 5G RF - Monolithic FDD gNB with SDAP trash 100012 From f1c5378e3b6a38c7a23bf7c41cf16537b529ccb3 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 2 Aug 2022 12:44:44 +0200 Subject: [PATCH 264/267] Shorten 5G RFsim tab names --- ci-scripts/xml_files/container_5g_f1_rfsim.xml | 2 +- ci-scripts/xml_files/container_5g_f1_rfsim_down.xml | 2 +- ci-scripts/xml_files/container_5g_fdd_rfsim.xml | 2 +- ci-scripts/xml_files/container_5g_fdd_rfsim_down.xml | 2 +- ci-scripts/xml_files/container_5g_rfsim.xml | 2 +- ci-scripts/xml_files/container_5g_rfsim_down.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ci-scripts/xml_files/container_5g_f1_rfsim.xml b/ci-scripts/xml_files/container_5g_f1_rfsim.xml index 05b20afed3..61157f72df 100644 --- a/ci-scripts/xml_files/container_5g_f1_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_f1_rfsim.xml @@ -22,7 +22,7 @@ --> rfsim-5gnr-f1 - Testing 5G NR RF sim in containers - CU-DU F1 split + CU-DU F1 split wrench 100021 diff --git a/ci-scripts/xml_files/container_5g_f1_rfsim_down.xml b/ci-scripts/xml_files/container_5g_f1_rfsim_down.xml index ac3f7347ba..bb640381cf 100644 --- a/ci-scripts/xml_files/container_5g_f1_rfsim_down.xml +++ b/ci-scripts/xml_files/container_5g_f1_rfsim_down.xml @@ -22,7 +22,7 @@ --> rfsim-5gnr-down-f1 - CleanUp 5G RF - CU-DU F1 split + CleanUp CU-DU F1 split trash 100022 diff --git a/ci-scripts/xml_files/container_5g_fdd_rfsim.xml b/ci-scripts/xml_files/container_5g_fdd_rfsim.xml index 09f3d62e26..9564b24b35 100644 --- a/ci-scripts/xml_files/container_5g_fdd_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_fdd_rfsim.xml @@ -22,7 +22,7 @@ --> rfsim-5gnr-fdd - Testing 5G NR RF sim - Monolithic FDD gNB with SDAP + Monolithic FDD gNB with SDAP wrench 4 diff --git a/ci-scripts/xml_files/container_5g_fdd_rfsim_down.xml b/ci-scripts/xml_files/container_5g_fdd_rfsim_down.xml index 408348e446..12648ca750 100644 --- a/ci-scripts/xml_files/container_5g_fdd_rfsim_down.xml +++ b/ci-scripts/xml_files/container_5g_fdd_rfsim_down.xml @@ -22,7 +22,7 @@ --> rfsim-5gnr-fdd-down - CleanUp 5G RF - Monolithic FDD gNB with SDAP + CleanUp Monolithic FDD gNB with SDAP trash 100012 diff --git a/ci-scripts/xml_files/container_5g_rfsim.xml b/ci-scripts/xml_files/container_5g_rfsim.xml index a1f50948a5..653e1e6513 100644 --- a/ci-scripts/xml_files/container_5g_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_rfsim.xml @@ -22,7 +22,7 @@ --> rfsim-5gnr-tdd - Testing 5G NR RF sim - Monolithic TDD gNB + Monolithic TDD gNB wrench 4 diff --git a/ci-scripts/xml_files/container_5g_rfsim_down.xml b/ci-scripts/xml_files/container_5g_rfsim_down.xml index b369b1fad8..028ff61864 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_down.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_down.xml @@ -22,7 +22,7 @@ --> rfsim-5gnr-down - CleanUp 5G RF - Monolithic TDD gNB + CleanUp Monolithic TDD gNB trash 100002 From 888c4ead0fe7a87f39bdc50571731b906d138e31 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Thu, 4 Aug 2022 15:58:40 +0200 Subject: [PATCH 265/267] fix(ci): Fixes for the legacy LTE bench - Problem with escaping chars - Killing properly tshark process on EPC - standalone Terminate eNB was failing Signed-off-by: Raphael Defosseux --- ci-scripts/cls_oaicitest.py | 25 ++++++++++++++----------- ci-scripts/ran.py | 14 ++++++-------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index 9d5ae84038..32d9c48966 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -1329,7 +1329,7 @@ class OaiCiTest(): SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) if self.ADBCentralized: SSH.command('adb devices', '\$', 15) - self.UEDevices = re.findall("\\\\r\\\\n([A-Za-z0-9]+)\\\\tdevice",SSH.getBefore()) + self.UEDevices = re.findall('\r\n([A-Za-z0-9]+)\tdevice',SSH.getBefore()) #report number and id of devices found msg = "UEDevices found by GetAllUEDevices : " + " ".join(self.UEDevices) logging.debug(msg) @@ -1379,8 +1379,7 @@ class OaiCiTest(): SSH.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) if self.ADBCentralized: SSH.command('lsusb | egrep --colour=never "Future Technology Devices International, Ltd FT2232C" | sed -e "s#:.*##" -e "s# #_#g"', '\$', 15) - #self.CatMDevices = re.findall("\\\\r\\\\n([A-Za-z0-9_]+)",SSH.getBefore()) - self.CatMDevices = re.findall("\\\\r\\\\n([A-Za-z0-9_]+)",SSH.getBefore()) + self.CatMDevices = re.findall('\r\n([A-Za-z0-9_]+)',SSH.getBefore()) else: if (os.path.isfile('./modules_list.txt')): os.remove('./modules_list.txt') @@ -2046,7 +2045,7 @@ class OaiCiTest(): req_bandwidth = '%.1f Gbits/sec' % req_bw req_bw = req_bw * 1000000000 - result = re.search('Server Report:\\\\r\\\\n(?:|\[ *\d+\].*) (?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(\d+\/..\d+) +(\((?P[0-9\.]+)%\))', SSH.getBefore()) + result = re.search('Server Report:\r\n(?:|\[ *\d+\].*) (?P[0-9\.]+ [KMG]bits\/sec) +(?P[0-9\.]+ ms) +(\d+\/..\d+) +(\((?P[0-9\.]+)%\))', SSH.getBefore()) if result is not None: bitrate = result.group('bitrate') packetloss = result.group('packetloss') @@ -2262,7 +2261,7 @@ class OaiCiTest(): def Iperf_analyzeV3Output(self, lock, UE_IPAddress, device_id, statusQueue,SSH): - result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?:|[0-9\.]+ ms +\d+\/\d+ \((?P[0-9\.]+)%\)) +(?:|receiver)\\\\r\\\\n(?:|\[ *\d+\] Sent \d+ datagrams)\\\\r\\\\niperf Done\.', SSH.getBefore()) + result = re.search('(?P[0-9\.]+ [KMG]bits\/sec) +(?:|[0-9\.]+ ms +\d+\/\d+ \((?P[0-9\.]+)%\)) +(?:|receiver)\r\n(?:|\[ *\d+\] Sent \d+ datagrams)\r\niperf Done\.', SSH.getBefore()) if result is None: result = re.search('(?Piperf: error - [a-zA-Z0-9 :]+)', SSH.getBefore()) lock.acquire() @@ -3865,7 +3864,7 @@ class OaiCiTest(): SSH = sshconnection.SSHConnection() SSH.open(IPAddress, UserName, Password) SSH.command('lsb_release -a', '\$', 5) - result = re.search('Description:\\\\t(?P[a-zA-Z0-9\-\_\.\ ]+)', SSH.getBefore()) + result = re.search('Description:\t(?P[a-zA-Z0-9\-\_\.\ ]+)', SSH.getBefore()) if result is not None: OsVersion = result.group('os_type') logging.debug('OS is: ' + OsVersion) @@ -3883,13 +3882,13 @@ class OaiCiTest(): logging.debug('OS is: ' + OsVersion) HTML.OsVersion[idx]=OsVersion SSH.command('uname -r', '\$', 5) - result = re.search('uname -r\\\\r\\\\n(?P[a-zA-Z0-9\-\_\.]+)', SSH.getBefore()) + result = re.search('uname -r\r\n(?P[a-zA-Z0-9\-\_\.]+)', SSH.getBefore()) if result is not None: KernelVersion = result.group('kernel_version') logging.debug('Kernel Version is: ' + KernelVersion) HTML.KernelVersion[idx]=KernelVersion - SSH.command('dpkg --list | egrep --color=never libuhd003', '\$', 5) - result = re.search('libuhd003:amd64 *(?P[0-9\.]+)', SSH.getBefore()) + SSH.command('dpkg --list | egrep --color=never libuhd', '\$', 5) + result = re.search('libuhd.*:amd64 *(?P[0-9\.]+)', SSH.getBefore()) if result is not None: UhdVersion = result.group('uhd_version') logging.debug('UHD Version is: ' + UhdVersion) @@ -3902,7 +3901,7 @@ class OaiCiTest(): logging.debug('UHD Version is: ' + UhdVersion) HTML.UhdVersion[idx]=UhdVersion SSH.command('echo ' + Password + ' | sudo -S uhd_find_devices', '\$', 180) - usrp_boards = re.findall('product: ([0-9A-Za-z]+)\\\\r\\\\n', SSH.getBefore()) + usrp_boards = re.findall('product: ([0-9A-Za-z]+)', SSH.getBefore()) count = 0 for board in usrp_boards: if count == 0: @@ -3914,14 +3913,18 @@ class OaiCiTest(): logging.debug('USRP Board(s) : ' + UsrpBoard) HTML.UsrpBoard[idx]=UsrpBoard SSH.command('lscpu', '\$', 5) - result = re.search('CPU\(s\): *(?P[0-9]+).*Model name: *(?P[a-zA-Z0-9\-\_\.\ \(\)]+).*CPU MHz: *(?P[0-9\.]+)', SSH.getBefore()) + result = re.search('CPU\(s\): *(?P[0-9]+)', SSH.getBefore()) if result is not None: CpuNb = result.group('nb_cpus') logging.debug('nb_cpus: ' + CpuNb) HTML.CpuNb[idx]=CpuNb + result = re.search('Model name: *(?P[a-zA-Z0-9\-\_\.\ \(\)]+)', SSH.getBefore()) + if result is not None: CpuModel = result.group('model') logging.debug('model: ' + CpuModel) HTML.CpuModel[idx]=CpuModel + result = re.search('CPU MHz: *(?P[0-9\.]+)', SSH.getBefore()) + if result is not None: CpuMHz = result.group('cpu_mhz') + ' MHz' logging.debug('cpu_mhz: ' + CpuMHz) HTML.CpuMHz[idx]=CpuMHz diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index 680763d247..a576054370 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -374,7 +374,7 @@ class RANManagement(): mySSH.open(lIpAddr, lUserName, lPassWord) eth_interface = 'any' fltr = 'sctp' - logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + ' with filter "' + fltr + '"\u001B[0m') + logging.debug('\u001B[1m Launching tshark on xNB on interface ' + eth_interface + ' with filter "' + fltr + '"\u001B[0m') pcapfile = pcapfile_prefix + self.testCase_id + '_log.pcap' mySSH.command('echo ' + lPassWord + ' | sudo -S rm -f /tmp/' + pcapfile , '\$', 5) mySSH.command('echo $USER; nohup sudo -E tshark -i ' + eth_interface + ' -f "' + fltr + '" -w /tmp/' + pcapfile + ' > /dev/null 2>&1 &','\$', 5) @@ -390,7 +390,7 @@ class RANManagement(): mySSH.open(localEpcIpAddr, localEpcUserName, localEpcPassword) eth_interface = 'any' fltr = 'sctp' - logging.debug('\u001B[1m Launching tshark on interface ' + eth_interface + ' with filter "' + fltr + '"\u001B[0m') + logging.debug('\u001B[1m Launching tshark on EPC on interface ' + eth_interface + ' with filter "' + fltr + '"\u001B[0m') self.epcPcapFile = 'enb_' + self.testCase_id + '_s1log.pcap' mySSH.command('echo ' + localEpcPassword + ' | sudo -S rm -f /tmp/' + self.epcPcapFile , '\$', 5) mySSH.command('echo $USER; nohup sudo tshark -f "host ' + lIpAddr +'" -i ' + eth_interface + ' -f "' + fltr + '" -w /tmp/' + self.epcPcapFile + ' > /tmp/tshark.log 2>&1 &', localEpcUserName, 5) @@ -517,7 +517,7 @@ class RANManagement(): localEpcUserName = EPC.UserName localEpcPassword = EPC.Password mySSH.open(localEpcIpAddr, localEpcUserName, localEpcPassword) - logging.debug('\u001B[1m Stopping tshark \u001B[0m') + logging.debug('\u001B[1m Stopping tshark on EPC \u001B[0m') mySSH.command('echo ' + localEpcPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) if self.epcPcapFile != '': mySSH.command('echo ' + localEpcPassword + ' | sudo -S chmod 666 /tmp/' + self.epcPcapFile, '\$', 5) @@ -644,18 +644,16 @@ class RANManagement(): time.sleep(5) mySSH.command('rm -f my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) #stopping tshark (valid if eNB and enabled in xml, will not harm otherwise) - logging.debug('\u001B[1m Stopping tshark \u001B[0m') + logging.debug('\u001B[1m Stopping tshark on xNB \u001B[0m') mySSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) time.sleep(1) mySSH.close() - # If tracer options is on, stopping tshark on EPC side - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if (result is not None): + if EPC.IPAddress != "none" and EPC.IPAddress != '': localEpcIpAddr = EPC.IPAddress localEpcUserName = EPC.UserName localEpcPassword = EPC.Password + logging.debug('\u001B[1m Stopping tshark on EPC (' + localEpcIpAddr + ') \u001B[0m') mySSH.open(localEpcIpAddr, localEpcUserName, localEpcPassword) - logging.debug('\u001B[1m Stopping tshark \u001B[0m') mySSH.command('echo ' + localEpcPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) time.sleep(1) if self.epcPcapFile != '': From 17aef213a1f5d016d1c8e58be5af101ecbd271e4 Mon Sep 17 00:00:00 2001 From: Angelo Athanassopoulos Date: Wed, 10 Aug 2022 17:08:28 +0200 Subject: [PATCH 266/267] Fix: noS1 with SDAP --- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 4ce570bc12..f0d3db314b 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -591,8 +591,10 @@ uint64_t nr_pdcp_module_init(uint64_t _pdcp_optmask, int id) int num_if = (NFAPI_MODE == NFAPI_UE_STUB_PNF || IS_SOFTMODEM_SIML1 || NFAPI_MODE == NFAPI_MODE_STANDALONE_PNF)? MAX_MOBILES_PER_ENB : 1; netlink_init_tun(ifsuffix_ue, num_if, id); //Add --nr-ip-over-lte option check for next line - if (IS_SOFTMODEM_NOS1) - nas_config(1, 1, !get_softmodem_params()->nsa ? 2 : 3, ifsuffix_ue); + if (IS_SOFTMODEM_NOS1){ + nas_config(1, 1, !get_softmodem_params()->nsa ? 2 : 3, ifsuffix_ue); + set_qfi_pduid(7, 10); + } LOG_I(PDCP, "UE pdcp will use tun interface\n"); start_pdcp_tun_ue(); } else if(ENB_NAS_USE_TUN) { From eba7dc5c76236024c6ea1e2a4444e20505b6f460 Mon Sep 17 00:00:00 2001 From: laurent Date: Thu, 4 Aug 2022 13:26:59 +0200 Subject: [PATCH 267/267] Print asn1c encoding logs using OAI logging system --- cmake_targets/CMakeLists.txt | 12 ++++--- common/utils/config.h | 56 ++++++++++++++++++++++++++++++++ openair2/F1AP/f1ap_common.c | 21 ------------ openair2/F1AP/f1ap_common.h | 9 ----- openair2/M2AP/m2ap_common.c | 21 ------------ openair2/M2AP/m2ap_common.h | 9 ++--- openair2/X2AP/x2ap_common.c | 21 ------------ openair2/X2AP/x2ap_common.h | 9 ++--- openair3/COMMON/security_types.h | 8 ++--- openair3/M3AP/m3ap_common.c | 21 ------------ openair3/M3AP/m3ap_common.h | 8 ++--- openair3/NGAP/ngap_common.h | 12 ------- openair3/S1AP/s1ap_common.h | 15 --------- openair3/TEST/test_kdf.c | 4 --- 14 files changed, 71 insertions(+), 155 deletions(-) create mode 100644 common/utils/config.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 157ac1f6b3..f85e994db0 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -334,13 +334,9 @@ add_definitions("-DPACKAGE_BUGREPORT=\"openair4g-devel@lists.eurecom.fr\"") # Debug related options ######################################### -add_boolean_option(ASN_EMIT_DEBUG False "ASN1 coder/decoder Debug") -add_boolean_option(ASN_THREAD_SAFE True "ASN1 coder/decoder Debug") -add_boolean_option(MSG_PRINT True "print debug messages") +add_boolean_option(DEBUG_ASN1C False "ASN1 coder/decoder Debug traces, see common/utils/config.h, the logs are regular OAI logs, in the log group 'ASN'") add_boolean_option(DISABLE_XER_PRINT False "print XER Format") add_boolean_option(XER_PRINT False "print XER Format") -add_boolean_option(RRC_MSG_PRINT False "print RRC messages") -add_boolean_option(PDCP_MSG_PRINT False "print PDCP messages to /tmp/pdcp.log") add_boolean_option(DEBUG_PDCP_PAYLOAD False "print PDCP PDU to stdout") # if true, make sure that global and PDCP log levels are trace add_boolean_option(DEBUG_MAC_INTERFACE False "print MAC-RLC PDU exchange to stdout") # if true, make sure that global and PDCP log levels are trace add_boolean_option(TRACE_RLC_PAYLOAD False "print RLC PDU to stdout") # if true, make sure that global and PDCP log levels are trace @@ -358,6 +354,12 @@ add_library(ITTI ) add_dependencies(ITTI rrc_flag) +# asn1c skeletons have hardcoded this flag to make customized debug logs +# OAI uses this feature to re-use OAI LOG_I(ASN, ...) +if (DEBUG_ASN1C) + add_definitions(-DHAVE_CONFIG_H) +endif() + ################################################## # ASN.1 grammar C code generation & dependencies # ################################################## diff --git a/common/utils/config.h b/common/utils/config.h new file mode 100644 index 0000000000..597ead7ed6 --- /dev/null +++ b/common/utils/config.h @@ -0,0 +1,56 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef UTILS_CONFIG_H_ASN1 +#define UTILS_CONFIG_H_ASN1 + +// This is hard coded file name "config.h" and HAVE_CONFIG_H_ in asn1c skeletons + +/* + * This file "config.h" will be used by asn1c if HAVE_CONFIG_H_ is defined and + * included. This logs asn1c encoder and decoder traces at execution time using + * the regular OAI logging system, i.e., LOG_I(ASN...); + * + * As it is very verbose, note that you can change the log level per module in + * source or in gdb, e.g., to only activate it for a short time. + * + * In code: + * ``` + * set_log(ASN, OAI_INFO); // enable logging + * // do your encoding here + * set_log(ASN, OAI_ERR); // disable logging + * ``` + * + * in gdb: + * ``` + * gdb> p set_log(ASN, 1) // disable log, 1 == OAI_ERR + * gdb> p set_log(ASN, 5) // enable log, 5 == OAI_INFO + * ``` + */ + +#include "common/utils/LOG/log.h" +#if DEBUG_ASN1C +#define ASN_DEBUG(x...) do{ LOG_I(ASN,x);LOG_I(ASN,"\n"); } while(false) +#else +#define ASN_DEBUG(x...) +#endif + +#endif /* UTILS_CONFIG_H_ASN1 */ diff --git a/openair2/F1AP/f1ap_common.c b/openair2/F1AP/f1ap_common.c index 338b5f0c2b..efcb1d161b 100644 --- a/openair2/F1AP/f1ap_common.c +++ b/openair2/F1AP/f1ap_common.c @@ -35,27 +35,6 @@ static f1ap_cudu_inst_t *f1_du_inst[NUMBER_OF_eNB_MAX]= {0}; static f1ap_cudu_inst_t *f1_cu_inst[NUMBER_OF_eNB_MAX]= {0}; -#if defined(EMIT_ASN_DEBUG_EXTERN) -int asn_debug = 0; -int asn1_xer_print = 0; - -inline void ASN_DEBUG(const char *fmt, ...) { - if (asn_debug) { - int adi = asn_debug_indent; - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "[ASN1]"); - - while(adi--) - fprintf(stderr, " "); - - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - } -} -#endif - uint8_t F1AP_get_next_transaction_identifier(instance_t enb_mod_idP, instance_t cu_mod_idP) { static uint8_t transaction_identifier[NUMBER_OF_eNB_MAX]; transaction_identifier[enb_mod_idP+cu_mod_idP] = diff --git a/openair2/F1AP/f1ap_common.h b/openair2/F1AP/f1ap_common.h index 6b64e1b59e..e89e8a70cc 100644 --- a/openair2/F1AP/f1ap_common.h +++ b/openair2/F1AP/f1ap_common.h @@ -29,11 +29,6 @@ * \note * \warning */ - -#if HAVE_CONFIG_H_ - #include "config.h" -#endif - #ifndef F1AP_COMMON_H_ #define F1AP_COMMON_H_ @@ -43,10 +38,6 @@ #define F1AP_UE_IDENTIFIER_NUMBER 3 #define F1AP_TRANSACTION_IDENTIFIER_NUMBER 3 -#if defined(EMIT_ASN_DEBUG_EXTERN) - inline void ASN_DEBUG(const char *fmt, ...); -#endif - #include "F1AP_RAT-FrequencyPriorityInformation.h" #include "F1AP_DLUPTNLInformation-ToBeSetup-Item.h" #include "F1AP_PrivateMessage.h" diff --git a/openair2/M2AP/m2ap_common.c b/openair2/M2AP/m2ap_common.c index d288a0a114..aa090d124d 100644 --- a/openair2/M2AP/m2ap_common.c +++ b/openair2/M2AP/m2ap_common.c @@ -31,27 +31,6 @@ #include "m2ap_common.h" #include "M2AP_M2AP-PDU.h" -int asn_debug = 0; -int asn1_xer_print = 0; - -#if defined(EMIT_ASN_DEBUG_EXTERN) -inline void ASN_DEBUG(const char *fmt, ...) -{ - if (asn_debug) { - int adi = asn_debug_indent; - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "[ASN1]"); - - while(adi--) fprintf(stderr, " "); - - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - } -} -#endif - ssize_t m2ap_generate_initiating_message( uint8_t **buffer, uint32_t *length, diff --git a/openair2/M2AP/m2ap_common.h b/openair2/M2AP/m2ap_common.h index 0a6895fcb7..2e84c51938 100644 --- a/openair2/M2AP/m2ap_common.h +++ b/openair2/M2AP/m2ap_common.h @@ -18,10 +18,8 @@ * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org */ - -#if HAVE_CONFIG_H_ -# include "config.h" -#endif +#ifndef M2AP_COMMON_H_ +#define M2AP_COMMON_H_ #include "M2AP_ProtocolIE-Field.h" #include "M2AP_M2AP-PDU.h" @@ -38,9 +36,6 @@ #include "common/ran_context.h" -#ifndef M2AP_COMMON_H_ -#define M2AP_COMMON_H_ - /** @defgroup _m2ap_impl_ M2AP Layer Reference Implementation * @ingroup _ref_implementation_ * @{ diff --git a/openair2/X2AP/x2ap_common.c b/openair2/X2AP/x2ap_common.c index 93a8c32513..a687b90666 100644 --- a/openair2/X2AP/x2ap_common.c +++ b/openair2/X2AP/x2ap_common.c @@ -31,27 +31,6 @@ #include "x2ap_common.h" #include "X2AP_X2AP-PDU.h" -int asn_debug = 0; -int asn1_xer_print = 0; - -#if defined(EMIT_ASN_DEBUG_EXTERN) -inline void ASN_DEBUG(const char *fmt, ...) -{ - if (asn_debug) { - int adi = asn_debug_indent; - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "[ASN1]"); - - while(adi--) fprintf(stderr, " "); - - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - } -} -#endif - ssize_t x2ap_generate_initiating_message( uint8_t **buffer, uint32_t *length, diff --git a/openair2/X2AP/x2ap_common.h b/openair2/X2AP/x2ap_common.h index 7dd88ffa21..e7b86c77b9 100644 --- a/openair2/X2AP/x2ap_common.h +++ b/openair2/X2AP/x2ap_common.h @@ -18,10 +18,8 @@ * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org */ - -#if HAVE_CONFIG_H_ -# include "config.h" -#endif +#ifndef X2AP_COMMON_H_ +#define X2AP_COMMON_H_ #include "X2AP_ProtocolIE-Field.h" #include "X2AP_X2AP-PDU.h" @@ -35,9 +33,6 @@ #include "X2AP_asn_constant.h" #include "intertask_interface.h" -#ifndef X2AP_COMMON_H_ -#define X2AP_COMMON_H_ - /** @defgroup _x2ap_impl_ X2AP Layer Reference Implementation * @ingroup _ref_implementation_ * @{ diff --git a/openair3/COMMON/security_types.h b/openair3/COMMON/security_types.h index eb55e44d77..5494ffd994 100644 --- a/openair3/COMMON/security_types.h +++ b/openair3/COMMON/security_types.h @@ -18,10 +18,8 @@ * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org */ - -#if HAVE_CONFIG_H -# include "config.h" -#endif +#ifndef SECURITY_TYPES_H_ +#define SECURITY_TYPES_H_ #if !defined(HAVE_UINT128_T) # include @@ -31,8 +29,6 @@ #include #include -#ifndef SECURITY_TYPES_H_ -#define SECURITY_TYPES_H_ #define RAND_LENGTH_BITS (128) #define RAND_LENGTH_OCTETS (RAND_LENGTH_BITS/8) diff --git a/openair3/M3AP/m3ap_common.c b/openair3/M3AP/m3ap_common.c index 5501997638..e43275d96c 100644 --- a/openair3/M3AP/m3ap_common.c +++ b/openair3/M3AP/m3ap_common.c @@ -31,27 +31,6 @@ #include "m3ap_common.h" #include "M3AP_M3AP-PDU.h" -int asn_debug = 0; -int asn1_xer_print = 0; - -#if defined(EMIT_ASN_DEBUG_EXTERN) -inline void ASN_DEBUG(const char *fmt, ...) -{ - if (asn_debug) { - int adi = asn_debug_indent; - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "[ASN1]"); - - while(adi--) fprintf(stderr, " "); - - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - } -} -#endif - ssize_t m3ap_generate_initiating_message( uint8_t **buffer, uint32_t *length, diff --git a/openair3/M3AP/m3ap_common.h b/openair3/M3AP/m3ap_common.h index c5f55bc70a..75c60db71a 100644 --- a/openair3/M3AP/m3ap_common.h +++ b/openair3/M3AP/m3ap_common.h @@ -18,10 +18,8 @@ * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org */ - -#if HAVE_CONFIG_H_ -# include "config.h" -#endif +#ifndef M3AP_COMMON_H_ +#define M3AP_COMMON_H_ #include "M3AP_ProtocolIE-Field.h" #include "M3AP_M3AP-PDU.h" @@ -35,8 +33,6 @@ #include "M3AP_asn_constant.h" #include "intertask_interface.h" -#ifndef M3AP_COMMON_H_ -#define M3AP_COMMON_H_ /** @defgroup _m3ap_impl_ M3AP Layer Reference Implementation * @ingroup _ref_implementation_ diff --git a/openair3/NGAP/ngap_common.h b/openair3/NGAP/ngap_common.h index a550b6e436..cfb9d63e59 100644 --- a/openair3/NGAP/ngap_common.h +++ b/openair3/NGAP/ngap_common.h @@ -33,23 +33,11 @@ */ -#if HAVE_CONFIG_H_ -# include "config.h" -#endif - #ifndef NGAP_COMMON_H_ #define NGAP_COMMON_H_ #include "common/utils/LOG/log.h" -/* replace ASN_DEBUG defined in asn_internal.h by oai tracing system - Would be cleaner to modify asn_internal.h but it seems to come - from non oai source, with BSD license, so prefer to do that here.. -*/ -#ifdef ASN_DEBUG -# undef ASN_DEBUG -#endif -#define ASN_DEBUG( x... ) LOG_I(ASN, x) #include "NGAP_ProtocolIE-Field.h" #include "NGAP_NGAP-PDU.h" diff --git a/openair3/S1AP/s1ap_common.h b/openair3/S1AP/s1ap_common.h index d383b622b6..9eee0d8dff 100644 --- a/openair3/S1AP/s1ap_common.h +++ b/openair3/S1AP/s1ap_common.h @@ -23,24 +23,10 @@ * @ingroup _ref_implementation_ * @{ */ - -#if HAVE_CONFIG_H_ -# include "config.h" -#endif - #ifndef S1AP_COMMON_H_ #define S1AP_COMMON_H_ - #include "common/utils/LOG/log.h" -/* replace ASN_DEBUG defined in asn_internal.h by oai tracing system - Would be cleaner to modify asn_internal.h but it seems to come - from non oai source, with BSD license, so prefer to do that here.. -*/ -#ifdef ASN_DEBUG -# undef ASN_DEBUG -#endif -#define ASN_DEBUG( x... ) LOG_I(ASN, x) #include "S1AP_ProtocolIE-Field.h" #include "S1AP_S1AP-PDU.h" @@ -63,7 +49,6 @@ #define S1AP_UE_ID_FMT "0x%06"PRIX32 -extern int asn_debug; extern int asn1_xer_print; #if defined(ENB_MODE) diff --git a/openair3/TEST/test_kdf.c b/openair3/TEST/test_kdf.c index 50a2ad347a..7e1b623e5e 100644 --- a/openair3/TEST/test_kdf.c +++ b/openair3/TEST/test_kdf.c @@ -24,10 +24,6 @@ #include #include -#if HAVE_CONFIG_H -# include "config.h" -#endif - #include "test_util.h" #include "secu_defs.h"

h0&06N?X9REx=xt1C&ZPLaVB>*KpD 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 diff --git a/doc/testbenches_doc_resources/5g-nsa-faraday-bench.pdf b/doc/testbenches_doc_resources/5g-nsa-faraday-bench.pdf index f6d960c1a257651b538b404f8f019438d3014f15..1b921e64370954673e45ed70ff1643462f4774ed 100644 GIT binary patch delta 1414 zcmV;11$p}E%oOF!6p$tYHz1eLtpg{KPYnXF!I54he~5nMzTLNY0IkHGP~vK(j+~K? zN}wRJpp_R9!6*_p`_(tWpevD)D+M|REB+Db@+Keo^HC7Q5Q6T{pM?S?Zjb#{8Ujm- zNVHL~po}u64W4&m^;Zpte5WeEhvS>Q7*gHTPsgz)C<6o}VFD<0DZf`guzv!f0~4)~ zs3RB*f9WZg+ts`G&as9kTKHgrhwYvCkEy;(Ao9nyX z`t$a~>ep@4V)O(KvuQNCJY-8`He0k292sF8kPdIk_uGm)0hP{=IvA#&=mV4s?|$2( z_~mi6Nk1)ojV@dG1(q5VSrILerPEaL1QfU+e;6D%Yvx5Mpo+;x^)Q z`}D-FaZJsmM6CrEXrXHgs)D+%@soBLUBQO!Qpn1l?TfxCLz-!LF5_&`7k$%sHa+dR z9ZsyhM+iEZgNERie6zz8NUr#`Q(dlskN zA2dyq-0FyD7R>7`vptjD0vUflpTlI0Xu-!GE9XsC&bzEUYO{v76ub;euR&YGwu+JO zwG^|_25)h}XdQy)sUscZ6`g9en$10?Z7kR&pY0$S(M@(ArY?H`8unMA*;vlb9O64; z@I2sdq@QlFHGGS{z>*1YGL#JY#FFzSF%=v+qM`+d?JyORi~jWZe6xRhnr=;p&|&E- zUD^1SZccikVOKW%US+k7-3(1u$lo|Yp22L|v2<<2%Y_@{=#F9Gc;)g5gdUW7vx}?X znS2(v4YRmuyPdx1s15`+GXl#(p)r^f*rz$nb>pm}K22V&2#ia)qJWJFyUMI~w?JVDeuD0{T?6}0=-vk>iy!gD6NjH||TE=c6b zGZQ9)h(!5mf2*Ufx#-YN8_&KN&@L~}p%~GcgJ)v+KKz=BF=Nm z@yp|ClYUzG8eO*V3oNw)vLaeVmQGW}lcK-{f5G6Cvu0kD0;-s-$>W#Z*ZY6R#UCMu zwXb|-BRroMGG}LnH7Z7WYxOAvUWvK-?Xaspvg#p!4@Q}AAOp?GP-w`;W07u*yz)}t z#nWU!G)kl91J7mWs?X|BQ5BShxFi6%zkj$NYcWQT#3-y~qupo6bhNU;SuLDb=)ili ze@~~06vR}M{`A)alQ}GkCWY)-ycVOkZCn1bfiMC9M5q@9j2UhIw6qQ_airYvf|6$iff5@m0M?o zGu)>qc8z0dCM9aEa)B1Qrl2aQ>l#04UzZVV*e->v?AgBPn=+)8hUYTQ7Jbn-jc3!- zp4;KX+Iv(%Cv(s$xFz50Fa?t9{;+%6eV@4I05>(wM7D8#(KDrwN>ezyX*L=!dZsj9 z1;QURO_SW}h-Vhe>nyX~liLCrf8U?OWQ}OS#~v%^O;*mktUPM7Rv}=ju;&#)jt2<> zp5|iAPRlW)TX0&3$_L&>?h13N)v_ksSUkpZ@UY~x9jIW6(T1th4q(GB>$ozrT50etl0L^qdSt7%wn5!rPZQOvyxe> zFi1+iPOJ22Ps87tvTD(1vg*W&!xofB)M8iUtIW9`T(ZW0`N@@LP44uMH=casiO(&~ z12FRXWMhl$GYe0yimIS&Z1=ajPXIJ|c8$R!Un`_#W8J5QhLq!WqfDAPr#Y8w2>E+2 z6@MP`_SnBY{|Ddy4by|Z1c$x^0f)W>0*Af?1Bbo@1h>8f1uq&bH83_YGBGqVF)J`K zConK4DGD!5Z)8MabY&nYL^?7sGBPkVFg7tVF*GtUw;3M=A_h?~GDA5tLqtR|L^d=q zLoq@)IXFW#MK>}vG&nRfH%3A}AUrTKLpd`;L_{$}HZ(9pF+w;wI72l>H!?LeI5aai zMnXPa3NK7$ZfA68ATcvJmy9I^D}TEU!axv&;Ti9pdE006j3A)_%0QwWN` zPAGr`%0L3oCZG1#XaV4t0Yws(sEP0dQE#B^(2i%&Zfnm{G%HHaiD)w}?w(UYB2S)~ zFcCx~(x>^Y_P*w#MLVoKyP`)sy*&G3K)dcd3x@B*udx_1hOOsF%oyhvFbFQ+_ydl+ T5oMP=CIuk~GYTaoMNdWw2!WYd diff --git a/doc/testbenches_doc_resources/5g-nsa-faraday-bench.png b/doc/testbenches_doc_resources/5g-nsa-faraday-bench.png index c677b598e9894a1bbf0e1e7321497e4c51e6fb17..006e6ab347d2dcd3283f5cdb59c65d1d1ba1ea8e 100644 GIT binary patch delta 49697 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 O+B%g@F&i!Ml>Y&OOLdk2 diff --git a/doc/testbenches_doc_resources/5g-nsa-faraday-bench.tex b/doc/testbenches_doc_resources/5g-nsa-faraday-bench.tex index 66b52f7f69..a9f12fe3df 100644 --- a/doc/testbenches_doc_resources/5g-nsa-faraday-bench.tex +++ b/doc/testbenches_doc_resources/5g-nsa-faraday-bench.tex @@ -30,7 +30,7 @@ \draw (obelix) -- (b210o); \node[above right=0.35cm of faraday.south west] (antn) {\includegraphics[width=0.3cm]{antenna}}; - \draw (b210n) -| node [pos=0.2, duplexer] {B78} (antn); + \draw (b210n) -| node [pos=0.2, duplexer] {n78} (antn); \node[left=5cm of faraday, label=above:porcepix] (porcepix) {\includegraphics[width=1.2cm]{server}}; diff --git a/doc/testbenches_doc_resources/5g-ota-bench.pdf b/doc/testbenches_doc_resources/5g-ota-bench.pdf index e4d4c15e394ad4664d6eea6580db9952d8d7e341..121969030e64e03ac0e4fedc9ba4fc1c692de71c 100644 GIT binary patch delta 9332 zcmai(LsaJvpv7x`*>;o7U#`hEC)>99&6-@3Z8zDI-DG33t;zNN=e*6^y~SPJbME#o zKKIt9qs*kCBv69bxw+H8rXX5iNL$X4NCNHmRo$_v-?5^mx=iT-}KR$_rp}%NU}afT~}^SPR+^7>4W-1wK_ms#q8;^m*dnFjipPGokAhjSC!Sd zNduiBw+MfEZLVnWUNnACb-B_ryv`|MYX6N{!#fN;;SCu4$)|GKm1b7ljTG?XbtbkV^&hc2_9+~%sSgV zbL6SCa%n2A1vI-yNuA#f-fvI$-Ut4C?B#tLy!pIuUY?y3|U#-$@er?}D!}y+z&?k;EGCWD` zs87=9vo`gYBU0fJ_RDU-RH&5y zSdSO|r_zNJ{KG3Y(mjkHUlPd_)8V`RaRUQ7g>1N~8Mi)v44ykP$zQs9FJ4DTtI&MOEqJ*MvdFJZC00$O-#P()?lNQnx zp=sSPddSG<^!HG^iluh<(n^S>$Y=q2p>*LJx5C?@AG^bYj+pA`1ZEu=zMZ1qVO@|5 z>78hrkTd%itdd-{Oo!E|d{vrH0NS)6vjat){2y^bjN9j489H%{tX4M?K- z4YY{s%CH$l)h&2*`V7e~CaQwQ4bhVnhOuQi_AB~sB$Vr*SHFqh=)tvkIw@2*oKg0; zE`XMcV9i3YGKJBpD51IMdUdmk4c2M&MHz{3pXST$tN9pH2`(ph{}Q(61mAFIc&sLE zt=BWs+0Qc>Uxi_8{~OQG@#0vx1Ei}5t>t4KosxG-2YR`gx` z#;IVnr=t`2eD;`*Pj_&hNIHQz?+DJ5PdSbqAlmu*Jtw;n3ay*fI^XYRrt)56MKke~C zM4%%?pdtU$msSyIke)e+lb1Cu-v)&Jg`Fdf)f7YrxT|^cXRmiqi^nrZaz*0As1!XO zcRvc^4acyBs1$n6%E1+;MSg`ZOgn~k#Op;rAyQc9=ad`3P=FL3B;feN?{VPOVHgX z>I(W7*QX*X*y3+_WJtR~P*wCFj@L}$*W8Ctk`SRHUr50T5D@2(5U*?B?%oxx16^Q& zPm$ZtaC>8vppQ!@&%h$41wT6Ho{=rUbQrBC27(~~X!v0ppc69&?6X&h0Fpg;-VEFRxuZ4XG2OIgW{d6(-LI0QV z{KWlC6yk^^{NT%5XA%w(WIZg1=aVZ6S{l#oEPkEj6X2Zgx%pfa{hTZa4Hf-7&byl) zhHTC8h2((f@r_vX`H*U>A%u#4VS)X?w?g`uKl+T1qwmK-s80*w75U_(js(&$264~x zK_V;PKCNSfoW;@yNLWy+L65<20gVs_0mdJI6U-EvuO{Bg#MzQRplp;rAfzf7v^qdc z%1RR`xVr?jv*oUj0D(w;S&;U#UpU?mZ&W^QJK3`0!9nN)v8 zFy7RkmKK2~=VLsEAC=e5t!3?lmxkd1%Njv~i`XL>L{^$m?V*z97(k_a7je(FGCPG| zCm^Y^DCxk?xyb-1@mR5`Wilw5hHXX%dV*N11l zMKa_>nG0s&667WXnM!2+1P&O6=Qqa2aiE+{+FJ*{s-sQaJQ7BZqA4C0XCg4<2TLb$oG67v6@7H?qjmu~Wh*C@TfY6w-Y zT-_dj&;9o@&9Bv2iGdzsi`B~PjFYdPV%cOg?`U8vY;wqV0C;C`?BS{WQSRK~r~FL) z7!t{%m6Cq97UzaMU&#I-YbeWpf8|D;)=WAC;rblxoTF?os!`m_dEKhU9BU|tewE=$ zNgP-qJJbd*`TdT*om#Njc&@{HFF7724QZ&5pb>To@Z-QyA&bC~bXK5`omo<7cJoYt zYntPUWde7k0j!Mail^&E>1~1;9d`5&n2xtPB81I(0S6w_B~9VYzhZb!Rcq7M6Ok<) z=2R~Ee~5R#kg={dNGX6J7Ro!6w!nKNk;mn% zQd}KXQBy1SN@Qq$kIG%l?Ck%@Q4SG!y`)PzR^D}A)B6a z7Bq-hSt`M<41TYYwgnn(*kQzMJB7P+0gl}n`0pQtt@CB#|wR&G$Kmj5_Yf3c0Vd-SaKJPfx2GYkqqH|5m7T>dT4%8YP?hG z9;)FOPN!Xic_^5H_jIA|Kbz`a;wdLIS0fGoW2-;AdMA0CQt8(qy4j~yb$i1nrnJXN z^%%Ozf1Ok5=Fim4T?FfGO>(XSGsB1Y*0u` zQimp!AyOoE9>*+{9WvFGZ840822I7ZUAuYO3DqV`%~6cHn=%=biaSHwPg*DKXXvaz zXfn5l*0)dD$XG$Hnp^g%R~tRZ562R!fHTBuM??T=O+l{b- zd()jTccYn`9KQ1 zFlH4{?+on5vr1w}uLRgu&mdy*?@h5!yJBn(*%#@m#mA_!Y#OCDue=;ROhZ? z2nf!*;GIu1M_XbQF=>0*r?8T|hUQ4Wf|(EOWQ%O6ndq{8E`7W-1KHH50xzD}-=ieB z#r5C2(oOKjnH#Ji8=m%+8OuwxSB_=eqMf&>(e9u40Bj*Dm7d#*)mgm|rf+Kf zMTR^B=P*tk3DjXiU zA0Ye5z0La*nssohYr4j$od&;7piNQEW|ymjPt%6O0Nuf+w@%?%dSaMLBMFPbprH0jF%c~e4i zmT6W2euM^EtIRh;zH>ma6S)j7G&~jHwdUyasHxR4MdtW&>4jHMgz5%TBEN{TvJP-e zNsUHi6*iGa*FOG9pl0EJ1KtDE^qu~aj~5x{vW0`|7AmWVH_KBcA49wpsz%2Xa=sA* zcCTCxuUvU+7(|})7zr}k{qs-bNwAuLs8XGO=5bzM8Ip(Pxd5el9&SaWaTg)e!?Wm( zZx@xmUh8!2mnl!^v*b`)LhKWFkIAM~#D6YwRll4fzv12+&0#AV->2q2q+`0D3i-!) zuTV_A#Sfp&8zd=g)cu`nnoDITylS(`ZS;N`b+F;CGFh34W2f~ho;fYlZINsB9zCvg zem+>2Ku|`*76l=N>M~KJxibHih zJr9?>sHhO!-WrJCI+~#L6gaF#egrmh>ir&f6u3aLOEZxLhQaLRjNEL7YVfKtCBzR` zLZ%b4ey12-Pdv$5e{Z$iSx(BvXZ6A9(pxP$JTrXqmhA`0oLaVLVu!UHc^6--mwu$%5yOIrRhA&R z=5`!*{qhWIVpFnv6L7g|th^~7=4ETAx%D|BI9aq-yr(K~*;??szU{Yf#W+i!uAAX` zx0Vlr@dMzsOgoqIrI=FVLlu+_6R;N3BjYJIYsW*bo+vgv>MUTOq#W72;Xl|ET>1D z<`3WAM`z>gC`gqs{fYVB3>sO_Ve>8NTqe{js3o)DZU+Ifg9ZzUsw`dsy0{FQ$M6-& zS|E!~FWEom(HLW4-McQ!M%uzJ1^kOc6SwXbCEETX{PprD#1SX;+`vIdKx0>U4%KRc z&&HU%W?8OyeDY-5B;;60bnWJBvSLyM{lWR|3=)5~julFkg6JFw6F1Z-H%YQ{w}sv- znx`t++Hy;_Jw9|=nJmDd5&>=RR9n0)f$tJSR^}yHSyZ36-1xw%z#?H7^&_*l z0aSY`{xYZZF-U1QZi+9m5haWo3*0A9o>G;nM0MU*rnw2_yQA==Xt6xa&YI#jHO?M2 zyqd?(zsI#5BzaNjSDEU07;x0mD0}P-MR*MFCOtaot-(MNH`duBTugdq36d?Iw5*S1 z?Dt%bDx_#bvAT`<%pr+0src9Weu8C2)1Nk8tC?o1?+O|^o75bzXiS&N08NA6HI)S% z&SP}eFrg?EI8o^6|6PkTf6F*AbFiWJp*Ts#YzGnpNP-_+XW zx7?@@i850pm0yjOn`D3^K2M+)MpLrA2;fHq|!2m0aaCp-R-ySdvN zYzvjTDG8&z$djet0|yw?q#szVCkmW+mFSj81$zvAe`fXO{Z0V(R-56-TlKpJeqCAo z>m%X%{H~mTzEK$tXe>>Jvd{C>8Z|#qBfEs`zbSKhLKQ)AvYL*s zR!j)O2{AG;TYAL!E)rx4mh6Fc>a2hcQI*S+-jC~8-uSxI*{sm~am)Xnzfg5scBa98 zsqEt?wBA5V*nY?n-gm%YS?{(b`1pf}WN_SU4ayF52&jCDDyDfw#{tqkY*n4@&~kxsz!%-Dum zkZ5`sH?V#w+UV%pBKNLrd0s${-?#MGwmTR>zW3^KfW!Hl&ia)|as|=hA9uYsa$xF$ z4T6J>+FW1to0&YUWR+*KI4|#X4}s!hgGnezGfK+oy=G}?9233f*z$vVwgUdy%YX?L zr)jrUo1kY^XSu@KKVL9DCWyW;#w9zT=^aAn1HjuO=ss88N~%&S^6jAN#?dTinS~ec zNBWhG!O17Bk)=ocy_q^`ZNV13;gVi>&UlUlZ8ZnMW!C;rnd&?N0_*TD?JHB@8XPhP#liHlX(@c zfH0dJXaoI>q4O`g!9`M3oOpsz%xOns9Mub>2d<}?HnM)}zMO2ra&iH?=vqm4IbaQY z!Mh6wo*$3JUxJ!kzBG}q3&F*a&9Avu1c*FWX3o>Bu)w)9RHb&tsGTZcoI~u|8J%4#=w3 z5jBn0{oGB`*Aft{R-*qS;n}b>xsio>I&SOs=C`_zeTeE^G}62|oOFz!oQ0x( zqJ^tw)VNEz--0mR`d@K3mV6%(gn{_%M;Dbc9z^BW+*j|`xylELb?nPGs|8~%1c`9C zTUtUNW5)}5ooAiQ(BTfu(W5ULJ|k(Ze*~gY>Rk31KZR{-TD5Wg=AXnV)cDGcRf^!s zl7_LwE2}$j!TA}97qTXX&!aQdA^aDxahNp*K0>-dHvWi$34fQr3)N=54**l~AJTjK zoVcma=szSd?M!yP7%SXiN!EmZSX8{oq6&~e~;Pu)$hW9$AwN;Xj8pv;0x0OrMKk>}x4Yww^9@jb%@5NucsW0!O=(8vDPC^ZQ%#k9YE zOw79HctOHfZRO-5$a2~>4at4rn^P@jn;~~`jJZmF3J3mH(c_r6!zU5e{#N_u~uHGb4Nf_0~6<#@e41%DLqa8 zSyawr;1gDrAxQl^ea$@5NJ$q<(hKuR@fLSU?U~-aH9GE4^2#=#hhXPaBgy07po|M{{OVGYiF^MBS4f8NA0St@HE+5S6R@po`w#`*3HSx5(im%Q~$ z*Bj5FZ?-Jmj7KI%I*=pV6Sr|^FFaIPJvy@*XJ~n8erCl>4kx)Er+^ri3S@_;99ap`Sm3u|1KC7ihVBtD8GC{B0Rmy|oS{ z6$SUQ9h5>D9cLENMB#VzFZbw<^IIJk>o9oy@ji_eyFg(z7+~!j3O8_2(O{Ntjq!-* zViU?Ci>lN;SStcHC1RjnI9g##+z~jXwum0dSvluxzX`pbKi70ky5cGQTAHM5=2-K1)xCjq*mn6d zD*d~1ln3ggGvGGa8ktkhSf!DfL$e}R*l%qqOHXp6>8%=G%Q=)!JJ&l!d7L9>hUE#) z-n5Iqq-I@2d7IU$xugCLHJxRYdZcNudMTfDCx2>1qF*HEs~dnDU|vWd_4y0aW9Vm# zM2BbcF}Hku{S!Zu%=YWfRE&PvOFM!nemq7<4ZJj$4WKxMpQgbxWR41i9pfU6PZj~3 zw092@W*vwIYz2w|%Omv5BgT)%RqyS$S8_?^9AsaQTG32g>3I0ilvj++t8F&KtDmmE z1+t)Ox@NHXan(Y~E+|8}9|_>rt>7xFb(zBgMw@?ZB~w?enP*$71Vl;7QA?`LCA z@C$h-4ZsJRy<#zEJL=<|S7KX298EU*#C_B`mfK`lwyomJE2$cO1$qyZ5m3i_XM%Hbx38iDPdwTDgNMo!o2##qWx-9 z9tk(3iMN7d)dugX#006##xUkj(B3(hKZ3b~S+WE)YFb1nNDiKhjRVZe&dI@*wjK&1 z_&@d|6f_3O^}o;cAB|1NbuKjE(a_n^c4p`e;{gl>nbbBGT%w%{Wgp0a+91EaW+#)d z&$wyWv!#->*QC|?#h;cmx@*t>E{?xMIw@MZBJjH?b&RxJgHE!B*+BZQ=wdQ^I<7#` zXpqFX5dxerxfEY1RG=a$Wz?vVE^K%Vj5bDckdZAC-IyyNy%Lu%dS?dzG%C&Zixgom zQ6^vT3m>IDxpb(WZ67>OQuG&ANfA~)9=xda_@5NcKbbeAvr{C_qFaJ&o?HbmmTT#_ z-46+t&cKeFj7sqnG#!@WM!WT4V&iM|$RQEvP>Tt@nf%Y%`VRCSDFp*!bvKpFmRXaF z_m!D{95*+C-vqEO)dydZ%JtV$S0H^L?i$jIYl<|J4VxBpbnxk|K{;KiFEn((m(6vT zf1F9{d^Pmk6waBo1Z_U?$Wl7^c7m1atlT$lnmJLM+yj01qoA0UmoI{5KrjaXz*(Ch@>7CDd}~N2CA7 zY56wbr-T!X+52V$3ZPM*{-e&T43v0#>%e&wSEr|vrwpy3_3iu8O*E+rD|*5HbBdLq zjJ6Se*JaBQ3TH+8ZfD(7bH0fmVM-)_DjMm}vgrS8Am$bo{)yM{UUTa*QLUZt%J*eX zgFU1N&a^=@`C17IPoURBcx@g~s`ne}=)6K=J_gs0af zxR?I3GqH`XZHjAwMwRJ*@0C*4H4AA~N0><@B|g8IB!CzlFK^l+ z%$DKvVkX7{{mp=Ql8_d6PSq|D+4Xs;d20$FB~0)ao{vYE?>LeKcUZKr?bZLKY@(y) zj`MGZV(+s~GI45np)tNPKO+;BE*($m`Ec{Ku%3dV^X_GZIRU>4&HaqT^|KUZI&Ii#TERMJ1c1xUzP&M-B^2*#u-yMX3%pl(&;xxr>1o6OttO^uNxIj_L*J*hG zjC9@9>-#&`VPd(i9U9M!J%BY>3XM9)IDeA>fw&XKaoG+uZ=7ej^jQ%?gw-Q-ZA|RW zkNT|!lH}hYr*@7eZRzDT%RHy$>E`Q1h{= zdIT%Okx|ts7|MDW8Se$N4F>UO2GSZJ!2Q`|HKaP>@n16=?HQN;!KzBV7H<-5?o!Q` zid~|UK>T7ppLQwd(H{n9YUV**XSxrxf4Gaef}XkHX7^b(&}r}<1-TOH_!51H#m$|y7D}Ugsj={x>jV*B#Il|sn+b<)@hor*~QYaF5pwI z@D@zU&o2vHsF%qi(3oi@(I6dVHc2iHQC=EeIXKdSmLTZ>;t2tQK4rA99alDtPxAH;oc!6U`_uy2vQ`k5 zhY1MbCnxQ%;A19;NBKL!yUlMPh#siXh(a`~#J|F!*eUk6-jL6K17+G?beVT$#nt5G zts+W}z9)?S&W&Q7MWa*M*t7S(-;(DT8<}dP=-5BoTgCKm5cEZ{THGkBhikG&z2L=Q gUkiX-vyK%)*}yzagN^}_Ah5D>B2ZCDC`lsx4}3}~4FCWD delta 9435 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%0Df-%sBKKHZvL8?Bum$h#?LEP24qI0hr%B-N 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⁣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 literal 90027 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%0D%sqj=-Kn=?=3kz@z+nwCt^ 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